button and label text not showing - python

the two windows in the picture are exact copies(same line of code), only difference being that the right window is a screen inside a screen manager, but somehow the window on the right does not show the texts.
i'm not sure what the problem is and can't find anything related to it while doing research.
RIGHT WINDOW PYTHON FILE:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.config import Config
space = ""
x = [(a * 9), (a*16)]
Config.set('graphics', 'width', x[0])
Config.set('graphics', 'height', x[1])
class MainScreen(Screen):
pass
class SecondScreen(Screen):
pass
class ThirdScreen(Screen):
pass
kv = Builder.load_file("main2.kv")
class ComplimentUI(App):
def build(self):
return kv
def change_screen(self, x):
scrnmanager = self.root.ids['sm']
scrnmanager.current = x
if __name__ == "__main__":
ComplimentUI().run()
RIGHT WINDOW BUILDER FILE:(main2.kv)
#:include secondscreen.kv
#:include thirdscreen.kv
<MainScreen>:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
FloatLayout:
TextInput:
pos_hint: {'center_x':1, 'top':.1}
size_hint: .1,.1
multiline: False
font_size: 20
font_name: "Dimbo Regular"
background_normal: ''
background_color: 0,0,0,0
Button:
text: "PLAY!"
pos_hint: {'center_x':.5, 'center_y':.3}
size_hint: .8, .17
font_name: "Splatch"
color: 0.15, .5, 0.2, 1
font_size: 0.14 * self.width
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screentwo")
root.manager.transition.direction = "left"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
ScreenManager:
GridLayout:
cols: 1
ScreenManager:
id: sm
MainScreen:
name: "screenone"
id: screenone
SecondScreen:
name: "screentwo"
id: screentwo
ThirdScreen:
name: "thirdscreen"
id: thirdscreen[enter image description here][1]
LEFT WINDOW PYTHON FILE:
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.config import Config
space = "";
x = [(a * 9), (a*16)]
Config.set('graphics', 'width', x[0])
Config.set('graphics', 'height', x[1])
kv = Builder.load_file("main.kv")
class MyMainApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyMainApp().run()
LEFT WINDOW BUILDER FILE:(main.kv)
FloatLayout:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
TextInput:
pos_hint: {'center_x':1, 'top':.1}
size_hint: .1,.1
multiline: False
font_size: 20
font_name: "Dimbo Regular"
background_normal: ''
background_color: 0,0,0,0
Button:
text: "PLAY!"
pos_hint: {'center_x':.5, 'center_y':.3}
size_hint: .8, .17
font_name: "Splatch"
color: 0.15, .5, 0.2, 1
font_size: 0.14 * self.width
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screentwo")
root.manager.transition.direction = "left"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
NEW EDIT:
as i pointed out in the comment below, the same problem happens with the FloatLayout of secondscreen.kv and thirdscreen.kv, if i put it inside the builder file of the left window, its normal. But when i put it inside a screen inside a screen manager(like the right window) it's gone. the same problem happens to all my screens. the reason i only put the mainscreen.kv is because its the shortest out of all the screens, but nonetheless i will still provide the files, but only 1 version of it (the one used for the right window) since they're basically the same lines. (only difference being the added first line for its class name and a slight indetation change to fit the levels)
SECONDSCREEN BUILDER FILE:
<SecondScreen>:
FloatLayout:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
TextInput:
pos_hint: {'center_x':.5, 'center_y':.56}
size_hint: .8, .3
multiline: False
font_size: 20
font_name: "Dimbo Regular"
background_normal: ''
background_color: 1, 1, .8, 1
Label:
pos_hint: {'center_x':.5, 'center_y':.76}
size_hint: .8, .07
text: "NAME!"
font_size: 0.8 * self.height
font_name: "kidsrock"
color: 0.15, .5, 0.2, 1
background_color: 0,0,0,0
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
Button:
text: "<<<"
size_hint: .28, .07
pos_hint: {'center_x':.24, 'center_y':.1}
font_name: "kidsrock"
color: 0.15, .5, 0.2, 1
font_size: 0.35 * self.width
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screenone")
root.manager.transition.direction = "right"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
Button:
pos_hint: {'center_x':.8, 'center_y':.35}
size_hint: .2, .07
background_normal: ''
background_color: 0,0,0,0
color: 0.15, .5, 0.2, 1
text: "ENTER"
font_name: "kidsrock"
font_size: 0.25 * self.width
on_press:
print("pressed, navigating to next screen")
app.change_screen("thirdscreen")
root.manager.transition.direction = "left"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
THIRDSCREEN BUILDER FILE:
<ThirdScreen>:
FloatLayout:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
TextInput:
pos_hint: {'center_x':1, 'top':.1}
size_hint: .1, .1
multiline: False
font_size: 20
font_name: "Dimbo Regular"
background_normal: ''
background_color: 0, 0, 0, 0
Label:
pos_hint: {'center_x':.5, 'center_y':.71}
size_hint: .8, .17
text: "COMPLIMENT!"
font_size: 20
font_name: "kidsrock"
color: 0.15, .5, 0.2, 1
background_color: 0,0,0,0
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
Button:
pos_hint: {'center_x':.24, 'center_y':.1}
size_hint: .28, .07
font_name: "kidsrock"
color: 0.15, .5, 0.2, 1
font_size: 0.35 * self.width
text: "<<<"
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screentwo")
root.manager.transition.direction = "right"
canvas.before:
Color:
rgb: 1,1, .8,1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
NEW- NEW EDIT!:
UPDATE
after restarting my computer, it now looks like this.

