I have two toggle buttons. When one is in the "down" state I need the other one to be in the "normal" state. I tried making an if statement but it makes both buttons have the same state at the same time. Here it is:
on_state: exlexport.state = "down" if exlexport.state == "normal" else "normal"
Here is my full code:
<SettingsWindow>:
name:"settings"
FloatLayout:
Widget:
canvas.before:
# Background
Rectangle:
pos: self.pos
size: self.size
source: "Images/logo_br.png"
# Brothers Menu
Color:
rgba: 1,1,1,.3
Rectangle:
size: 200, 500
pos: self.width/10, self.height/7
Color:
rgba: 0,0,0,.5
Rectangle:
size: 190, 350
pos: self.width/9.4, self.height/3
# Jobs Menu
Color:
rgba: 1,1,1,.3
Rectangle:
size: 200, 500
pos: self.width/2.5, self.height/7
Color:
rgba: 0,0,0,.5
Rectangle:
size: 190, 350
pos: self.width/2.465, self.height/3
# Export Menu
Color:
rgba: 1,1,1,.3
Rectangle:
size: 200, 250
pos: self.width/1.43, self.height/3.08
Color:
rgba: 0,0,0,.5
Rectangle:
size: 190, 205
pos: self.width/1.416, self.height/3
# Brothers Scroll List
ScrollView:
size_hint: (None, None)
size: (150, 325)
pos_hint: {'center_x': .23, 'center_y': .62}
# Brothers Menu Scroll Label
Label:
size_hint: None, None
size: self.texture_size
text: root.pretty_list_people
# Jobs Menu Scroll Label
ScrollView:
size_hint: (None, None)
size: (150, 325)
pos_hint: {'center_x': .53, 'center_y': .62}
Label:
size_hint: None, None
size: self.texture_size
text: root.pretty_list_jobs
Button:
text:"Back"
size_hint: 0.1, 0.1
pos_hint: {"x":0, "y":0}
background_color: 1,1,1,.6
on_release:
app.root.current = "main"
root.manager.transition.direction = 'right'
# Brothers Title
Label:
text: "Brothers"
font_size: 30
italic: True
pos_hint: {"x":-0.275, "y":0.45}
color: 0,0,0,1
# Jobs Title
Label:
text: "Jobs"
font_size: 30
italic: True
pos_hint: {"x":0.02, "y":0.45}
color: 0,0,0,1
# Exporting Title
Label:
text: "Exporting"
font_size: 30
italic: True
pos_hint: {"x":0.325, "y":0.21}
color: 0,0,0,1
# Brothers Menu Buttons
Button:
text:"Update"
size_hint: 0.25, 0.1
pos_hint: {"x":0.1, "y":0.144}
on_press: root.Pretty_Print_People(root.get_People())
Button:
text:"Add"
size_hint: 0.125, 0.09
pos_hint: {"x":0.1, "y":0.243}
on_press: root.showpop_addbro()
Button:
text:"Remove"
size_hint: 0.125, 0.09
pos_hint: {"x":0.225, "y":0.243}
on_press: root.showpop_removebro()
Button:
text:"Update"
size_hint: 0.25, 0.1
pos_hint: {"x":0.1, "y":0.144}
on_press: root.Pretty_Print_People(root.get_People())
# Jobs Menu Buttons
Button:
text:"Add"
size_hint: 0.125, 0.09
pos_hint: {"x":0.4, "y":0.243}
on_press: root.showpop_addjob()
Button:
text:"Remove"
size_hint: 0.125, 0.09
pos_hint: {"x":0.525, "y":0.243}
on_press: root.showpop_removejob()
Button:
text: "Update"
size_hint: 0.25, 0.1
pos_hint: {"x":0.4, "y":0.144}
on_press: root.Pretty_Print_Jobs(root.get_Jobs())
# Exporting Menu Content
ToggleButton:
id: txtexport
text: "Toggle Text File Export"
size_hint: 0.236, 0.08
pos_hint: {"x":0.707, "y":0.59}
on_state: exlexport.state = "down" if exlexport.state == "normal" else "normal"
ToggleButton:
id: exlexport
text: "Toggle Excel File Export"
size_hint: 0.236, 0.08
pos_hint: {"x":0.707, "y":0.51}
The toggle buttons start after the comment "Exporting Menu Content"
ToggleButton:
id: txtexport
group: 'exportopts'
text: "Toggle Text File Export"
size_hint: 0.236, 0.08
pos_hint: {"x":0.707, "y":0.59}
state: 'down'
ToggleButton:
id: exlexport
group: 'exportopts'
text: "Toggle Excel File Export"
size_hint: 0.236, 0.08
pos_hint: {"x":0.707, "y":0.51}
Credit to this solution goes to John Anderson! Thank you.
Just assign the toggle buttons the same group via group property and set the state of one them to 'down'.
I was looking for a way to always make one of my toggle buttons be "down" because belonging to the same group, don't assure me that, they can both be "normal". In order to get that result and have always one button "down", I've added this line on each one:
on_press: self.state = "down"
Related
I completed my code for main window which is the login page and I'm writing my code for the second page. Then, I tried to use the text field on my login screen and I can't type in it. However, before making my second window, the text field worked as expected and I can type in it. What could cause this issue?
Furthermore, I recieve an error (AttributeError: 'super' object has no attribute 'getattr'
) when I tried to press the clear button in main window.
Also, if you tried to run this code and see the second window, you will notice 3 MD cards not aligned properly if you don't expand the window to full size. if you have any idea how to fix it, please let me know.
SUMMARY OF WHAT I'M TRYING TO ACHIEVE HERE:
Figure out what why I can't use the textfield in main window
Fix the error when press the clear button
Align MD Cards properly
.py file
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import ScreenManager, Screen
class MainWindow(Screen):
pass
class SecondWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class BaseApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "Green"
return Builder.load_file("base.kv")
def clear(self):
self.root.ids.user.text = ""
self.root.ids.passw.text = ""
if __name__ == "__main__":
BaseApp().run()```
.kv file
# Filename: base.kv
#:kivy 2.1.0
#:include main.py
WindowManager:
MainWindow:
SecondWindow:
<MainWindow>:
name: "main"
Screen:
MDCard:
size_hint: None, None
size: 400, 500
pos_hint: {"center_x": 0.5, "center_y": 0.5}
elevation: 10
padding: 25
spacing: 25
orientation: "vertical"
MDLabel:
id: login_label
text: "WELCOME TO JAMES MADISON/n HIGH SCHOOL STUDENTS APP"
font_size: 22
font_name: "Raleway-Regular"
halign: "center"
size_hint_y: None
height: self.texture_size[1]
padding_y: 15
MDBoxLayout:
Image:
source: "jmhs.png"
size_hint_x: 1.15
halign: "center"
size_hint_y: 1.15
height: self.texture_size[1]
padding_y: 10
MDTextFieldRound:
id: user
hint_text: "Username"
icon_right: "account"
size_hint_x: None
width: 200
font_size: 18
font_name: "Roboto-Regular"
pos_hint: {"center_x": 0.5}
MDTextFieldRound:
id: passw
hint_text: "Password"
icon_right: "eye-off"
size_hint_x: None
width: 200
font_size: 18
font_name: "Roboto-Regular"
pos_hint: {"center_x": 0.5}
password: True
MDRoundFlatButton:
text: "LOG IN"
font_size: 12
font_name: "Raleway-Regular"
pos_hint: {"center_x": 0.5}
on_press:
app.root.current = "second"
root.manager.transition.direction = "left"
MDRoundFlatButton:
text: "CLEAR"
font_size: 12
font_name: "Raleway-Regular"
pos_hint: {"center_x": 0.5}
on_press: app.clear()
<SecondWindow>:
name: "second"
MDBoxLayout:
orientation: "horizontal"
MDBoxLayout:
size_hint: .225, 1
canvas.before:
Color:
rgba: 0, 0, 0, 0
Rectangle:
pos: self.pos
size: self.size
MDBoxLayout:
orientation: "vertical"
spacing: "10dp"
size_hint: 1, 1
canvas.before:
Color:
rgba: 227/255, 255/255, 226/255, 0.8
Rectangle:
pos: self.pos
size: self.size
MDBoxLayout:
spacing: "10dp"
size_hint: 1, .1
MDBoxLayout:
spacing: "10dp"
size_hint: 1, .9
canvas.before:
Color:
rgba: 227/255, 255/255, 226/255, 0.8
Rectangle:
pos: self.pos
size: self.size
MDGridLayout:
cols: 3
padding: 18
spacing: "20dp"
MDCard:
padding: 16
elevation: 0
border_radius: 20
radius: [15]
size_hint: None, None
size: "370dp", "140dp"
pos_hint: {"center_x": .5, "center_y": .5}
MDCard:
padding: 16
elevation: 0
border_radius: 20
radius: [15]
size_hint: None, None
size: "370dp", "140dp"
pos_hint: {"center_x": .5, "center_y": .5}
MDCard:
padding: 16
elevation: 0
border_radius: 20
radius: [15]
size_hint: None, None
size: "200dp", "140dp"
pos_hint: {"center_x": .5, "center_y": .5}
MDBoxLayout:
size_hint: .29, 1
canvas.before:
Color:
rgba: 0, 0, 0, 0
Rectangle:
pos: self.pos
size: self.size
When I double click on the video, it goes full screen, but if I double click on it again, it doesn't go back to normal. However, the rest of the window elements are partially visible. The part of my .kv code responsible for the VideoPlayer is given below:
<VideosWindow>:
name: 'vids'
FloatLayout:
FileChooserListView:
id:chooser
path: root.get_files_list()
canvas.before:
Color:
rgb: .4, .5, .5
Rectangle:
pos: self.pos
size: self.size
on_selection: root.select(chooser.selection)
size_hint: (.9, .15)
pos_hint: {'x':.05, 'y':.8}
VideoPlayer:
id:vid
options: {'eos':'loop'}
size_hint: (.9, .7)
pos_hint: {'x':.05, 'y':.05}
Button:
size_hint_y: 0.3
height: 48
text: "open"
disabled: not chooser.selection
on_release: root.select(chooser.selection)
size_hint: (.45, .05)
pos_hint: {'x':.05, 'y':.00}
Button:
text: 'Go Back'
color: (1,1,1,1)
background_normal:''
background_color: (0.3,0.6,0.7,1)
on_release:
vid.state = 'pause'
app.root.current = 'saved_files'
size_hint: (.45, .05)
pos_hint: {'x':.50, 'y':.00}
VideosWindow class code:
class VideosWindow(Screen):
def get_files_list(self):
files = os.sep.join([my_folder,'mp4'])
return files
def select(self, filename):
self.ids.vid.source = filename[0]
self.ids.vid.state = 'play'
The screenshots of my program before and after I go fullscreen mode:
before
after
Solved this issue by adding VideoPlayer widget to the GridLayout. Now .kv code looks like this:
<VideosWindow>:
name: 'vids'
FloatLayout:
FileChooserListView:
id:chooser
path: root.get_files_list()
canvas.before:
Color:
rgb: .4, .5, .5
Rectangle:
pos: self.pos
size: self.size
on_selection: root.select(chooser.selection)
size_hint: (.9, .15)
pos_hint: {'x':.05, 'y':.8}
GridLayout:
cols:1
size_hint: (.9, .7)
pos_hint: {'x':.05, 'y':.05}
VideoPlayer:
id:vid
options: {'eos':'loop'}
Button:
size_hint_y: 0.3
height: 48
text: "open"
disabled: not chooser.selection
on_release: root.select(chooser.selection)
size_hint: (.45, .05)
pos_hint: {'x':.05, 'y':.00}
Button:
text: 'Go Back'
color: (1,1,1,1)
background_normal:''
background_color: (0.3,0.6,0.7,1)
on_release:
vid.state = 'pause'
app.root.current = 'saved_files'
size_hint: (.45, .05)
pos_hint: {'x':.50, 'y':.00}
Don't know if it is good decision but it works.
Good Morning,
I work on my cross-platform app project. I've got a trouble with size management in KivyMD.
I would like to change the size and position of my widgets as well as this I want to set size_hint into (None, None) in order to have a right working on cross-platform devices. I try to change the size with size parameter but this only works on the y-axis. X-axis is still in the beginning position. I would like to ask about another widgets like icons, FloatLayout layers how to set size_hint to None and also change the size in order to have a right working on cross-platform devices.
#: import utils kivy.utils
MDScreen:
name: "LoginPage"
on_enter:
app.animationBack1(back1)
app.animationBack2(back2)
app.animationIcon(userIcon)
app.animationLoginLabel(loginLabel)
MDFloatLayout:
MDFloatLayout:
id: back1
size_hint_y: .3
pos_hint: {'center_y': 1.5}
canvas.before:
Color:
rgb: utils.get_color_from_hex('#74A3FC')
Rectangle:
size: self.size
pos: self.pos
MDFloatLayout:
id: back2
size_hint_y: .6
pos_hint: {'center_y': 1.5}
canvas.before:
Color:
rgb: utils.get_color_from_hex('#74A3FC') # most
Ellipse:
size: self.size
pos: self.pos
MDIcon:
id: userIcon
halign: 'center'
icon: 'account-circle'
font_size: '70sp'
pos_hint: {'center_x': .5, 'center_y': .75}
opacity: 0 # visibility
MDLabel:
id: loginLabel
text: '[size=60][b]Login Page[/b][/size]'
markup: True
halign: 'center'
pos_hint: {'center_y': .8}
opacity: 0 # visibility
MDTextField:
id: email
hint_text: 'Enter Email'
required: True
helper_text_mode: 'on_error'
helper_text: 'Please, enter Your Email.'
color_mode: 'custom'
line_color_focus: utils.get_color_from_hex('#74A3FC')
current_hint_text_color: utils.get_color_from_hex('#74A3FC') # can be, otherwise after running app, hint_text will be grey
# after error rasing hint_text will be also customized
size: 800, 1
size_hint: None, None
pos_hint: {'center_x': .5, 'center_y': .45}
MDTextField:
id: password
hint_text: 'Enter Password'
password: True
required: True
helper_text_mode: 'on_error'
helper_text: 'Please, enter Your Password.'
pos_hint: {'center_x': .5, 'center_y': .3}
size: 800, 1
size_hint: (None, None)
line_color_focus: utils.get_color_from_hex('#74A3FC')
current_hint_text_color: utils.get_color_from_hex('#74A3FC')
color_mode: 'custom' # must be, otherwise on the second click line color
will customized
MDFillRoundFlatButton:
text: 'Login'
pos_hint: {'center_x': .5, 'center_y': 0.05}
size: 800, 100
size_hint: (None, None) #text never leaves the button-I don't know why
# theme_text_color: 'Error' #['Primary', 'Secondary', 'Hint', 'Error', 'Custom', 'ContrastParentBackground'] - only change text color
md_bg_color: utils.get_color_from_hex('#74A3FC')
try to use
root.width*i, root.height*j ##when dealing with widget size and pos it will get u what u want
good day
is it possible to have multiple instances of a screen each using unique data? for example, i have a 'homescreen' with various buttons for various categories that takes you to a batch list screen unique to that category where you can add batches to be listed. each buttons batch list screen would have unique data to that category but the template for all batch list screens are the same.
ive made a simple example for one category but in order to expand it to the others would i need to repeat the code and create appropriately named .kv files and add each screen to the screen manager.
.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.uix.behaviors.touchripple import TouchRippleButtonBehavior
from kivy.uix.button import Button
from kivy.clock import Clock
from kivy.uix.textinput import TextInput
class CapitalInput(TextInput):
def insert_text(self, substring, from_undo=False):
s = substring.upper()
return super(CapitalInput, self).insert_text(s, from_undo=from_undo)
class RippleButton(TouchRippleButtonBehavior, Button):
def on_touch_down(self, touch):
collide_point = self.collide_point(touch.x, touch.y)
if collide_point:
touch.grab(self)
self.transparency = self.background_color[3]
self.background_color[3] = 0.5 # set transparency to half (0.5)
self.ripple_show(touch)
self.dispatch('on_press')
return True
return False
def on_touch_up(self, touch):
if touch.grab_current is self:
touch.ungrab(self)
self.ripple_fade()
def defer_release(dt):
self.background_color[3] = self.transparency
self.dispatch('on_release')
Clock.schedule_once(defer_release, self.ripple_duration_out)
return True
return False
class AddBatchScreen(Screen):
pass
class BatchScreen(Screen):
pass
class HomeScreen(Screen):
pass
gui = Builder.load_file('BatchTracker.kv')
class BatchTrackerApp(App):
def build(self):
return gui
def insert(self, value):
bs = self.root.get_screen('batch_screen')
bs.ids.rv.data.insert(0, {'value': value or 'default value'})
if __name__ == '__main__':
BatchTrackerApp().run()
BatchTraker.kv
#:kivy 1.11.1
#:include batchscreen.kv
#:include add_batch_screen.kv
#:include homescreen.kv
#:import hex kivy.utils.get_color_from_hex
#:import TouchRippleButtonBehavior kivy.uix.behaviors.touchripple
#:import SlideTransition kivy.uix.screenmanager.SlideTransition
ScreenManager:
id: screen_manager
HomeScreen:
name: 'home_screen'
id: home_screen
BatchScreen:
name: 'batch_screen'
id: batch_screen
AddBatchScreen:
name: 'add_batch_screen'
id: add_batch_screen
<RoundButton#RippleButton>:
background_color: (0,0,0,0)
background_normal: ''
back_color: (1,0,1,1)
border_radius: [20]
canvas.before:
Color:
rgba: self.back_color
RoundedRectangle:
size: self.size
pos: self.pos
radius: self.border_radius
homescreen.kv
<HomeScreen>:
BoxLayout:
orientation: 'vertical'
canvas:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
Label:
canvas.before:
Color:
rgba: 1, 0.7, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
size_hint_y: None
pos_hint: {'top': .1}
text: 'Home Screen'
font_size: 40
GridLayout:
rows: 4
AnchorLayout:
canvas:
Color:
rgba: 0.1, 0.1, 1, 0.9
Rectangle:
pos: self.pos
size: self.size
Button:
pos_hint: {'center_x': 0.5}
size_hint: 0.5, 0.7
halign: 'center'
valign: 'middle'
text: 'Isolations'
font_size: 40
size: self.texture_size
text_size: self.width, None
on_press: print('isolations')
on_release: root.manager.current = 'batch_screen'
AnchorLayout:
canvas:
Color:
rgba: 0.1, 0.1, 1, 0.9
Rectangle:
pos: self.pos
size: self.size
Button:
pos_hint: {'center_x': 0.5}
size_hint: 0.5, 0.7
halign: 'center'
valign: 'middle'
text: 'QPCR'
font_size: 40
size: self.texture_size
text_size: self.width, None
on_release: root.manager.current = 'batch_screen'
AnchorLayout:
canvas:
Color:
rgba: 0.1, 0.1, 1, 0.9
Rectangle:
pos: self.pos
size: self.size
Button:
pos_hint: {'center_x': 0.5}
size_hint: 0.5, 0.7
halign: 'center'
valign: 'middle'
text: 'PCR'
font_size: 40
size: self.texture_size
text_size: self.width, None
AnchorLayout:
canvas:
Color:
rgba: 0.1, 0.1, 1, 0.9
Rectangle:
pos: self.pos
size: self.size
Button:
pos_hint: {'center_x': 0.5}
size_hint: 0.5, 0.7
halign: 'center'
valign: 'middle'
text: 'Electrophoresis'
font_size: 40
size: self.texture_size
text_size: self.width, None
batchscreen.kv
<Row#BoxLayout>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Button:
text: root.value
font_size: sp(80)
on_press: print(f'pressed button {root.value}')
<BatchScreen>:
rv: rv #to expose the widget
FloatLayout:
canvas:
Color:
rgba: hex('c6e2ff')
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
canvas.before:
Color:
rgba: hex('b3b3ff')
RoundedRectangle:
radius: 0,0,25,25
pos: self.pos
size: self.size
pos_hint: {'top':1}
size_hint: 1, .1
Label:
id: lb
text: 'User'
font_size: 60
pos_hint: {'top': 1, 'x': .15}
size_hint: .2, .8
RoundButton:
text: 'Sign Out'
font_size: 40
on_release: print('Sign Out pressed')
pos_hint: {'top': .95, 'x': .55}
size_hint: .4, .8
BoxLayout:
canvas.before:
Color:
rgba: hex('eaec3c')
Rectangle:
pos: self.pos
size: self.size
pos_hint: {'center_x':.5,'center_y':.5}
size_hint: 0.9,0.8
RecycleView:
id: rv
viewclass: 'Row'
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
RecycleBoxLayout:
default_size: None,100
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
GridLayout:
cols:3
canvas.before:
Color:
rgba: hex('969c9c')
Rectangle:
pos: self.pos
size: self.size
pos_hint: {'y': 0}
size_hint: 1, .1
RoundButton:
id: add_batch
text: 'Add Batch'
font_size: 30
on_press: root.manager.transition = SlideTransition(direction="left")
on_release: root.manager.current = 'add_batch_screen'
pos_hint: {'center_y': .5, 'x': .05}
size_hint: .4, .8
back_color: hex('62fd00')
RoundButton:
text: 'Remove Batch'
font_size: 30
halign: 'center'
valign: 'middle'
size: self.texture_size
text_size: self.width, None
on_release: print('Remove pressed')
on_release: print(root.manager.ids.batch_screen.rv.data)
pos_hint: {'center_y': .5, 'x': .55}
size_hint: .4, .8
back_color: hex('fd0000')
RoundButton:
text: 'Back'
font_size: 30
halign: 'center'
valign: 'middle'
size: self.texture_size
text_size: self.width, None
on_press: print('Back pressed')
on_release: root.manager.current = 'home_screen'
pos_hint: {'center_y': .5, 'x': .55}
size_hint: .4, .8
back_color: hex('0000ff')
add_batch_screen.kv
<AddBatchScreen>:
canvas:
Color:
rgba: 0,0,1,1
Rectangle:
pos: self.pos
size: self.size
CapitalInput:
id: capital_input
size_hint: .9, .15
pos_hint: {'center_x': .5, 'y': .6}
font_size: 40
padding: [0, (self.height-self.line_height)/2]
hint_text: 'Batch No.'
multiline: False
halign: 'center'
Button:
id: addbtn
text: 'Add'
size_hint: .4, .08
pos_hint: {'center_x': .5, 'y': .2}
on_press: app.insert(capital_input.text) if capital_input.text != '' else None
on_release: capital_input.text = ''
Button:
text: 'Batch List'
size_hint: .4, .08
pos_hint: {'center_x': .5, 'y': .1}
on_press: root.manager.transition = SlideTransition(direction="right")
on_release: root.manager.current = 'batch_screen'
on_release: print(root.manager.ids.batch_screen.rv.data)
As this is a lot of code you will have a hard time finding someone to give you a specific answer. Without looking through all of your code, yes it is possible to have multiple instances of a screen with unique data. This is exactly the use case of class instances. You simply need to pass a variable, list or object into the instance. I will give you a short example, then you should be able to figure it out yourself for your code.
class MyReusableScreen(Screen):
def __init__(self, data, **kwargs):
super(MyReusableScreen, self).__init__(**kwargs)
self.data = data
mylabel = Label(text=self.data['mylabel_text'])
We added the attribute data to the class. Now we have to pass the data when we initialize the class instance
data1 = {'mylabel_text': 'first label'}
data2 = {'mylabel_text': 'second label'}
screen1 = MyReusableScreen(data=data1)
screen2 = MyReusableScreen(data=data2)
Like this we added unique label texts to the class instances labels. I guess you should now be able to build it up on your own. In case you defined a label in kv language, give it an id like for exanple id: mylabel and then assign the data value like this within you screen mylabel.text = self.data['mylabel_text']. I hope this helps you and if you struggle with something just give me a sign.
This: (https://imgur.com/a/Y9Xwl) (can't format it for some reason) is the user interface I am currently trying to create in Kivy. I am having difficulty recreating this as I do not understand the layout system and I have read a lot of documentation, watched a lot of Youtube videos, tinkered with the code and still I cannot get the desired result. So far this is my code, it has all the widgets that I need within it, they're just not sized/positioned how I want them:
from kivy.app import App
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.properties import ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class CaloriesScreen(Screen):
pass
class categoriesScreen(Screen):
pass
class loginScreen(Screen):
pass
class registerScreen(Screen):
pass
class shoppingListScreen(Screen):
pass
class theScreenManager(ScreenManager):
pass
root_widget = Builder.load_string('''
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
theScreenManager:
transition: FadeTransition()
CaloriesScreen:
<CaloriesScreen>:
name: 'calories'
BoxLayout:
orientation: 'vertical'
BoxLayout:
orientation: 'horizontal'
size_hint: 1, .3
Button:
text: '<'
size_hint: .1, 1
font_size: 75
background_normal: ""
background_color: 0.18, .5, .92, 1
on_release: app.root.current = 'main'
Label:
text: 'Calories'
halign: 'left'
font_size: 50
canvas.before:
Color:
rgb: 0.18, .5, .92
Rectangle:
pos: self.pos
size: self.size
Widget:
size_hint: .1, 1
canvas.before:
Color:
rgb: 0.18, .5, .92
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
orientation: 'horizontal'
size_hint: 1, .4
canvas.before:
Color:
rgb: 0.8, 0.8, 0.8
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Recipes'
font_size: 30
color: 0.18, .5, .92, 1
size_hint: 1, 1
Button:
id: btn
text: 'Select a recipe...'
on_release: dropdown.open(self)
height: '48dp'
size_hint: .5, .3
pos: self.x, .3
DropDown:
id: dropdown
on_parent: self.dismiss()
on_select: btn.text = '{}'.format(args[1])
Button:
text: 'First recipe'
size_hint_y: None
height: '48dp'
on_release: dropdown.select('First Item')
Button:
text: 'Second recipe'
size_hint_y: None
height: '48dp'
on_release: dropdown.select('Second Item')
Button:
text: 'Third recipe'
size_hint_y: None
height: '48dp'
on_release: dropdown.select('Third Item')
Button:
text: '+'
font_size: 30
background_normal: ""
background_color: 0.18, .5, .92, 1
#on_release:
BoxLayout:
orientation: 'vertical'
BoxLayout:
orientation: 'horizontal'
Label:
text: 'Food'
font_size: 30
color: 0.18, .5, .92, 1
Label:
text: 'Cal'
font_size: 30
color: 0.18, .5, .92, 1
BoxLayout:
orientation: 'horizontal'
Label:
text: 'Simple Cheese Omelette'
font_size: 30
color: 0.18, .5, .92, 1
Label:
text: '241'
font_size: 30
color: 0.18, .5, .92, 1
BoxLayout:
orientation: 'horizontal'
Label:
text: 'Burger'
font_size: 30
color: 0.18, .5, .92, 1
Label:
text: '295'
font_size: 30
color: 0.18, .5, .92, 1
BoxLayout:
orientation: 'horizontal'
Label:
text: 'Tomato and caper linguine '
font_size: 30
color: 0.18, .5, .92, 1
Label:
text: '393'
font_size: 30
color: 0.18, .5, .92, 1
BoxLayout:
orientation: 'vertical'
canvas.before:
Color:
rgb: 0.8, 0.8, 0.8
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
orientation: 'horizontal'
Label:
text: 'Total Cal'
font_size: 30
color: 0.18, .5, .92, 1
Label:
text: '929'
font_size: 30
color: 0.18, .5, .92, 1
BoxLayout:
orientation: 'horizontal'
Label:
text: 'You are under calories'
font_size: 30
color: 0.18, .5, .92, 1
Button:
text: 'Clear'
font_size: 75
background_normal: ""
background_color: 0.18, .5, .92, 1
#on_release:
''')
class RecipeApp(App):
def build(self):
return root_widget
if __name__ == "__main__":
RecipeApp().run()
This(https://imgur.com/a/zW2z0) (can't format it for some reason) is what the output of that code looks like. The top bar with the "<" button is how I want it and I've only tried to edit the horizontal row of widgets below it. I cannot position the dropdown menu with the 'select your recipe' label how I would like it. I have tried altering it's y-axis multiple times but it always sinks to the botton of the boxlayout. I even tried giving it a new boxlayout just for the dropdown and tried doing: pos: self.parent.x, self.parent.y * 0.5 assuming it would go halfway up the y-axis of it's parent layout (the boxlayout) but still nothing. I am wondering whether it would be better to just use a floatlayout and manually position all the widgets but I am unsure how this will work well when I compile it into an APK for an Android device. What is the best way to go about positioning my widgets on the screen?
Use pos_hint for this.
If pos_hint: {'top': 1}, the top of the widget will hit the roof of the parent box.
So if your widgets height is 30% of its parent box (size_hint: 0.5, 0.3), and you want it to be centered vertically, you want pos_hint: {'top': 0.5 + 0.3/2}, which means the top of the widget will be half way to the roof + half of the widgets height which is 15% of the parent box.
That takes us 65% to the top :)
size_hint: 0.5, 0.3
pos_hint: { 'top' : 0.65}
If the widgets size_hint is dynamic you can do something like this.
pos_hint: {'top': 0.5 + self.size_hint[1]/2}
And lets take your Select recipe button as an example:
Button:
id: btn
text: 'Select a recipe...'
on_release: dropdown.open(self)
height: '48dp'
size_hint: .5, .3
pos_hint: {'top': 0.5 + self.size_hint[1]/2}