My for loop creates a simple list of labels within a scrollview, instead of changing the font size and colour in the python file, I would rather customise the labels within my KV file. Is this possible?
I know I can use ids to reference a label in the KV file, but I cant wrap my head around how to do it here.
If I create a label in my python file, is it good practice to customise in my kv file or continue to customise it in the python file. What is the best way to go about this?
*.py
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.properties import StringProperty
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock
from kivy.uix.button import Button
from kivy.core.window import Window
class FirstWindow(Screen):
def __init__(self, **kwargs):
super(FirstWindow, self).__init__(**kwargs)
Clock.schedule_once(self.create_scrollview)
def create_scrollview(self, dt):
list1 = ['1','2','3','4','5','6','7','8','9','10','11','12']
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter("height"))
for x in list1:
l = Label(text=x, size=(10, 50), size_hint=(1, None)) <----- Change the font colour in my kv file
layout.add_widget(l)
scrollview = ScrollView(size_hint=(1, None), size=(Window.width, Window.height))
self.view.add_widget(scrollview)
scrollview.add_widget(layout)
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('NearMe.kv')
class NearMeApp(App):
def build(self):
return kv
*.kv
WindowManager:
FirstWindow:
<FirstWindow>:
view: view
BoxLayout:
orientation: 'vertical'
BoxLayout:
size: (64, 64)
size_hint: (1, None)
Label:
text: "NearMeApplications"
canvas.before:
Color:
rgba: .5, .5, .5, 1
Line:
width: 2
rectangle: self.x, self.y, self.width, self.height
ScrollView:
id: view
canvas.before:
Color:
rgba: .8, .8, .8, 1
Line:
width: 2
rectangle: self.x, self.y, self.width, self.height
You can define your own customized Label like this:
def MyLabel(Label):
pass
Then in your kv make a rule for MyLabel:
<MyLabel>:
color: 1,0,0,1
size: 10, 50
size_hint: 1, None
And in your loop:
for x in list1:
l = MyLabel(text=x) <----- Change the font colour in my kv file
layout.add_widget(l)
Correct me if I'm wrong, but it is not possible to set the value of any widget that is initiallized in the python file from the .kv file, as it is only added AFTER the entire .kv file is loaded, which would most likely result in an error. Though you can still edit the color in the python file, which would require ids to be added into individual label, something like this:
for x in list1:
l = Label(id=x, text=x, size=(10, 50), size_hint=(1, None)) #ids from the list1 list
layout.add_widget(l)
You just need to add color: r,g,b,a.
Label:
text: "NearMeApplications"
color: 1,0,1,1
class MyTestApp(App):
def build(self):
return Button(text="HELLO", color=(0, 0, 5, 1), background_color=(7, 4, 5, 1), font_size=150)
if __name__ == "__main__":
MyTestApp().run()
Related
I want to know how to remove a specific Rectangle object in Kivy. I create the Rectangle in .py file by pressing a button and I want to the second button could be able to remove that specific Rectangle.
My .py code:
import kivy
kivy.require("1.10.1")
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.app import App
from kivy.graphics import RoundedRectangle
class Screen1(Screen):
def create_on_press(self):
with self.canvas:
RoundedRectangle(pos = (770, 1250), size = (400, 400), size_hint = (None, None), source = "Rectangle.jpeg")
def remove_on_press(self):
pass #I don't know what to write there
class Test(App):
def build(self):
Builder.load_file("Test.kv")
sm = ScreenManager(transition = FadeTransition())
sm.add_widget(Screen1(name = "scr1"))
return sm
Test().run()
And the .kv file:
#: kivy 1.10.1
<Screen1>:
id: scr1
orientation: "vertical"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "Background.png"
Button:
pos: (root.width - 600) / 2, 800
size: 600, 200
text: "Create rectangle"
on_press: scr1.create_on_press()
pos_hint: {'width': 0.5, 'top': 0.8}
size_hint: None, None
Button:
pos: (root.width - 600) / 2, 200
size: 600, 200
text: "Remove rectangle"
on_press: scr1.remove_on_press
pos_hint: {'width': 0.5, 'top': 0.2}
size_hint: None, None
Thanks for any help.
I tried to use self.parent.remove_widget, but it removed the whole Screen1. However, I want to remove only this Rectangle.
One of the various ways can be adding a group attr. and remove that group later. Since RoundedRectangle is inherited from class Instruction, you can set its attr. group and later use method remove_group to remove that particular group as follows,
def create_on_press(self):
with self.canvas:
RoundedRectangle(pos = (770, 1250), size = (400, 400), size_hint = (None, None), source = "Rectangle.jpeg", group = u"rect")
def remove_on_press(self):
self.canvas.remove_group(u"rect")
Also an obvious change you need in .kv,
...
Button:
pos: (root.width - 600) / 2, 200
size: 600, 200
text: "Remove rectangle"
on_press: scr1.remove_on_press() # Call the function.
...
Thanks, it finally works. My .py:
import kivy
kivy.require("1.10.1")
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.app import App
from kivy.graphics import RoundedRectangle
class Screen1(Screen):
def create_on_press(self):
with self.canvas:
RoundedRectangle(pos = (770, 1250), size = (400, 400), size_hint = (None, None), source = "Rectangle.jpeg", group = u"rect")
def remove_on_press(self):
self.canvas.remove_group(u"rect")
class Test(App):
def build(self):
Builder.load_file("Test.kv")
sm = ScreenManager(transition = FadeTransition())
sm.add_widget(Screen1(name = "scr1"))
return sm
Test().run()
And the .kv:
#: kivy 1.10.1
<Screen1>:
id: scr1
orientation: "vertical"
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "Background.png"
Button:
pos: (root.width - 600) / 2, 800
size: 600, 200
text: "Create rectangle"
on_press: scr1.create_on_press()
pos_hint: {'width': 0.5, 'top': 0.8}
size_hint: None, None
Button:
pos: (root.width - 600) / 2, 200
size: 600, 200
text: "Remove rectangle"
on_press: scr1.remove_on_press()
size_hint: None, None
Thanks everyone for answer.
I'm trying to make a notebook app using kivy, where the user will be able to scroll the sheet up and down and write on it. I tried using ScrollView, but it doesn't seem to work - I wanted the sheet image to be stretched to the width of the window and as the height is greater than the width - have the image scrollable up and down. What happened instead was this:
I would really appreciate anyone looking into the code and trying the figure out what I was doing wrong :)
python code:
import kivy
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from PIL import Image as Image1
from kivy.uix.image import Image
GUI = Builder.load_file('style.kv')
Window.size = (1000, 200)
img_size = Image1.open("images/notebook.png").size
class NotebookScreen(GridLayout):
def __init__(self, **kwargs):
self.rows = 1
super(NotebookScreen, self).__init__(**kwargs)
def get_size_for_notebook(self, **kwargs):
global img_size
width, height = Window.size
return width, (img_size[0] * height / width)
class MainApp(App):
def build(self):
return NotebookScreen()
if __name__ == "__main__":
MainApp().run()
kv file:
<NotebookScreen>
FloatLayout:
rows: 2
GridLayout:
size_hint: 1, .05
pos_hint: {"top": 1, "left": 1}
id: tool_bar
cols: 1
canvas:
Color:
rgba: 0, 0, 1, 1
Rectangle:
pos: self.pos
size: self.size
GridLayout:
id: notebook_grid
size_hint: 1, .95
pos_hint: {"top": .95, "left": 0}
cols: 1
ScrollView:
Image:
id: notebook_image
source: 'images/notebook.png'
allow_stretch: True
keep_ratio: True
pos: self.pos
size: root.get_size_for_notebook()
The problem is that you are setting the size of the Image in your kv, but it is having no effect, since size_hint over-rules size. The default size_hint is (1,1), so no scrolling is done (the Image is constrained to fit in the ScrollView). To allow your size to take effect, just add:
size_hint: None, None
to the Image in your kv.
I'm trying to get a part of the screen a scrollable image, so it will fit in the screen without ruining the image ratio (referring to notebook.jpg in the code). I saw some comments that suggested using ScrollView, but I couldn't really figure out how to add it to the existing class I already have (I mean as a second class in addition to NotebookScreen, so NotebookScreen will be able to use it).
Would really appreciate some help :)
Python code:
import kivy
from kivy.lang import Builder
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
GUI = Builder.load_file('style.kv')
# Window.size = (2224, 1668)
class NotebookScreen(GridLayout):
def __init__(self, **kwargs):
self.rows = 1
super(NotebookScreen, self).__init__(**kwargs)
class MainApp(App):
def build(self):
return NotebookScreen()
if __name__ == "__main__":
MainApp().run()
kivy code:
<NotebookScreen>
FloatLayout:
rows: 2
GridLayout:
size_hint: 1, .05
pos_hint: {"top": 1, "left": 1}
id: tool_bar
cols: 1
canvas:
Color:
rgba: 0, 0, 1, 1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
id: notebook_grid
size_hint: 1, .95
pos_hint: {"top": .95, "left": 0}
cols: 1
Image:
id: notebook_image
source: 'images/notebook.jpg'
allow_stretch: True
keep_ratio: True
pos: self.pos
size_hint: 1, 1
Here is a quick and dirty example of how you could do that. I simply used a Label's canvas to draw the image. I added the label to the scrollview and added scrollview along with another label to show you that you don't need to have the entire screen for your scrolling part. I only used PIL to get the size of the image, because I wanted to make sure that your window is smaller than the image you want to scroll. I hope it helps you with your approach.
from kivy.app import App
from kivy.uix.scrollview import ScrollView
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.graphics import Rectangle
from PIL import Image
class MyApp(App):
def build(self):
img = Image.open("path/to/your/image/dummy.jpg")
Window.size = (img.size[0]*0.8, img.size[1]*1.2)
layout = BoxLayout(orientation="vertical", size_hint=(None, None), size=Window.size)
lbl = Label(text="This is your picture!", size_hint=(None, None), size=(Window.width, Window.height*0.5))
layout.add_widget(lbl)
sv = ScrollView(size_hint=(None, None), size=(Window.width, Window.height*0.5))
img_box = Label(size_hint=(None, None), size=img.size)
with img_box.canvas:
Rectangle(source="path/to/your/image/dummy.jpg", size=img.size)
sv.add_widget(img_box)
layout.add_widget(sv)
return layout
MyApp().run()
[EDIT]
Here is basically the same thing I made at first, but with some outsourcing to a kv string. I hope this is now, what you are looking for.
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
from kivy.lang.builder import Builder
from PIL import Image
kv = """
#:import Window kivy.core.window.Window
<MyImageView>:
orientation: "vertical"
size_hint: None, None
size: Window.size
Label:
text: "This is your picture!"
size_hint: None, None
size: Window.width, Window.height * .5
ScrollView:
size_hint: None, None
size: Window.width, Window.height * .5
Label:
id: img_box
size_hint: None, None
size: root.img.size
canvas:
Rectangle:
source: root.img_path
size: root.img.size
"""
class MyImageView(BoxLayout):
def __init__(self, img_path, **kwargs):
self.img_path = img_path
self.img = Image.open(self.img_path)
Window.size = (self.img.size[0] * 0.8, self.img.size[1] * 1.2)
super(MyImageView, self).__init__(**kwargs)
class MyApp(App):
def build(self):
Builder.load_string(kv)
layout = MyImageView("Path/to/your/image.png")
return layout
MyApp().run()
I'm a beginner in kivy and python. I've been trying to create a scrollview in a page that displays selected video on the screen. But after a while when i selected 5-6 videos to display even though i delete the video widget it starts to lag. And i'm open to any suggestions to better way to handle this kind of application.
from kivy.config import Config
Config.set('graphics', 'width', '1920')
Config.set('graphics', 'height', '1080')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.properties import StringProperty
from kivy.uix.scrollview import ScrollView
from kivy.uix.label import Label
from kivy.clock import Clock
from kivy.uix.button import Button
import os
from kivy.uix.video import Video
from kivy.uix.videoplayer import VideoPlayer
from kivy.clock import mainthread
from functools import partial
from kivy.core.window import Window
Window.clearcolor = (0, 0, 0, 0)
isThereVideo=False
picture_path="/home/linux/kivyFiles/kivyLogin/assets"
video_path="/home/linux/kivyFiles/kivyLogin/videoAssets/"
class Image(Image):
pass
class MainScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class Selfie(Screen):
pass
class RootWidget(Widget):
def __init__(self, **kwargs):
super(RootWidget, self).__init__(**kwargs)
Clock.schedule_once(self.createMultipleButton)
#mainthread
def createMultipleButton(self, dt):
self.root = Widget()
size_y=150;
size_x=150;
for i in range(1):
folderList = os.listdir(picture_path)
if len(folderList)==0:
time.sleep(1)
break
fileList = os.listdir(picture_path)
print fileList
for file in fileList:
x = (picture_path+"/"+file)
button = Button(id=str(file),text="" + str(file),size_hint=(None, None),height=size_y,width=size_x, pos_hint={'x': 0, 'y': 1},background_normal=x)
button.bind(on_release=partial(self.VideoContainer, file))
print file
self.scrollview.content_layout.add_widget(button)
print button.id
print("Parent of ScreenTwo: {}".format(self.parent))
#print(button.pos)
def VideoContainer(self,name,btn):
global isThereVideo
if isThereVideo==True:
#self.videocontainer.video_layout.unload()
self.videocontainer.clear_widgets()
mylist=name.split('.')
emailButton = Button(id='email')
video = Video(source="/home/linux/kivyFiles/kivyLogin/videoAssets/"+mylist[0]+".mp4", state='play',options={'eos': 'loop'})
video.size=(self.parent.width,self.parent.height)
video_pos=(self.parent.x,self.parent.y)
#video.pos_hint={'x': self.parent.width /2, 'y': self.parent.height/2}
video.play=True
#video.pos=(self.parent.width /2 , self.parent.height/2)
#self.videocontainer.video_layout.add_widget(emailButton)
self.videocontainer.add_widget(emailButton)
emailButton.add_widget(video)
isThereVideo=True
print("Parent of ScreenTwo: {}".format(self.parent))
return 0
class ScreenManagement(ScreenManager):
pass
class VideoContain(Widget):
pass
class ScrollableContainer(ScrollView):
pass
presentation = Builder.load_file("login.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == '__main__':
Window.fullscreen = True
app=MainApp()
app.run()
And my Kv file
ScreenManagement:
MainScreen:
Selfie:
<MainScreen>:
name: 'main'
Button:
on_release: app.root.current = 'selfie'
text: 'Another Screen'
font_size: 50
<Selfie>:
name: 'selfie'
Button:
on_release: app.root.current = 'login'
text: 'Selfie Screen'
font_size: 10
pos_hint: {"right": 1, 'top':1}
size_hint: (0.1, 0.1)
RootWidget:
<RootWidget>
size_hint: (0.1, None)
scrollview: scrollview
videocontainer:videocontainer
size:(self.parent.width, self.parent.height)
VideoContain:
id:videocontainer
##size:(self.parent.width, self.parent.height)
size:(root.width, root.height)
ScrollableContainer:
id: scrollview
size: root.size
pos: root.pos
<VideoContain>
video_layout:video_layout
FloatLayout:
cols:1
id: video_layout
<ScrollableContainer>:
scroll_timeout: 75
scroll_distance: 10
app: app
content_layout: content_layout
GridLayout:
id: content_layout
cols: 1
size_hint: (0.1, None)
pos: root.pos
height: self.minimum_height
padding: 25
spacing: 25
I posted all my code since i don't know which part may causing the problem i'm facing.
Solved it.
def VideoContainer(self,name,btn):
global isThereVideo
if isThereVideo:
# self.videocontainer.video_layout.unload()
self.videocontainer.clear_widgets()
In this part i'm clearing the widgets but i also need to unload the video somehow.
self.video.unload() solved my problem
I add widgets to a GridLayout in a ScrollView, so its content expands dynamically.
By default, without user scrolling, the view stays at the top, no matter how many more widgets do you add. If the user scrolls, the view attaches to this point, but it seems a little annoying for me to have to scroll down (even a little bit) for the view to always show the latest content. How can I make it show the downmost part by default?
Here is the sample code just in case:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
Builder.load_string('''
<MessageView>:
canvas:
Color:
rgba: 1, 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
<Message>:
canvas:
Color:
rgba: 0, 1, 0, 0.3
Rectangle:
pos: self.pos
size: self.size
''')
class Message(Widget):
pass
class MessageView(ScrollView):
pass
class TestApp(App):
def msg_in(self, btn):
msg = Message()
msg.size_hint = [None, None]
self.msg_layout.add_widget(msg)
def build(self):
self.scr = Screen()
self.sv1_main = MessageView(pos_hint={"top": 0.87, "center_x": 0.5},
size_hint=(0.97, 0.65))
self.msg_layout = GridLayout(cols=1,
size_hint_y=None)
self.msg_layout.bind(minimum_height=self.msg_layout.setter('height'))
self.bt1_main = Button(size_hint=(0.1, 0.078),
pos_hint={"top": 0.097, "center_x": 0.927},
on_press=self.msg_in)
self.scr.add_widget(self.sv1_main)
self.sv1_main.add_widget(self.msg_layout)
self.scr.add_widget(self.bt1_main)
return self.scr
TestApp().run()
You can use scroll_to method after adding a new content.
class TestApp(App):
def msg_in(self, btn):
msg = Message()
msg.size_hint = [None, None]
self.msg_layout.add_widget(msg)
self.sv1_main.scroll_to(msg)
# ...