Root Cause - Button & Label text not showing
The most probable cause is that the default color for text is white ([1, 1, 1, 1]), and the background color for both widgets are also white. You need to set the text color to non-white e.g. black ([0, 0, 0, 1]).
TextInput Box - not showing
The TexInput box is not visible in both windows (left & right) because of background_normal: '' and background_color: 0,0,0,0.
Comment them off and the TextInput box will be visible.
Button's text, 'PLAY' - not showing in right window
It could be something in the include kv files e.g. secondscreen.kv, and/or thirdscreen.kv that are/is causing the visibility. Comment off both kv files to trouble shoot the problem.
Example
The following example of the right window i.e. using ScreenManager is able to display the Button's text, "PLAY" and also the TextInput box.
main-right.py
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder
class MainScreen(Screen):
pass
class SecondScreen(Screen):
pass
class ThirdScreen(Screen):
pass
kv = Builder.load_string("""
# :include secondscreen.kv
# :include thirdscreen.kv
<MainScreen>:
canvas.before:
Color:
rgb: .59, .74, .20
Rectangle:
size: self.size
pos: self.pos
FloatLayout:
TextInput:
hint_text: 'Type here'
pos_hint: {'center_x':1, 'top':.1}
size_hint: .1,.1
multiline: False
font_size: 20
# font_name: "Dimbo Regular"
# background_normal: ''
# background_color: 0,0,0,0
Button:
text: "PLAY!"
pos_hint: {'center_x':.5, 'center_y':.3}
size_hint: .8, .17
#font_name: "Splatch"
color: 0.15, .5, 0.2, 1
font_size: 0.14 * self.width
background_normal: ''
background_color: 0,0,0,0
on_press:
print("pressed, navigating to prev screen")
app.change_screen("screentwo")
root.manager.transition.direction = "left"
canvas.before:
Color:
rgba: 1, 1, .8, 1
RoundedRectangle:
size: self.size
pos: self.pos
radius: [4,]
GridLayout:
cols: 1
ScreenManager:
id: sm
MainScreen:
name: "screenone"
id: screenone
SecondScreen:
name: "screentwo"
id: screentwo
ThirdScreen:
name: "thirdscreen"
id: thirdscreen
""")
class RightWindow(App):
title = "ComplimentUI"
def build(self):
return kv
if __name__ == "__main__":
RightWindow().run()
Output

I was facing a similar problem and the bug for me turned out to be a declaration of size_hint_x for the button. Once I removed that, the text was visible.

Related

How to push kivy widget to the top of the screen

