I'm trying to create this simple background.
This is what I have so far:
import kivy
kivy.require('1.11.1')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
class BaseLayout(BoxLayout):
pass
class MyWindow(FloatLayout):
def __init__(self, **kwargs):
super(MyWindow, self).__init__(**kwargs)
self.add_widget(BaseLayout())
class MyApp(App):
# 'Global' Variables
size_x = 220*1.3
size_y = 250*1.3
def build(self):
return BaseLayout()
MyApp().run()
And my .kv-file:
#:kivy 1.11.1
#:import hex kivy.utils.get_color_from_hex
<BaseLayout>:
orientation: "vertical"
size: (app.size_x, app.size_y)
size_hint: (None, None)
#:set bg_color hex('#262626')
#:set topBar_color hex('#1c1c1c')
#:set bt_color hex('#4d4d4d')
AnchorLayout:
size_hint_y: .1
Label:
canvas.before:
Color:
rgba: topBar_color
Rectangle:
size: self.size
pos: self.pos
AnchorLayout:
anchor_x: 'right'
anchor_y: 'center'
padding: 10, 10
Label:
size_hint: (1, 1)
# size: (25, 0)
canvas.before:
Color:
rgba: bt_color
Ellipse:
pos: self.pos
size: self.size
Label:
size_hint_y: .9
canvas.before:
Color:
rgba: bg_color
Rectangle:
size: self.size
pos: self.pos
I'm looking for a way to have the circle always adapt to the height of the bar at the top (and of course it should be an actual circle and not the stretched ellipse it is now).
The window is not meant to be resized, but I want to be able to control the widget with the size_x and size_y variables, so I cannot just enter some absolute values.
The size_hint for the height is correct, but I could not find a way to just set the width of the circle to its height.
Thanks in advance
Here is a modified version of your kv:
#:kivy 1.11.1
#:import hex kivy.utils.get_color_from_hex
<BaseLayout>:
orientation: "vertical"
size: (app.size_x, app.size_y)
size_hint: (None, None)
#:set bg_color hex('#262626')
#:set topBar_color hex('#1c1c1c')
#:set bt_color hex('#4d4d4d')
AnchorLayout:
anchor_x: 'right'
size_hint_y: .1
canvas.before:
Color:
rgba: topBar_color
Rectangle:
size: self.size
pos: self.pos
Widget:
size_hint: None, 1
width: self.height
canvas.before:
Color:
rgba: bt_color
Ellipse:
pos: self.pos
size: self.size
Label:
size_hint_y: .9
canvas.before:
Color:
rgba: bg_color
Rectangle:
size: self.size
pos: self.pos
This uses a Widget with size_hint: None, 1 to make it the height of the parent, and allow the width to be set as width: self.height to make a square Widget. The drawn Ellipse using that size will be a circle. Note that, in general, the AnchorLayout only works well with one child (additional children will be drawn on top of each other).
Related
I have a very basic kivy code. I have the .py file and the .kv file. The questions are: where should the methods be placed? In this example the 2 methods that interact are 'def GetTicker(ticker):' and 'def GetTickers(self):'. I have placed both outside of any class, because I could not get the code to work otherwise; however I think the proper way to code would be to place them inside the 'app' class.
As an aside I am very confused about where/when the 'self' should be passed. I'm working by trial and error here.
Then there is the 'NumericProperty'. I read here that when it is updated, it automatically updates the widgets that are associated with it. It doesn't for me, therefore I had to create Id's for some labels; but the id's won't work at the beginning of the run, only on update.
I'm using python 3.9 and kivy 2.0.0, PyCharm 2021.3.1 (Community Edition) on win10 box.
Any and all assistance will be greatly appreciated.
Ray
the .py file
from kivy.app import App
from kivy.properties import NumericProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.textinput import TextInput
from kivy.core.window import Window
Window.size = (300, 300)
import time
from yahoo_fin.stock_info import get_live_price # This API only gets the live price
from yahoo_fin import stock_info as si # This is SLOWER than the above API, buts gets more info
class MyBoxLayout(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def press(self):
name = self.ids.ticker_name.text.upper()
self.ids.ticker_value.text = self.GetTicker(name)
def update(self):
#GetTickers(self) # This won't work here :(
self.ids.mydow_price.text, self.ids.mydow_chg = self.GetTicker("^DJI")
self.ids.mysp_price.text, self.ids.mysp_chg = self.GetTicker("^GSPC")
self.ids.mynasdaq_price.text, self.ids.mynasdaq_chg.text = self.GetTicker("^IXIC")
self.ids.myeuro_price, self.ids.myeuro_chg.text = self.GetTicker("EURUSD=X")
#print(self.ids.amazon_id.text)
class MyOtherBoxlayout(BoxLayout):
pass
class MyTicker(TextInput):
pass
class gridlayout(GridLayout):
pass
def GetTicker(ticker):
# data = get_live_price(ticker)
data = si.get_quote_table(ticker)
price = data['Quote Price']
change = price - data['Previous Close']
# print("Price: %.3f" % price)
# print("Change: %.3f" % change)
return [str("%s" % format(price, ',.3f')), str("%s" % format(change, ',.3f'))]
def GetTickers(self):
self.dow_price, self.dow_chg = self.GetTicker("^DJI")
self.sp_price, self.sp_chg = self.GetTicker("^GSPC")
self.nasdaq_price, self.nasdaq_chg = self.GetTicker("^IXIC")
self.euro_price, self.euro_chg = self.GetTicker("EURUSD=X")
# This is the app class
class StockTickerApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
App.title = "Ray's Stock Ticker"
dow_price = NumericProperty(0.00)
dow_chg = NumericProperty(0.00)
sp_price = NumericProperty(0.00)
sp_chg = NumericProperty(0.00)
nasdaq_price = NumericProperty(0.00)
nasdaq_chg = NumericProperty(0.00)
euro_price = NumericProperty(0.00)
euro_chg = NumericProperty(0.00)
start_time = time.time()
self.GetTickers()
end_time = time.time()
print (end_time - start_time)
# and its run here
StockTickerApp().run()
the .kv file
MyBoxLayout:
<MYLabel#ButtonBehavior+Label>: # this is something I found that helps make a label behave
# like a button.
<MyBoxLayout>:
canvas.before:
Color:
rgba: (153/255, 255/255, 255/255, 1)
Rectangle:
pos: self.pos
size: self.size
padding: ("15dp", "15dp", "15dp", "15dp") #left, top, right, bottom
spacing: "10dp"
orientation: "vertical"
#
# 1st widget
#
Label:
text: "Stocks Ticker"
size_hint: 1, .1
#pos_hint: {"top": 1}
color:0,0,0,1
#
# 2nd widget
#
BoxLayout:
canvas.before:
Color:
rgba: (19/255,202/255,55/255,1) # lime more intense
Rectangle:
pos: self.pos
size: self.size
padding: ("10dp", "0dp", "15dp", "0dp")
spacing: "20dp"
orientation: "horizontal"
size_hint: 1, .4
#pos_hint: {"center": .5}
Label:
text: " Enter Stock"
size_hint: .6, .5
pos_hint: {"center_X":.5, "top": .7}
color: 72/255,89/255,89/255,1
MyTicker: # this is a textinput widget
id: ticker_name
text: ""
size_hint: .6, .6
pos_hint: {"top": .8}
Label:
id: ticker_value
#text: " Enter Stock"
size_hint: .5, .1
color: 0,0,0,1
pos_hint: {"top":.5, "center": 1}
#
# 3rd widget
#
BoxLayout:
size_hint: 1, .3
Button:
#id: "Find_Value"
text: "Find Value"
on_press: root.press()
#
# 4th widget
#
gridlayout:
canvas.before:
Color:
rgba: (19/255,202/255,55/255,1) # lime more intense
Rectangle:
pos: self.pos
size: self.size
rows: 4
cols: 3
padding: "10dp"
MYLabel:
color: 72/255,89/255,89/255,1
text: "Dow"
text_size: self.size
halign: 'left'
on_press: root.update()
MYLabel:
id: mydow_price
color: 0,0,0,1
text: app.dow_price
text_size: self.size
halign: 'right'
on_press: root.update()
MYLabel:
id: mydow_chg
color: 0,0,0,1
text: app.dow_chg
text_size: self.size
halign: 'right'
on_press: root.update()
MYLabel:
text: "S&P 500"
color: 72/255,89/255,89/255,1
text_size: self.size
halign: 'left'
on_press: root.update()
MYLabel:
id: mysp_price
text: app.sp_price
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
id: mysp_chg
text: app.sp_chg
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
text: "Nasdaq"
color: 72/255,89/255,89/255,1
text_size: self.size
halign: 'left'
on_press: root.update()
MYLabel:
id: mynasdaq_price
text: app.nasdaq_price
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
id: mynasdaq_chg
text: app.nasdaq_chg
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
text: "Euro/USD"
color: 72/255,89/255,89/255,1
text_size: self.size
halign: 'left'
on_press: root.GetTickers()
MYLabel:
id: myeuro_price
text: app.euro_price
color: 0,0,0,1
text_size: self.size
halign: 'right'
MYLabel:
id: myeuro_chg
text: app.euro_chg
color: 0,0,0,1
text_size: self.size
halign: 'right'
I am using the default Kivy Settings widget to create a settings screen for my app. I don't want to build a custom settings widget from scratch, but I would like to customise simple properties like the text size of each item and the colour of the "close" button.
Based on the Kivy docs and the answer to this question I understand that I need to modify the styles for the different Settings class widgets that are defined in style.kv. For example, I have been able to add the following to the top of my main.py to redefine the style of the MenuSidebar widget and change the size and colour of the settings "close" button:
from kivy.lang import Builder
Builder.load_string('''
<-MenuSidebar>:
size_hint_x: None
width: '200dp'
buttons_layout: menu
close_button: button
GridLayout:
pos: root.pos
cols: 1
id: menu
padding: 5
canvas.after:
Color:
rgb: .2, .2, .2
Rectangle:
pos: self.right - 1, self.y
size: 1, self.height
Button:
text: 'Close'
id: button
size_hint: None, None
width: root.width - dp(20)
height: max(50, self.texture_size[1] + dp(20))
pos: root.x + dp(10), root.y + dp(10)
font_size: '30sp'
Following a similar approach, I now want to modify the style of each setting item so that the text colour is red. I add the following into Builder.load_string() at the top of my main.py to redefine the style of the SettingItem widget:
<-SettingItem>:
size_hint: .25, None
height: labellayout.texture_size[1] + dp(10)
content: content
canvas:
Color:
rgba: 47 / 255., 167 / 255., 212 / 255., self.selected_alpha
Rectangle:
pos: self.x, self.y + 1
size: self.size
Color:
rgb: .2, .2, .2
Rectangle:
pos: self.x, self.y - 2
size: self.width, 1
BoxLayout:
pos: root.pos
Label:
size_hint_x: .66
id: labellayout
markup: True
text: u'{0}\\n[size=13sp][color=999999]{1}[/color][/size]'.format(root.title or '', root.desc or '')
font_size: '15sp'
color: [1, 0 , 0 , 1]
text_size: self.width - 32, None
BoxLayout:
id: content
size_hint_x: .33
Everything works as expected, however the value of each setting item disappears.
I have tried everything I can think off, but I can't work out how to modify the appearance of the settings screen without losing the actual value of each setting item, or messing up the whole layout of the settings screen. Can anyone advise how I can achieve my goal?
Here is a minimal reproducible example illustrating the issue that is based on the Kivy Settings example
from kivy.app import App
from kivy.uix.settings import SettingsWithSidebar
from kivy.logger import Logger
from kivy.lang import Builder
kv = '''
BoxLayout:
orientation: 'vertical'
Button:
text: 'Configure app (or press F1)'
on_release: app.open_settings()
Label:
id: label
text: 'Hello'
<-MenuSidebar>:
size_hint_x: None
width: '200dp'
buttons_layout: menu
close_button: button
GridLayout:
pos: root.pos
cols: 1
id: menu
padding: 5
canvas.after:
Color:
rgb: .2, .2, .2
Rectangle:
pos: self.right - 1, self.y
size: 1, self.height
Button:
text: 'Close'
id: button
size_hint: None, None
width: root.width - dp(20)
height: max(50, self.texture_size[1] + dp(20))
pos: root.x + dp(10), root.y + dp(10)
font_size: '30sp'
color: [1, 0 , 0, 1]
<-SettingItem>:
size_hint: .25, None
height: labellayout.texture_size[1] + dp(10)
content: content
canvas:
Color:
rgba: 47 / 255., 167 / 255., 212 / 255., self.selected_alpha
Rectangle:
pos: self.x, self.y + 1
size: self.size
Color:
rgb: .2, .2, .2
Rectangle:
pos: self.x, self.y - 2
size: self.width, 1
BoxLayout:
pos: root.pos
Label:
size_hint_x: .66
id: labellayout
markup: True
text: u'{0}\\n[size=13sp][color=999999]{1}[/color][/size]'.format(root.title or '', root.desc or '')
font_size: '15sp'
color: [1, 0 , 0 , 1]
text_size: self.width - 32, None
BoxLayout:
id: content
size_hint_x: .33
'''
json = '''
[
{
"type": "string",
"title": "Label caption",
"desc": "Choose the text that appears in the label",
"section": "My Label",
"key": "text"
},
{
"type": "numeric",
"title": "Label font size",
"desc": "Choose the font size the label",
"section": "My Label",
"key": "font_size"
}
]
'''
class MyApp(App):
def build(self):
self.settings_cls = SettingsWithSidebar
root = Builder.load_string(kv)
label = root.ids.label
label.text = self.config.get('My Label', 'text')
label.font_size = float(self.config.get('My Label', 'font_size'))
return root
def build_config(self, config):
config.setdefaults('My Label', {'text': 'Hello', 'font_size': 20})
def build_settings(self, settings):
settings.add_json_panel('My Label', self.config, data=json)
def on_config_change(self, config, section, key, value):
Logger.info("main.py: App.on_config_change: {0}, {1}, {2}, {3}".format(
config, section, key, value))
if section == "My Label":
if key == "text":
self.root.ids.label.text = value
elif key == 'font_size':
self.root.ids.label.font_size = float(value)
def close_settings(self, settings=None):
Logger.info("main.py: App.close_settings: {0}".format(settings))
super(MyApp, self).close_settings(settings)
MyApp().run()
Add this to your kv string:
<SettingString>:
Label:
text: root.value or ''
pos: root.pos
font_size: '15sp'
color: 1,0,0,1
Color obviously can be whatever you want.
this only works for the settings string, if you use other settings objects modify them in a similar way :)
When the application is windowed the button and labels are in the right places, exactly where I want them, but when I view the window in full screen everything moves out of place
I've tried messing around with the padding and height of the box layouts and label properties, but I just getting the broken outcome.
*.py
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.image import Image
class LoginReg(BoxLayout):
pass
class LoginApp(App):
def build(self):
return LoginReg()
if __name__== '__main__':
LoginApp().run()
*.kv
#:kivy 1.0
#:import hex kivy.utils.get_color_from_hex
<TextInput>:
size_hint_y: None
height:30
<Label>:
size_hint_y: None
height:30
color: 0,0,0,1
<FlatButton#ButtonBehavior+Label>:
font_size: 18
<LoginReg>:
id: main_win
orientation: "vertical"
spacing: 10
space_x: self.size[0]/3
space_y: 40
#Code for background start
BoxLayout:
id: background
orientation: 'vertical'
canvas.before:
Color:
rgba: hex('#f2f2f2f2')
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
id: header
size_hint_y:None
height: 50
canvas.before:
Color:
rgba: hex('#1A5276')
Rectangle:
size: self.size
pos: self.pos
FlatButton:
text:"Virtual Assistant"
color: (1,1,1,1)
BoxLayout:
orientation: 'vertical'
padding: main_win.space_x, main_win.space_y
BoxLayout:
spacing: 10
orientation: 'vertical'
padding: 50
canvas.before:
Color:
rgba: hex('#111')
Rectangle:
size: self.size
pos: self.pos
Label:
text: "Login: "
TextInput:
hint_text: "Username"
multiline: False
Label:
text: "Password: "
TextInput:
hint_text: "password"
multiline: False
Button:
text:"Login"
size_hint_y: None
height: 60
background_color: (2.08, 2.40, 1.92,1)
Label:
id:sp
size_hint_y:None
height: 200
I am not getting any error messages, I just want to work out how to keep everything relative it its size when resizing the window.
The best way to get everything to keep relative size/position is to use hints. Use size_hint for sizes and pos_hint for positions. Also, don't add unnecessary complexity to your layout. In your posted code, your LoginReg is a BoxLayout, and the only item you have in it is another BoxLayout. Similarly, later in your kv you have another vertical BoxLayout with its only child being another vertical BoxLayout. That is unnecessary complexity. Here is a simpler version of your code that I believe accomplished what you want:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
class LoginReg(FloatLayout):
pass
Builder.load_string('''
#:kivy 1.0
#:import hex kivy.utils.get_color_from_hex
<TextInput>:
size_hint_y: None
height:30
<Label>:
size_hint_y: None
height:30
color: 0,0,0,1
<FlatButton#ButtonBehavior+Label>:
font_size: 18
<LoginReg>:
spacing: 10
#Code for background start
canvas.before:
Color:
rgba: hex('#f2f2f2f2')
Rectangle:
size: self.size
pos: self.pos
FlatButton:
id: fb
canvas.before:
Color:
rgba: hex('#1A5276')
Rectangle:
size: self.size
pos: self.pos
pos_hint: {'center_x': 0.5, 'top':1.0}
size_hint_y:None
height: 50
text:"Virtual Assistant"
color: (1,1,1,1)
BoxLayout:
spacing: 10
orientation: 'vertical'
padding: 50
canvas.before:
Color:
rgba: hex('#111')
Rectangle:
size: self.size
pos: self.pos
pos_hint: {'center_x': 0.5, 'top': (root.height - fb.height)/root.height}
size_hint: 0.33, None
size_hint_min_x: 200
height: self.minimum_height
Label:
text: "Login: "
TextInput:
id: ti
hint_text: "Username"
multiline: False
Label:
text: "Password: "
TextInput:
hint_text: "password"
multiline: False
Button:
text:"Login"
size_hint_y: None
height: 60
background_color: (2.08, 2.40, 1.92,1)
''')
class LoginApp(App):
def build(self):
return LoginReg()
if __name__== '__main__':
LoginApp().run()
I have used Builder.load_string instead of a file just for my own convenience.
The important changes are to make LoginReg extend FloatLayout just because it allows more flexibility than a BoxLayout. I have removed any BoxLayouts that only had a single BoxLayout child.
The FlatButton now uses pos_hint to position it at the top of LoginReg.
The BoxLayout inside Loginreg uses pos_hint to center it horizontally, and to position it vertically just below the FlatButton. It also uses size_hint to make its width one third of the width of LoginReg, but with a minimum width of 200. Its height is set to use the minimum height that will contain its children.
I've got the below popup in one of my screens and I can't workout how to change the background colour of the popup, it just defaults to the Kivy standard grey. I've tried background_colour but it changed the entire screen behind instead.
def none_selected(self):
pop = Popup(title='Error',
content=Label(text='Please select at least one option', multiline=True,),
size_hint=(None, None), size=(250, 200))
pop.open()
If you are content to just change the background color of the Label portion of the Popup, you can just define your own Label subclass:
class MyLabel(Label):
pass
and in your 'kv':
<MyLabel>:
canvas.before:
Color:
rgba: 1,0,0,1
Rectangle:
pos: self.pos
size: self.size
Then, using MyLabel instead of Label in your Popup will give you a red background (but not for the title area of the Popup).
If you want to change the background color for the entire Popup, I think you will need to redefine the pre-defined style for the Popup. Again, create a subclass of Popup:
class MyPopup(Popup):
bg_color = ListProperty([0,0,0,1])
The bg_color will become the background color.
Now redefine the style:
<-MyPopup>:
_container: container
GridLayout:
padding: '12dp'
cols: 1
size_hint: None, None
pos: root.pos
size: root.size
Label:
canvas.before:
Color:
rgba: root.bg_color
Rectangle:
pos: self.pos
size: self.size
text: root.title
color: root.title_color
size_hint_y: None
height: self.texture_size[1] + dp(16)
text_size: self.width - dp(16), None
font_size: root.title_size
font_name: root.title_font
halign: root.title_align
Widget:
size_hint_y: None
height: dp(4)
canvas.before:
Color:
rgba: root.bg_color
Rectangle:
pos: self.pos
size: self.size
canvas:
Color:
rgba: root.separator_color
Rectangle:
pos: self.x, self.y + root.separator_height / 2.
size: self.width, root.separator_height
BoxLayout:
canvas.before:
Color:
rgba: root.bg_color
Rectangle:
pos: self.pos
size: self.size
id: container
The - at the start of the above kv, indicate that we are redefining the default style (most of the above kv is copied from the default style.kv). The use of canvas.before sets the background color. The MyPopup now has a bg_color property that you can set to whatever color you want, for example, to set the background to red:
def none_selected(self):
pop = MyPopup(title='Error',
content=Label(text='Please select at least one option', multiline=True,),
size_hint=(None, None), size=(250, 200), bg_color=[1,0,0,1])
pop.open()
I would like to build the following simple design in a .kv file.
It is made of 3 parts :
One top-left Anchor Layout which is made up of a Grid Layout of 3 columns. I want its width to be equal to 20% of the window's with and its height to be equal to 75% of the window's height.
One top-right Anchor Layout which is made up of a vertically-oriented Box Layout. I want its width to be equal to 80% of the window's with and its height to be equal to 75% of the window's height.
One bottom-left Anchor Layout which is empty for the moment. I want its height to be 25% of the window's height.
These three parts are themselves included in an AnchorLayout.
I tried to translate this design into a .kv file as follows.
#:kivy 1.11.1
<Example>:
anchor_x: "center"
anchor_y: "center"
AnchorLayout:
anchor_x: "left"
anchor_y: "top"
size_hint: (0.2, 0.75)
GridLayout:
cols: 3
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
AnchorLayout:
anchor_x: "right"
anchor_y: "top"
size_hint: (0.8, 0.75)
BoxLayout:
orientation: "vertical"
Label:
text: "HELLO..."
Label:
text: "WORLD..."
AnchorLayout:
anchor_x: "left"
anchor_y: "bottom"
size_hint: (1, 0.25)
Label:
text: "FOOTER"
In case it matters, here is the code of my .py file as well.
# Importing Kivy
import kivy
kivy.require("1.11.1")
# Importing kivy libraries
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.lang import Builder
# Importing external libraries
# Import kv files
Builder.load_file("example.kv")
# Root widget of the application
class Example(AnchorLayout):
pass
# Application class
class TestApp(App):
def build(self, **kwargs):
return Example()
# Launch the application
if __name__=="__main__":
app = TestApp()
app.run()
The output does not look as I expected as shown on the picture below :
I don't get it. Because the AnchorLayout is a subclass of the Widget class and is itself included within a Layout, its size_hint property should enable me to define its size.
What am I missing here ? Thanks in advance!
Problem - design centered
The design is placed in the center.
Root Cause
The root is an AnchorLayout with value 'center' for both anchor_x and anchor_y. Therefore, all its children (the AnchorLayouts) are placed in respect to the root.
Below is a view of your design in different colours for visualization.
AnchorLayout
The AnchorLayout aligns its children to a border (top, bottom, left, right) or center.
Solution
There are three possible solutions to your design. The preference is method 1.
Method 1 - No AnchorLayouts
This method replace all AnchorLayouts with BoxLayouts. It use one less AnchorLayout widget which makes the app more resource efficient i.e. use less memory and the app is smaller.
Snippets - Method 1
<Example>:
orientation: 'vertical'
BoxLayout:
...
GridLayout: # left box
...
BoxLayout: # right box
...
BoxLayout: # footer
...
Method 2 - BoxLayout as root
This method replace the root widget with BoxLayout and realign the left box.
Snippets - Method 2
<Example>:
orientation: 'vertical'
AnchorLayout:
...
GridLayout: # left box
...
AnchorLayout: # right box
...
AnchorLayout: # footer
...
Method 3
This method add a BoxLayout as a child of the root, and the rest of the AnchorLayout as children of the BoxLayout.
Snippets - Method 3
<Example>:
anchor_x: "center"
anchor_y: "center"
BoxLayout:
orientation: 'vertical'
AnchorLayout:
...
GridLayout: # left box
...
AnchorLayout: # right box
...
AnchorLayout: # footer
...
Example
Method 1 - No AnchorLayouts
main.py
from kivy.base import runTouchApp
from kivy.lang import Builder
runTouchApp(Builder.load_string("""
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint: 1, 0.75
GridLayout:
size_hint: 0.2, 1
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
size: self.size
pos: self.pos
cols: 3
row_force_default: True
row_default_height: 40
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
BoxLayout:
orientation: 'vertical'
canvas.before:
Color:
rgba: 0, 1, 0, 1
Rectangle:
size: self.size
pos: self.pos
Label:
text: "HELLO..."
Label:
text: "WORLD..."
BoxLayout:
size_hint: 1, 0.25
canvas.before:
Color:
rgba: 0, 0, 1, 1
Rectangle:
size: self.size
pos: self.pos
Label:
text: "FOOTER"
"""))
Output: Method 1 - No AnchorLayouts
Method 2 - BoxLayout as root
main.py
from kivy.base import runTouchApp
from kivy.lang import Builder
runTouchApp(Builder.load_string("""
BoxLayout:
orientation: 'vertical'
AnchorLayout:
size_hint: 1, 0.75
anchor_x: 'left'
anchor_y: 'top'
GridLayout:
size_hint: 0.2, 1
canvas.before:
Color:
rgba: 1, 0, 0, 1
Rectangle:
size: self.size
pos: self.pos
cols: 3
row_force_default: True
row_default_height: 40
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
AnchorLayout:
anchor_x: 'right'
anchor_y: 'top'
BoxLayout:
orientation: 'vertical'
size_hint: 0.8, 1
canvas.before:
Color:
rgba: 0, 1, 0, 1
Rectangle:
size: self.size
pos: self.pos
Label:
text: "HELLO..."
Label:
text: "WORLD..."
AnchorLayout:
size_hint: 1, 0.25
anchor_x: 'left'
anchor_y: 'bottom'
canvas.before:
Color:
rgba: 0, 0, 1, 1
Rectangle:
size: self.size
pos: self.pos
Label:
text: "FOOTER"
"""))
Output: Method 2 - BoxLayout as root
Changing the Example class to extend FloatLayout instead of AnchorLayout allows more control of its children. With that change to Example, here is a kv that looks more like what you want:
<Example>:
AnchorLayout:
anchor_x: "center"
anchor_y: "top"
size_hint: (0.2, 0.75)
pos_hint: {'x':0, 'top':1}
GridLayout:
cols: 3
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
Button:
text: "X"
AnchorLayout:
anchor_x: "center"
anchor_y: "top"
size_hint: (0.8, 0.75)
pos_hint: {'right':1, 'top':1}
BoxLayout:
orientation: "vertical"
Label:
text: "HELLO..."
Label:
text: "WORLD..."
AnchorLayout:
anchor_x: "center"
anchor_y: "bottom"
size_hint: (1, 0.25)
pos_hint: {'x':0, 'y':0}
Label:
text: "FOOTER"