Related
My problem is that I want to add multiple labels without having to repeat so many lines of code. I have searched for solutions for a long time and all I see is simply writing a for loop in the python file instead of working on the .kv file. However, the location of the labels I want to add is inside a GridLayout inside a scrollLayout inside a BoxLayout and inside another BoxLayout. Is the only solution really to code all of that in my python file? Is there a better approach to this solution?
This is my first time asking a question on StackOverflow, I am very new to all of this, please correct me if I haven't asked the question in a conventional or clear format. Thank you very much.
python code
from kivy.uix.widget import Widget
from kivy.app import App
from kivy.lang import Builder
Builder.load_file('widgetq.kv')
class Win(Widget):
pass
class WidgetApp(App):
def build(self):
return Win()
if __name__ == '__main__':
WidgetApp().run()
.kv file code
<Win>
box1:box1
BoxLayout:
size: root.size
orientation: "vertical"
BoxLayout:
size_hint: 1, 5
ScrollView:
GridLayout:
id:box1
orientation: 'tb-lr'
height: self.minimum_height
size_hint_y: None
row_default_height:180
spacing: 2
cols:1
Label:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Label:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Label:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Label:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint: 1, 1
Label:
background_color:(94/255, 94/255, 94/255, 1)
text:"tab"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Yes, you can avoid writting the same code for every Label. As all your labels have the same style, you may create a custom Label class in your .py file:
from kivy.uix.label import Label # Don't forget to import Label class
class CustomLabel(Label):
pass
Then, in your .kv file customize that class:
<CustomLabel>:
background_color:(150/255, 150/255, 150/255, 1)
text:"table"
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
Now, you're able to call CustomLabel in your .kv file, instead of the whole code for every label. The example below produces the same result you already have.
<Win>
box1:box1
BoxLayout:
size: root.size
orientation: "vertical"
BoxLayout:
size_hint: 1, 5
ScrollView:
GridLayout:
id:box1
orientation: 'tb-lr'
height: self.minimum_height
size_hint_y: None
row_default_height:180
spacing: 2
cols:1
CustomLabel:
CustomLabel:
CustomLabel:
CustomLabel:
As you can see you only have to call CustomLabel:.
However, if you pretend to add a lot of Labels, the best way is to use a for loop within your python file.
I am looking to add a border to the main screen of my application but I'm not sure how.
I tried to take some tips from this question:
Kivy-how can i make my canvas height smaller than the parent height
But I can't seem to figure it out.
The issue is that I am also using a KivyMD's Navigation Drawer, I would like the border be separate from the top bar, enclosing everything below the bar. Please let me know if I'm not being clear.
Here is some sample code that replicates my setup.
Perhaps I could add some random rectangles to act as a border?
EDIT:
Okay almost there, I got the 'border' but I now need the size_hint added in the AnchorLayout to ignore the top portion of the screen where the menu bar is. Here is the updated code.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
kv = '''
#:import hex kivy.utils.get_color_from_hex
NavigationLayout:
canvas.before:
Color:
rgb: hex('#C0C0C0')
Rectangle:
size: self.size
pos: self.pos
ScreenManager:
id: screen_manager
Screen:
name: "home_screen"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Name of the App!'
elevation: 10
Widget:
FloatLayout:
orientation: 'vertical'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgb: hex('#F5F5F5')
Rectangle:
size: self.size
pos: self.pos
size_hint: .95, .95
MDLabel:
text: "Some More Text"
halign: "center"
color: 0,0,0,1
pos_hint: {"center_x": .5, "center_y": .75}
size_hint: .7, .1
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
source: "image.jpg"
MDLabel:
text: "Text here"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]
'''
class ContentNavigationDrawer(BoxLayout):
pass
class MyApp(MDApp):
def build(self):
return Builder.load_string(kv)
MyApp().run()
I think you will get what you want if you indent the FloatLayout so that it is in the BoxLayout. Like this:
#:import hex kivy.utils.get_color_from_hex
NavigationLayout:
canvas.before:
Color:
rgb: hex('#C0C0C0')
Rectangle:
size: self.size
pos: self.pos
ScreenManager:
id: screen_manager
Screen:
name: "home_screen"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Name of the App!'
elevation: 10
# Widget: # not needed
FloatLayout:
orientation: 'vertical'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgb: hex('#F5F5F5')
Rectangle:
size: self.size
pos: self.pos
size_hint: .95, .95
MDLabel:
text: "Some More Text"
halign: "center"
color: 0,0,0,1
pos_hint: {"center_x": .5, "center_y": .75}
size_hint: .7, .1
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
# source: "image.jpg"
source: 'tester.png'
MDLabel:
text: "Text here"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]
I try to make a simple ToDoList program.There are add, remove and do it buttons. But I have some bugs about labels color. When I click "DO IT" button label color change in scrollview but when I click remove button when some of them done, colored labels change. I did using canvas. How can I fix this problem?
class Home(Screen):
def __init__(self,**kwargs):
super(Home,self).__init__(**kwargs)
def addWidget(self):
task_input = self.ids.task_input.text
newListItem = EachTask(text=task_input ,
id=str((len(self.ids.add_field.children))) )
print(newListItem.id)
self.ids.add_field.add_widget(newListItem)
class EachTask(BoxLayout):
def __init__(self, text= "", **kwargs):
super(EachTask,self).__init__(**kwargs)
self.ids.label.text = text
def Do_Task(self,instance):
child = instance.parent.parent
with self.canvas.before:
Color(.5,1,.2,1, mode='rgba')
Rectangle(pos=child.ids.label.pos, size=child.ids.label.size)
kv_file
<FlatButton#ButtonBehavior+Label>:
font_size: 15
<Home>:
BoxLayout:
id: home
orientation: "vertical"
spacing: 5
#space_x: self.size[0]/2
canvas.before:
Color:
rgba: (1,1,1,1)
Rectangle:
size: self.size
pos: self.pos
##########HEADER#######
BoxLayout:
id: header
size_hint_y: None
height: 50
canvas.before:
Color:
rgba: (.85,.7,.2,1)
Rectangle:
size: self.size
pos: self.pos
Label:
text: "TO DO LIST"
font_size: "20sp"
bold: True
size_hint_x: .9
FlatButton:
text: "Back"
size_hint_x: .1
####################################
ScrollView:
canvas.before:
Color:
rgba: (1,1,.2,.2)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
id: add_field
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: 2 #Spaces between childs
#####################################################
BoxLayout:
id: input_field
size_hint_y: None
height: 80
TextInput:
id: task_input
focus: True
size_hint_x: .9
multiline: False
Button:
font_size: "40sp"
size_hint_x: .1
text: "+"
on_release: root.addWidget()
id: button1
color: 1,0.5,0.5,1
#######################################################
<EachTask>:
size_hint_y: None
height: 50
id: each_task
BoxLayout:
Label:
size_hint_x: .8
id: label
canvas.before:
Color:
rgba: (1,.2,.2,.2)
Rectangle:
size: self.size
pos: self.pos
Button:
size_hint_x: .1
text: "X"
on_release: app.root.ids.add_field.remove_widget(root)
Button:
size_hint_x: .1
text: "DO IT"
on_release: root.Do_Task(self)
The following enhancements are required to the kv and py files to solve the problem.
Method 1 - Kivy automatically created & added an ObjectProperty, rgba
Kivy automatically created & added an ObjectProperty
If the widget doesn’t have a property with the given name, an
ObjectProperty will be automatically created and added to the widget.
kv file
Add a class attribute, rgba and initialize it to default colour, (1, .2, .2, .2) to class rule, <EachTask>:
Replace label's colour to root.rgba
Snippets - kv file
<EachTask>:
rgba: (1,.2,.2,.2) # Kivy auto created & added ObjectProperty, "rgba"
...
BoxLayout:
Label:
size_hint_x: .8
id: label
canvas.before:
Color:
rgba: root.rgba
...
py file
Remove all the codes in method Do_Task()
Add self.rgba = [.5, 1, .2, 1] whereby self refers to the current widget i.e. EachTask object.
Snippets - py file
def Do_Task(self, instance):
self.rgba = [.5, 1, .2, 1]
Method 2 - Explicitly declaring rgba
kv file
Replace rgba: (1,.2,.2,.2) with root.rgba
Snippets - kv file
<EachTask>:
...
BoxLayout:
Label:
size_hint_x: .8
id: label
canvas.before:
Color:
rgba: root.rgba
...
py file
Add import statement, from kivy.properties import ListProperty
Declare class attribute, rgba of ListProperty type and initilaize it to default colour, [1, .2, .2, .2] in class EachTask()
Remove all the codes in method Do_Task()
Add self.rgba = [.5, 1, .2, 1] whereby self refers to the current widget i.e. EachTask object.
Snippets - py file
from kivy.properties import ListProperty
...
class EachTask(BoxLayout):
rgba = ListProperty([1, .2, .2, .2])
...
def Do_Task(self, instance):
self.rgba = [.5, 1, .2, 1]
I'm having issues with refreshing a BoxLayout of widgets by removing them and then rebuilding the widgets based on the list 'Groups'. When on the EditDeviceGroups screen, the 'create' button should add an element to the list and forward the user to the GroupTemplateScreen, which it does.
The issue occurs when the user uses the back button to return to the EditDeviceGroups screen. At that point, I thought the on_enter method would refresh the widgets to include the new element, but the list shows no changes.
I assume it's some sort of issue with classes and instances, but I cant quite see around this one as this is my first real attempt with Kivy.
soundclout.py
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, StringProperty
from kivy.uix.listview import ListItemButton
from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button,Label
from kivy.graphics import Color,Rectangle,InstructionGroup
class GroupTemplateScreen(Screen):
def remove(self):
pass
class HomeScreen(Screen):
skipBuild = 'build_timeline_screen_6'
#skips build option if already timeline is already built
def skip_build_screen(self,value):
if value is 1:
print('HomeScreen.skip_build_screen')
self.skipBuild = 'edit_timeline_screen_7'
class EditDeviceGroupsScreen(Screen):
#Groups = [GroupNo,null]
Groups = [[1,10],[2,20]]
def on_enter(self):
self.ids.glayout2.clear_widgets()
for i in xrange(0,len(EditDeviceGroupsScreen().Groups)):
##THISPRINT##
print(str(EditDeviceGroupsScreen().Groups[i][0]))
addedGroup = BoxLayout(size_hint_y=None,height='120sp',orientation='horizontal')
addedButton=Button(text="Group " + str(EditDeviceGroupsScreen().Groups[i][0]) + " Settings",font_size=25)
addedGroup.add_widget(addedButton)
self.ids.glayout2.add_widget(addedGroup)
#Removes all widget on leaving to prevent the creation of duplicate widgets
def nav_to_group(self):
self.manager.current = 'edit_group_behaviour_screen_9'
def create_group(self):
base = 1
for i in xrange(0,len(EditDeviceGroupsScreen().Groups)):
if base < EditDeviceGroupsScreen().Groups[i][0]:
base = EditDeviceGroupsScreen().Groups[i][0]
EditDeviceGroupsScreen().Groups.append([base+1,(base+1)*10])
#manages screens
class Manager(ScreenManager):
home_screen = ObjectProperty()
edit_device_groups_screen = ObjectProperty()
group_template_screen= ObjectProperty()
def update(self):
self.connected_device_list._trigger_reset_populate()
self.current_screen.update()
class SoundCloutApp(App):
def build(self):
return Manager(transition=WipeTransition())
if __name__=='__main__':
SoundCloutApp().run()
soundclout.kv
#: kivy 1.10.0
#: import hex kivy.utils.get_color_from_hex
#: import main soundclout
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
#: import ListItemButton kivy.uix.listview.ListItemButton
#: import ScrollView kivy.uix.scrollview
<GroupTemplateScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 20
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
orientation: "horizontal"
height: 50
spacing: 10
padding: 0
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_x: None
size_hint_y: None
height: 50
width:100
text: 'Back'
on_release: root.manager.current = 'edit_device_groups_screen_5'
Button:
size_hint_x: None
size_hint_y: None
height: 50
width:100
text: 'Remove'
#have to change first argument, for now assume switch is on
on_press: root.remove()
on_release:root.manager.current = 'edit_device_groups_screen_5'
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#ffffff')
Rectangle:
pos: self.pos
size: self.size
#Devices connected
BoxLayout:
orientation: "horizontal"
canvas:
Color:
rgba: hex('#98a6b3')
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Name:'
font_size: 24
#TODO
Label:
text: 'Group 1'
font_size: 24
#Devices connected
BoxLayout:
orientation: "horizontal"
canvas:
Color:
rgba: hex('#98a6b3')
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Devices:'
font_size: 24
#TODO
Label:
text: '1,2,3,4'
font_size: 24
<HomeScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 50
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
text: "Start"
font_size: 20
Button:
text: "Device Tester"
font_size: 20
Button:
text: "Connect Devices"
font_size: 20
Button:
text: "Edit Device Groups"
font_size: 20
on_press: root.manager.current = 'edit_device_groups_screen_5'
Button:
text: "Edit Group Behavior"
font_size: 20
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Label:
text: "Connected Devices"
font_size: 30
<EditDeviceGroupsScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
#ToolBar
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 20
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_x: None
size_hint_y: None
height: 50
size: self.size
text: 'create group'
on_press: main.EditDeviceGroupsScreen().create_group()
on_release: root.manager.current = 'group_template_screen_11'
#Groups holder
BoxLayout:
orientation: "vertical"
spacing: 5
padding: 5
canvas:
Color:
rgba: hex('#ffffff')
Rectangle:
pos: self.pos
size: self.size
#Adds Scrollability
ScrollView:
do_scroll_x:False
do_scroll_Y:True
BoxLayout:
id: glayout2
orientation: 'vertical'
spacing: 5
size_hint_y: None
height: self.minimum_height
<Manager>:
id: screen_manager
home_screen: home_screen
edit_device_groups_screen: edit_device_groups_screen
group_template_screen: group_template_screen
HomeScreen:
id: home_screen
name: 'homescreen_1'
manager: screen_manager
EditDeviceGroupsScreen:
id: edit_device_groups_screen
name: 'edit_device_groups_screen_5'
manager: screen_manager
GroupTemplateScreen:
id: group_template_screen
name: 'group_template_screen_11'
manager: screen_manager
#Problem#
The EditDeviceGroups screen is not refreshed with the newly added widgets because when the Back button is pressed, another instance of EditDeviceGroupScreen was instantiated.
#Solution#
With the following changes, when the user clicked the back button to return to the EditDeviceGroups screen, the on_enter method refreshed the widgets to include the new element added. Please refer to the example and output for details.
##soundclout.kv##
Deleted #:import main soundclout
Replaced main.EditDeviceGroupsScreen().create_group() with root.create_group()
##soundclout.py##
Replace all occurrence of EditDeviceGroupsScreen(). with self.
#Example#
##main.py##
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, StringProperty
from kivy.uix.listview import ListItemButton
from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button, Label
from kivy.graphics import Color, Rectangle, InstructionGroup
class GroupTemplateScreen(Screen):
def remove(self):
pass
class HomeScreen(Screen):
skipBuild = 'build_timeline_screen_6'
# skips build option if already timeline is already built
def skip_build_screen(self, value):
if value is 1:
print('HomeScreen.skip_build_screen')
self.skipBuild = 'edit_timeline_screen_7'
class EditDeviceGroupsScreen(Screen):
# Groups = [GroupNo, null]
Groups = [[1, 10], [2, 20]]
def on_enter(self):
print("EditDeviceGroupsScreen.on_enter:")
self.ids.glayout2.clear_widgets()
for i in range(0, len(self.Groups)):
##THISPRINT##
print(str(self.Groups[i][0]))
addedGroup = BoxLayout(size_hint_y=None, height='120sp', orientation='horizontal')
addedButton = Button(text="Group " + str(self.Groups[i][0]) + " Settings", font_size=25)
addedGroup.add_widget(addedButton)
self.ids.glayout2.add_widget(addedGroup)
# Removes all widget on leaving to prevent the creation of duplicate widgets
def nav_to_group(self):
self.manager.current = 'edit_group_behaviour_screen_9'
def create_group(self):
base = 1
for i in range(0, len(self.Groups)):
if base < self.Groups[i][0]:
base = self.Groups[i][0]
self.Groups.append([base+1, (base+1)*10])
# manages screens
class Manager(ScreenManager):
home_screen = ObjectProperty()
edit_device_groups_screen = ObjectProperty()
group_template_screen= ObjectProperty()
def update(self):
self.connected_device_list._trigger_reset_populate()
self.current_screen.update()
class SoundCloutApp(App):
def build(self):
return Manager(transition=WipeTransition())
if __name__ == '__main__':
SoundCloutApp().run()
##soundclout.kv##
#:kivy 1.10.0
#:import hex kivy.utils.get_color_from_hex
#:import ListAdapter kivy.adapters.listadapter.ListAdapter
#:import ListItemButton kivy.uix.listview.ListItemButton
#:import ScrollView kivy.uix.scrollview
<GroupTemplateScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 20
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
orientation: "horizontal"
height: 50
spacing: 10
padding: 0
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_x: None
size_hint_y: None
height: 50
width:100
text: 'Back'
on_release: root.manager.current = 'edit_device_groups_screen_5'
Button:
size_hint_x: None
size_hint_y: None
height: 50
width:100
text: 'Remove'
#have to change first argument, for now assume switch is on
on_press: root.remove()
on_release:root.manager.current = 'edit_device_groups_screen_5'
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#ffffff')
Rectangle:
pos: self.pos
size: self.size
#Devices connected
BoxLayout:
orientation: "horizontal"
canvas:
Color:
rgba: hex('#98a6b3')
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Name:'
font_size: 24
#TODO
Label:
text: 'Group 1'
font_size: 24
#Devices connected
BoxLayout:
orientation: "horizontal"
canvas:
Color:
rgba: hex('#98a6b3')
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Devices:'
font_size: 24
#TODO
Label:
text: '1,2,3,4'
font_size: 24
<HomeScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 50
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
text: "Start"
font_size: 20
Button:
text: "Device Tester"
font_size: 20
Button:
text: "Connect Devices"
font_size: 20
Button:
text: "Edit Device Groups"
font_size: 20
on_press: root.manager.current = 'edit_device_groups_screen_5'
Button:
text: "Edit Group Behavior"
font_size: 20
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Label:
text: "Connected Devices"
font_size: 30
<EditDeviceGroupsScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
#ToolBar
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 20
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_x: None
size_hint_y: None
height: 50
size: self.size
text: 'create group'
on_press: root.create_group()
on_release: root.manager.current = 'group_template_screen_11'
#Groups holder
BoxLayout:
orientation: "vertical"
spacing: 5
padding: 5
canvas:
Color:
rgba: hex('#ffffff')
Rectangle:
pos: self.pos
size: self.size
#Adds Scrollability
ScrollView:
do_scroll_x:False
do_scroll_Y:True
BoxLayout:
id: glayout2
orientation: 'vertical'
spacing: 5
size_hint_y: None
height: self.minimum_height
<Manager>:
id: screen_manager
home_screen: home_screen
edit_device_groups_screen: edit_device_groups_screen
group_template_screen: group_template_screen
HomeScreen:
id: home_screen
name: 'homescreen_1'
manager: screen_manager
EditDeviceGroupsScreen:
id: edit_device_groups_screen
name: 'edit_device_groups_screen_5'
manager: screen_manager
GroupTemplateScreen:
id: group_template_screen
name: 'group_template_screen_11'
manager: screen_manager
#Output#
I am new to Python UI programming, and I am trying out Kivy. I want to center some buttons on my screen, but the buttons do not move from the bottom right of the window. I was wondering if anyone could point out what I am doing wrong or am missing?
vgx.kv:
#:kivy 1.9.1
<VgxMainScreen>:
BoxLayout:
size_hint: 0.2,0.2
size: 200, 100
orientation: 'vertical'
Button:
text: 'Game Select'
Button:
text: 'Options'
Button:
text: 'Controllers'
<VgxUI>:
AnchorLayout:
anchor_x: 'center'
VgxMainScreen:
size_hint: 0.2,0.2
<VgxApp>:
FloatLayout:
VgxUI:
center: 0.5, 0.5
VgxApp.py:
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
kivy.require('1.9.1')
class VgxMainScreen(Widget):
pass
class VgxUI(Widget):
pass
class VgxApp(App):
def build(self):
return VgxUI()
if __name__ == '__main__':
VgxApp().run()
Edit: Best way to debug what's going on with you widgets is to change their background colors :).
canvas.before:
Color:
rgba: X, X, X, 1
Rectangle:
pos: self.pos
size: self.size
The problem was that your BoxLayout wasn't positioned relatively to its parent even though it was inside it.
What I did here is that I positioned the BoxLayout to its parent's size and position using:
size: self.parent.size
pos: self.parent.pos
I also moved the size property from VgxMainScreen to VgxUI because I assume this is more common use-case (you can have multiple VgxMainScreens each with different size). Full code with background colors:
#:kivy 1.9.1
<VgxMainScreen>:
size_hint: None, None
canvas.before:
Color:
rgba: 1, 0, 0, 1 # red
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
canvas.before:
Color:
rgba: 0, 0, 1, 1 # blue
Rectangle:
pos: self.pos
size: self.size
size: self.parent.size # important!
pos: self.parent.pos # important!
orientation: 'vertical'
Button:
text: 'Game Select'
Button:
text: 'Options'
Button:
text: 'Controllers'
<VgxUI>:
AnchorLayout:
canvas.before:
Color:
rgba: 1, 1, 1, 1 # white
Rectangle:
pos: self.pos
size: self.size
size: self.parent.size
anchor_x: 'center'
anchor_y: 'center'
VgxMainScreen:
size: 200, 100
<VgxApp>:
FloatLayout:
VgxUI:
center: 0.5, 0.5
There's yet another solution to this.
You can use RelativeLayout and all widgets inside it will position relatively to this layout.
<VgxMainScreen>:
size_hint: None, None
RelativeLayout:
pos: self.parent.pos
size: self.parent.size
BoxLayout:
orientation: 'vertical'
Button:
text: 'Game Select'
Button:
text: 'Options'
Button:
text: 'Controllers'
I've personally scratched my head many times when using Kivy and wondered why my widgets aren't positioned as I think they should :).
VgxMainScreen is a Widget, so it doesn't apply any positioning or sizing to its children (only Layouts do that), so the BoxLayout has the default position of (0, 0) and size of (100, 100).
Make VgxMainScreen inherit from something else, like a FloatLayout.