Am having a hard time trying to align my widgets to the top of window in kivy, here is the pictorial represenation. My expectation is that adding an empty widget at the bottom would push the widgets to the top of the screen but it only gets to the middle of the screen. Any guidance will be helpful.
Layout
.kv file
#:import utils kivy.utils
#: import Window kivy.core.window.Window
<FlatButton#ButtonBehavior+Label>:
font_size: 14
<PosWindow>:
id: main_win
orientation: 'vertical'
canvas.before:
Color:
rgb: utils.get_color_from_hex('#ffffff')
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
spacing: 0
orientation: 'vertical'
#THE BEGINNNING OF THE TOP BAR
BoxLayout:
size_hint_y: None
height: 30
Label:
text: 'HEADER POSITION'
size_hint_x: .6
bold: True
color: (1,1,1,1)
canvas.before:
Color:
rgb: utils.get_color_from_hex('#5B2437')
Rectangle:
size: self.size
pos: self.pos
Label:
text: 'The Name'
size_hint_x: .4
height: 30
bold: True
color: (1,1,1,1)
canvas.before:
Color:
rgb: utils.get_color_from_hex('#5B2437')
Rectangle:
size: self.size
pos: self.pos
# THE END OF THE TOP BAR
#THE BEGINNING OF THE SECOND WAVE FULL
BoxLayout:
id: current
size_hint_y: None
height: 50
canvas.before:
Color:
rgba: (1,1,1, 1)
Rectangle:
size: self.size
pos: self.pos
Button:
text: 'Current Item:'
background_normal: ''
background_color: (.06, .32, .32, 1)
size_hint_x: .4
Button:
id: cur_product
text: 'Default Product'
background_normal: ''
background_color: (.06, .4, .4, 1)
Button:
id: cur_price
text: '0.00'
background_normal: ''
background_color: (.06, .65, .65, 1)
size_hint_x: .2
Widget: #To place everything at the top of the screen
#THE END OF THE SECOND WAVE FULL
#SEARCH FOR A PRODUCT
BoxLayout:
id: current
orientation: 'horizontal'
size_hint_y: None
height: 50
canvas.before:
Color:
rgba: (1,1,1, 1)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint_x: .4
id: searchBox
canvas.before:
Color:
rgba: (.06, .75, .35, 1)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint_x: .6
id: previewBox
canvas.before:
Color:
rgba: (.06, .35, .85, 1)
Rectangle:
size: self.size
pos: self.pos
Widget:
I found that as a little, I had to remove the first BoxLayout first the empty widgets except for the last boxlayout.
#:import utils kivy.utils
#: import Window kivy.core.window.Window
<FlatButton#ButtonBehavior+Label>:
font_size: 14
:
id: main_win
orientation: 'vertical'
canvas.before:
Color:
rgb: utils.get_color_from_hex('#ffffff')
Rectangle:
size: self.size
pos: self.pos
#THE BEGINNNING OF THE TOP BAR
BoxLayout:
size_hint_y: None
height: 30
Label:
text: 'HEADER POSITION'
size_hint_x: .6
bold: True
color: (1,1,1,1)
canvas.before:
Color:
rgb: utils.get_color_from_hex('#5B2437')
Rectangle:
size: self.size
pos: self.pos
Label:
text: 'The Name'
size_hint_x: .4
height: 30
bold: True
color: (1,1,1,1)
canvas.before:
Color:
rgb: utils.get_color_from_hex('#5B2437')
Rectangle:
size: self.size
pos: self.pos
#THE BEGINNING OF THE SECOND WAVE FULL
BoxLayout:
id: current
size_hint_y: None
height: 50
canvas.before:
Color:
rgba: (1,1,1, 1)
Rectangle:
size: self.size
pos: self.pos
Button:
text: 'Current Item:'
background_normal: ''
background_color: (.06, .32, .32, 1)
size_hint_x: .4
Button:
id: cur_product
text: 'Default Product'
background_normal: ''
background_color: (.06, .4, .4, 1)
Button:
id: cur_price
text: '0.00'
background_normal: ''
background_color: (.06, .65, .65, 1)
size_hint_x: .2
#THE END OF THE SECOND WAVE FULL
#SEARCH FOR A PRODUCT
BoxLayout:
id: current
orientation: 'horizontal'
size_hint_y: None
height: 50
canvas.before:
Color:
rgba: (1,1,1, 1)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint_x: .4
id: searchBox
canvas.before:
Color:
rgba: (.06, .75, .35, 1)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
size_hint_x: .6
id: previewBox
canvas.before:
Color:
rgba: (.06, .35, .85, 1)
Rectangle:
size: self.size
pos: self.pos
Widget:

kivy multiple instances of a screen with unique data

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.

How to Dynamically add a button from the .py file to a single screen of a screen manager in .kv file

How can I dynamically add a button to a particular screen of my .kv file's screenmanager? The problem is, the buttons that get created show up on all screens.
I have a program I am working on that will allow the user to input there particular conditions and calculate ACFM. I am currently trying to set up a file screen that allows the user to create multiple files. I am trying to allow one main button called "create new file" creates more buttons on the first screen. The problem is, the buttons that get created show up on all screens.
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
import Functions as f1
from kivy.uix.button import Button
Window.size = (300,625)
window_x = Window.width
window_y = Window.height
Builder.load_file("main.kv")
class counter:
def __init__(self):
self.count = 2
def increase(self):
self.count += 1
b = counter()
class Calc(FloatLayout):
def testbutton(self,instance):
btn = Button(text = "testing123", color = (1,1,1,1),
size_hint =(.5,.05),
pos = (0,(window_y-(window_y*(.07+(b.count*.05)))))
)
b.increase()
self.add_widget(btn)
# define the multiplication of a function
def calculate(self, instance):
f = float(self.flow.text)
p = float(self.pressure.text)
t = float(self.temperature.text)
sg = float(self.specific_gravity.text)
self.acfm.text = str(f) #str(f1.ACFM(f,p,t,sg)) I commented this out for the purpose of posting this in my questions.
class test(App):
def build(self):
return Calc()
if __name__=="__main__":
test().run()
main.kv
<calc>:
flow: _flow
pressure: _pressure
temperature: _temperature
specific_gravity: _specific_gravity
acfm: _acfm
FloatLayout:
ScreenManager:
id: screen_manager
size: self.size
Screen:
name: "filescreen"
FloatLayout:
canvas:
Color:
rgb: 1,1,1
Rectangle:
size: self.width, self.height
pos: self.pos
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.size
pos: self.pos
Color:
rgb: 0,0,0
Line:
width: 1
rectangle: self.x,self.y,self.width,self.height
size_hint: 1,.07
FilescreenButton:
text: "Create New File"
pos: 0,root.height-(root.height*(.07+.05))
on_press: root.testbutton(*args)
Screen:
name: "solverscreen"
GridLayout:
cols:1
size_hint: 1,1
ScrollView:
FloatLayout:
canvas:
Color:
rgb: 1,1,1
Rectangle:
size: self.width, self.height
pos: self.pos
size_hint: 1,1.5
GridLayout:
cols:1
spacing: 1
pos_hint: {"top": (1),"left": 1}
size_hint: .4, None
row_default_height: root.height*.05
Label:
text: "Inputs"
color: 0,0,0,1
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
CustomLabel:
text: "Flow"
CustomLabel:
text: "Pressure"
CustomLabel:
text: "Temperature"
CustomLabel:
text: "Specific Gravity"
Label:
text: "Results"
color: 0,0,0,1
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
Button:
text: "Calculate"
on_press: root.calculate(*args)
GridLayout:
cols:1
spacing: 1
pos_hint: {"top": (1),"right": .7}
size_hint: .3, None
row_default_height: root.height*.05
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
TextInput:
text: "0"
id: _flow
TextInput:
text: "0"
id: _pressure
TextInput:
text: "0"
id: _temperature
TextInput:
text: ".6"
id: _specific_gravity
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
Label:
id: _acfm
color: 0,0,0,1
canvas.before:
Color:
rgba: .7,.7,.7,1
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: 1,1,1
Line:
width: 1
rectangle: self.x,self.y,self.width,self.height
GridLayout:
cols:1
spacing: 1
pos_hint: {"top": (1),"right": 1}
size_hint: .3, None
row_default_height: root.height*.05
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height/2
pos: self.pos
CustomButton:
text: "MMSCFD"
CustomButton:
text: "PSIG"
CustomButton:
text: "F"
CustomButton:
text: "SG"
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
CustomButton:
text: "ACFM"
AnchorLayout:
anchor_x: 'left'
anchor_y: 'bottom'
GridLayout:
cols: 4
size_hint: 1,.05
canvas:
Color:
rgb: 1,1,1
Rectangle:
size: self.size
pos: self.pos
Button:
text: "Files"
on_press: screen_manager.current = 'filescreen'
Button:
text: "Solver"
on_press: screen_manager.current = 'solverscreen'
<CustomLabel#Label>:
#font_size: (((self.width*5)+(self.height))/6)*.12
canvas.before:
Color:
rgb: 0,0,0
Rectangle:
size: self.size
pos: self.pos
<CustomButton#Button>:
background_color: .25,.25,.25,1
canvas.before:
Color:
rgba: .25,.25,.25,1
Rectangle:
size: self.size
pos: self.pos
Line:
width: .09
rectangle: self.x,self.y,self.width,self.height
<FilescreenButton#Button>:
size_hint: .5,.05
color: 0,0,0,1
background_color: 1,1,1,0
canvas:
Color:
rgb: 0,0,0
Line:
width: 1
rectangle: self.x,self.y,self.width,self.height
I am not getting any error messages. I just want the dynamically created buttons from the .py file to only go to one screen of the .kv file.
You are currently adding it to the Calc FloatLayout which is the root and each screen is a child of this root. If you want to add it to just one screen, than you need to call the add_widgets function of that specific screen.
One option is via an id
change kv file like below
Screen:
id: id_solverscreen
name: "solverscreen"
change py file like below
self.ids.id_solverscreen.add_widget(btn)
python file
from kivy.app import App
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
Window.size = (300,625)
window_x = Window.width
window_y = Window.height
Builder.load_file("main.kv")
class counter:
def __init__(self):
self.count = 2
def increase(self):
self.count += 1
b = counter()
class Calc(FloatLayout):
def testbutton(self,instance):
btn = Button(text = "testing123", color = (1,1,1,1),
size_hint =(.5,.05),
pos = (0,(window_y-(window_y*(.07+(b.count*.05)))))
)
b.increase()
self.ids.id_solverscreen.add_widget(btn)
# define the multiplication of a function
def calculate(self, instance):
f = float(self.flow.text)
p = float(self.pressure.text)
t = float(self.temperature.text)
sg = float(self.specific_gravity.text)
self.acfm.text = str(f) #str(f1.ACFM(f,p,t,sg)) I commented this out for the purpose of posting this in my questions.
class test(App):
def build(self):
return Calc()
if __name__=="__main__":
test().run()
kv file
<calc>:
flow: _flow
pressure: _pressure
temperature: _temperature
specific_gravity: _specific_gravity
acfm: _acfm
FloatLayout:
ScreenManager:
id: screen_manager
size: self.size
Screen:
name: "filescreen"
FloatLayout:
canvas:
Color:
rgb: 1,1,1
Rectangle:
size: self.width, self.height
pos: self.pos
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.size
pos: self.pos
Color:
rgb: 0,0,0
Line:
width: 1
rectangle: self.x,self.y,self.width,self.height
size_hint: 1,.07
FilescreenButton:
text: "Create New File"
pos: 0,root.height-(root.height*(.07+.05))
on_press: root.testbutton(*args)
Screen:
id: id_solverscreen
name: "solverscreen"
GridLayout:
cols:1
size_hint: 1,1
ScrollView:
FloatLayout:
canvas:
Color:
rgb: 1,1,1
Rectangle:
size: self.width, self.height
pos: self.pos
size_hint: 1,1.5
GridLayout:
cols:1
spacing: 1
pos_hint: {"top": (1),"left": 1}
size_hint: .4, None
row_default_height: root.height*.05
Label:
text: "Inputs"
color: 0,0,0,1
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
CustomLabel:
text: "Flow"
CustomLabel:
text: "Pressure"
CustomLabel:
text: "Temperature"
CustomLabel:
text: "Specific Gravity"
Label:
text: "Results"
color: 0,0,0,1
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
Button:
text: "Calculate"
on_press: root.calculate(*args)
GridLayout:
cols:1
spacing: 1
pos_hint: {"top": (1),"right": .7}
size_hint: .3, None
row_default_height: root.height*.05
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
TextInput:
text: "0"
id: _flow
TextInput:
text: "0"
id: _pressure
TextInput:
text: "0"
id: _temperature
TextInput:
text: ".6"
id: _specific_gravity
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
Label:
id: _acfm
color: 0,0,0,1
canvas.before:
Color:
rgba: .7,.7,.7,1
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: 1,1,1
Line:
width: 1
rectangle: self.x,self.y,self.width,self.height
GridLayout:
cols:1
spacing: 1
pos_hint: {"top": (1),"right": 1}
size_hint: .3, None
row_default_height: root.height*.05
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height/2
pos: self.pos
CustomButton:
text: "MMSCFD"
CustomButton:
text: "PSIG"
CustomButton:
text: "F"
CustomButton:
text: "SG"
Label:
canvas.before:
Color:
rgb: 1,1,1
Rectangle:
size: self.width,self.height
pos: self.pos
CustomButton:
text: "ACFM"
AnchorLayout:
anchor_x: 'left'
anchor_y: 'bottom'
GridLayout:
cols: 4
size_hint: 1,.05
canvas:
Color:
rgb: 1,1,1
Rectangle:
size: self.size
pos: self.pos
Button:
text: "Files"
on_press: screen_manager.current = 'filescreen'
Button:
text: "Solver"
on_press: screen_manager.current = 'solverscreen'
<CustomLabel#Label>:
#font_size: (((self.width*5)+(self.height))/6)*.12
canvas.before:
Color:
rgb: 0,0,0
Rectangle:
size: self.size
pos: self.pos
<CustomButton#Button>:
background_color: .25,.25,.25,1
canvas.before:
Color:
rgba: .25,.25,.25,1
Rectangle:
size: self.size
pos: self.pos
Line:
width: .09
rectangle: self.x,self.y,self.width,self.height
<FilescreenButton#Button>:
size_hint: .5,.05
color: 0,0,0,1
background_color: 1,1,1,0
canvas:
Color:
rgb: 0,0,0
Line:
width: 1
rectangle: self.x,self.y,self.width,self.height

Why is Screens not loading in Kv Language?

I have an App with three toggle buttons in a fixed header that is an outside indented layout for screen manager. On initialisation, the Import screen must show i.e. self.ids.scrn_man.current = 'import_scn" and when a toggle button is pushed a next screen should show i.e. on_state: scrn_man.current = "settings_scrn".
But for some reason, only the header is showing and the screens do not want to transition. I don't get any errors.
I tried different layouts as my Apps main class inheritance including, FloatLayout, StackLayout and BoxLayout. I also made the header fixed with AnchorLayout and use a different layout as the inline layout for ScreenManager. If I remove the ScreenManager I see my widgets, but of course, I cannot transition. I did at first try using TabbedPanel to house my different widgets but I encountered a constant RefError: weak object reference if I added too many widgets (but that's not for now). So I re-designed with something I knew worked on a previous App albeit less complex.
Here is my faulty code:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.stacklayout import StackLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.properties import StringProperty, ObjectProperty
Builder.load_string("""
<RoundedButton#Button>:
background_color: 0,0,0,0
canvas.before:
Color:
rgba: (.47,.47,.47,1) if self.state=='normal' else (1,.6,0,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [8,]
<RoundedCancelButton#Button>:
background_color: 0,0,0,0
canvas.before:
Color:
rgba: (.47,.47,.47,1) if self.state=='normal' else (1,.2,.2,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [8,]
<RoundedAcceptButton#Button>:
background_color: 0,0,0,0
canvas.before:
Color:
rgba: (.47,.47,.47,1) if self.state=='normal' else (.2,1,.6,1)
RoundedRectangle:
pos: self.pos
size: self.size
radius: [8,]
<TabbedContainer#ToggleButton>:
background_color: (1, .5, 0, 1)
background_normal: ''
size_hint_y: None
height: 50
size_hint_x: (1 / 3)
spacing: 30
<Tab>:
canvas.before:
Color:
rgba: (.89, .89, .89, 1)
Rectangle:
size: self.size
pos: self.pos
orientation: 'lr-tb'
BoxLayout:
orientation: 'horizontal'
size_hint_y: None
height: 30
canvas.before:
Color:
rgba: (1, .3, 0, 1)
Rectangle:
size: self.size
pos: self.pos
Label:
text: 'Test'
color: (1, 1, 1, 1)
size_hint_x: 1
StackLayout:
orientation: 'lr-tb'
Label:
text: ''
size_hint_x: 1
size_hint_y: None
height: 10
TabbedContainer:
id: import_tog
text: 'Import'
state: 'down'
group: 'admin_navs'
on_state: root.change_screen(self)
TabbedContainer:
id: calculate_tog
text: 'Calculate'
group: 'admin_navs'
on_state: root.change_screen(self)
TabbedContainer:
id: settings_tog
text: 'Settings'
group: 'admin_navs'
on_state: root.change_screen(self)
BoxLayout:
id: ui_content
padding: 10
ScreenManager: #Problem here I think
id: scrn_man
Screen:
id: import_scrn
name: 'import_scrn'
StackLayout:
orientation: 'lr-tb'
Label:
text: ''
size_hint_x: 1
Label:
text: ''
size_hint_x: 0.2
RoundedButton:
text: 'Choose File'
size_hint_x: 0.2
TextInput:
id: get_file
readonly: True
size_hint_x: 0.5
Label:
text: ''
size_hint_x: 0.1
Label:
text: ''
size_hint_x: 0.2
RoundedButton:
text: 'Import'
size_hint_x: 0.2
Label:
text: ''
size_hint_x: 0.6
StackLayout:
id: import_data_content
orientation: 'lr-tb'
size_hint_y: None
height: 90
Screen:
id: calculate_scrn
name: 'calculate_scrn'
Screen:
id: settings_scrn
name: 'settings_scrn'
StackLayout:
orientation: 'lr-tb'
size_hint_x: 0.5
Label:
text: ''
size_hint_x: 0.1
Button:
text: 'Add Employee'
size_hint_x: 0.2
Label:
text: ''
size_hint_x: 0.2
Button:
text: 'CSV'
size_hint_x: 0.2
Label:
text: ''
size_hint_x: 0.3
BoxLayout:
orientation: 'horizontal'
size_hint_x: 0.5
Label:
text: 'In Time'
size_hint_x: 0.7
TextInput:
size_hint_x: 0.3
Label:
text: 'Out Time'
size_hint_x: 0.7
TextInput:
size_hint_x: 0.3
""")
class TabbedContainer(ToggleButton):
pass
class FileChoosePopup(Popup):
load = ObjectProperty()
class RoundedButton(Button):
pass
class RoundedCancelButton(Button):
pass
class RoundedAcceptButton(Button):
pass
class Tab(StackLayout):
file_path = StringProperty("No file chosen")
the_popup = ObjectProperty(None)
def __init__(self, **kwargs):
super().__init__(**kwargs)
#load import window on initialisation
import_window = self.ids.import_scrn
self.ids.scrn_man.current = 'import_scrn'
def change_screen(self, instance):
if instance.text == 'Import':
self.ids.scrn_man.current = 'import_scrn'
elif instance.text == 'Calculate':
self.ids.scrn_man.current = 'calculate_scrn'
else:
self.ids.scrn_man.current = 'settings_scrn'
class TestApp(App):
def build(self):
return Tab()
if __name__ == '__main__':
TestApp().run()
I expect that the import screen must show on initialisation and screens transition on toggle button state: down. Can someone please give me some advice on how to make my App act as explained above?
Your screens are loading correctly according to your settings. You need to review your entire kv string looking at your size_hint settings. Check each item that contains children and make sure that the total of size_hint_x for its children is less than or equal to 1.0 and the same for size_hint_y.

How do I position widgets and use layouts in Kivy?

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}

Categories

Resources