How can I make Spacing in BoxLayout? - python

I try to build a simple layout of widgets.
The BoxLayout includes three widgets: label and two anchorlayouts.
BoxLayout has a spacing parameter that is specified as "vertical".
So ... I don't see any spaces between the widgets inside the boxlayout.
enter image description here
There is kv:
<WellcomeScreen>:
wellcome_label: wellcome_user
BoxLayout:
orientation: 'vertical'
pos: self.parent.pos
size: self.parent.size
padding: [30, 30]
spacing: [10,10]
canvas.before:
Rectangle:
source: 'Data\game background.png'
pos: self.pos
size: self.size
ShadowLabel:
canvas.before:
Color:
rgba: .5,1,.7,1
Rectangle:
pos: self.pos
size: self.size
size_hint: (1, .6)
id: wellcome_user
font_size: self.height/16
text_size: self.width-10, None
markup: True
color: 'purple'
halign: "center"
AnchorLayout:
size_hint: (1,.1)
canvas.before:
Color:
rgba: 1,.5,0,1
Rectangle:
pos: self.pos
size: self.size
Button:
pos_hint: {"center_x":0.5,"center_y":0.5}
size_hint: (None,None)
size: (self.parent.height-5,self.parent.height-5)
background_normal: "Data\Button_sound.png"
AnchorLayout:
size_hint: (1,.3)
canvas.before:
Color:
rgba: .2,.7,.7,1
Rectangle:
pos: self.pos
size: self.size
Button:
canvas.before:
Rectangle:
source: "Data\Button_start.png"
pos: self.pos
size: self.size
pos_hint: {"center_x":0.5,"center_y":0.5}
size_hint: (None, None)
size: (self.parent.height/4*3, self.parent.height/4*3)
background_color: (1,1,1,0)
font_size: self.height/4
text_size: self.width, None
text: "START"
color: "yellow"
bold: True
halign: 'center'
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'login'

According to the documentation, the spacing is a number, not a list of numbers. Try changing:
spacing: [10,10]
to:
spacing: 10

Related

Is it possible to add padding and margin to each widgets in kivy?

I want to apply margin and padding to each widgets is that possible in kivy?
Here is the exact image I need; I want to apply padding and margin to each button:
![1][1]
I applied one method in kivy, put the widget in 2 layouts but the problem is without adding margin, padding there is space between the widgets. How can we set the 2 layout size according to widget size? Here is my code:
kv file
<Demoproject>:
Screen:
name:"screen_2917"
canvas.before:
Color:
rgba:(1.0,1.0,1.0,1.0)
Rectangle:
pos:self.pos
size:self.size
#source:""
BoxLayout:
orientation:"vertical"
BoxLayout:
orientation:"vertical"
padding:dp(0),dp(0),dp(0),dp(0)
color:(1,0,0,1)
canvas:
Color:
rgb: [.10, .10, .10]
Rectangle:
pos: self.pos
size: self.size
GridLayout:
cols:1
padding:dp(0),dp(0),dp(0),dp(0)
canvas:
Color:
rgb: [.6, .6, .6]
Rectangle:
pos: self.pos
size: self.size
Button:
text:"close"
size:(200,100)
size_hint:(None,None)
BoxLayout:
orientation:"vertical"
padding:dp(0),dp(0),dp(0),dp(0)
color:(1,0,0,1)
canvas:
Color:
rgb: [.10, .10, .10]
Rectangle:
pos: self.pos
size: self.size
GridLayout:
cols:1
padding:dp(0),dp(0),dp(0),dp(0)
canvas:
Color:
rgb: [.6, .6, .6]
Rectangle:
pos:self.pos
size:self.size
Button:
text:"close"
size:(200,100)
size_hint:(None,None)
I think you can simplify your kv file and just use padding and spacing. Like this:
<Demoproject>:
Screen:
name:"screen_2917"
canvas.before:
Color:
rgba:(1.0,1.0,1.0,1.0)
Rectangle:
pos:self.pos
size:self.size
#source:""
BoxLayout:
orientation:"vertical"
size_hint: None, None
size: self.minimum_size
pos_hint: {'top': 1}
padding: 5 # between Boxlayout edges and Buttons
spacing: 5 # between Buttons
Button:
text:"close"
size:(200,100)
size_hint:(None,None)
Button:
text:"close"
size:(200,100)
size_hint:(None,None)
Padding can only be applied by a few of the Layout classes. So if you want different padding for each Button, you must use separate Layouts. Here is another version of your kv that uses AnchorLayout to apply different padding for each Button:
<Demoproject>:
Screen:
name:"screen_2917"
canvas.before:
Color:
rgba:(1.0,1.0,1.0,1.0)
Rectangle:
pos:self.pos
size:self.size
#source:""
BoxLayout:
orientation:"vertical"
size_hint: None, None
size: self.minimum_size
pos_hint: {'top': 1}
canvas.before:
Color:
rgba:(0,1,0,1)
Rectangle:
pos:self.pos
size:self.size
AnchorLayout:
size_hint: None, None
size: butt1.width + self.padding[0] + self.padding[2], butt1.height + self.padding[1] + self.padding[3]
padding: 20
canvas.before:
Color:
rgba: 1,0,0,1
Rectangle:
pos: self.pos
size: self.size
Button:
id: butt1
text:"close"
size:(200,100)
size_hint:(None,None)
AnchorLayout:
size_hint: None, None
size: butt2.width + self.padding[0] + self.padding[2], butt2.height + self.padding[1] + self.padding[3]
padding: 5, 10, 15, 20
canvas.before:
Color:
rgba: 0,0,1,1
Rectangle:
pos: self.pos
size: self.size
Button:
id: butt2
text:"close"
size:(200,100)
size_hint:(None,None)
The canvas instructions are just to more easily visualize what is happening. The AnchorLayout sizes are calculated to just fit the Button with the specified padding.

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

Issues with refreshing kivy widgets

I'm having issues with refreshing a BoxLayout of widgets by removing them and then rebuilding the widgets based on the list 'Groups'. When on the EditDeviceGroups screen, the 'create' button should add an element to the list and forward the user to the GroupTemplateScreen, which it does.
The issue occurs when the user uses the back button to return to the EditDeviceGroups screen. At that point, I thought the on_enter method would refresh the widgets to include the new element, but the list shows no changes.
I assume it's some sort of issue with classes and instances, but I cant quite see around this one as this is my first real attempt with Kivy.
soundclout.py
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, StringProperty
from kivy.uix.listview import ListItemButton
from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button,Label
from kivy.graphics import Color,Rectangle,InstructionGroup
class GroupTemplateScreen(Screen):
def remove(self):
pass
class HomeScreen(Screen):
skipBuild = 'build_timeline_screen_6'
#skips build option if already timeline is already built
def skip_build_screen(self,value):
if value is 1:
print('HomeScreen.skip_build_screen')
self.skipBuild = 'edit_timeline_screen_7'
class EditDeviceGroupsScreen(Screen):
#Groups = [GroupNo,null]
Groups = [[1,10],[2,20]]
def on_enter(self):
self.ids.glayout2.clear_widgets()
for i in xrange(0,len(EditDeviceGroupsScreen().Groups)):
##THISPRINT##
print(str(EditDeviceGroupsScreen().Groups[i][0]))
addedGroup = BoxLayout(size_hint_y=None,height='120sp',orientation='horizontal')
addedButton=Button(text="Group " + str(EditDeviceGroupsScreen().Groups[i][0]) + " Settings",font_size=25)
addedGroup.add_widget(addedButton)
self.ids.glayout2.add_widget(addedGroup)
#Removes all widget on leaving to prevent the creation of duplicate widgets
def nav_to_group(self):
self.manager.current = 'edit_group_behaviour_screen_9'
def create_group(self):
base = 1
for i in xrange(0,len(EditDeviceGroupsScreen().Groups)):
if base < EditDeviceGroupsScreen().Groups[i][0]:
base = EditDeviceGroupsScreen().Groups[i][0]
EditDeviceGroupsScreen().Groups.append([base+1,(base+1)*10])
#manages screens
class Manager(ScreenManager):
home_screen = ObjectProperty()
edit_device_groups_screen = ObjectProperty()
group_template_screen= ObjectProperty()
def update(self):
self.connected_device_list._trigger_reset_populate()
self.current_screen.update()
class SoundCloutApp(App):
def build(self):
return Manager(transition=WipeTransition())
if __name__=='__main__':
SoundCloutApp().run()
soundclout.kv
#: kivy 1.10.0
#: import hex kivy.utils.get_color_from_hex
#: import main soundclout
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
#: import ListItemButton kivy.uix.listview.ListItemButton
#: import ScrollView kivy.uix.scrollview
<GroupTemplateScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 20
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
orientation: "horizontal"
height: 50
spacing: 10
padding: 0
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_x: None
size_hint_y: None
height: 50
width:100
text: 'Back'
on_release: root.manager.current = 'edit_device_groups_screen_5'
Button:
size_hint_x: None
size_hint_y: None
height: 50
width:100
text: 'Remove'
#have to change first argument, for now assume switch is on
on_press: root.remove()
on_release:root.manager.current = 'edit_device_groups_screen_5'
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#ffffff')
Rectangle:
pos: self.pos
size: self.size
#Devices connected
BoxLayout:
orientation: "horizontal"
canvas:
Color:
rgba: hex('#98a6b3')
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Name:'
font_size: 24
#TODO
Label:
text: 'Group 1'
font_size: 24
#Devices connected
BoxLayout:
orientation: "horizontal"
canvas:
Color:
rgba: hex('#98a6b3')
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Devices:'
font_size: 24
#TODO
Label:
text: '1,2,3,4'
font_size: 24
<HomeScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 50
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
text: "Start"
font_size: 20
Button:
text: "Device Tester"
font_size: 20
Button:
text: "Connect Devices"
font_size: 20
Button:
text: "Edit Device Groups"
font_size: 20
on_press: root.manager.current = 'edit_device_groups_screen_5'
Button:
text: "Edit Group Behavior"
font_size: 20
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Label:
text: "Connected Devices"
font_size: 30
<EditDeviceGroupsScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
#ToolBar
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 20
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_x: None
size_hint_y: None
height: 50
size: self.size
text: 'create group'
on_press: main.EditDeviceGroupsScreen().create_group()
on_release: root.manager.current = 'group_template_screen_11'
#Groups holder
BoxLayout:
orientation: "vertical"
spacing: 5
padding: 5
canvas:
Color:
rgba: hex('#ffffff')
Rectangle:
pos: self.pos
size: self.size
#Adds Scrollability
ScrollView:
do_scroll_x:False
do_scroll_Y:True
BoxLayout:
id: glayout2
orientation: 'vertical'
spacing: 5
size_hint_y: None
height: self.minimum_height
<Manager>:
id: screen_manager
home_screen: home_screen
edit_device_groups_screen: edit_device_groups_screen
group_template_screen: group_template_screen
HomeScreen:
id: home_screen
name: 'homescreen_1'
manager: screen_manager
EditDeviceGroupsScreen:
id: edit_device_groups_screen
name: 'edit_device_groups_screen_5'
manager: screen_manager
GroupTemplateScreen:
id: group_template_screen
name: 'group_template_screen_11'
manager: screen_manager
#Problem#
The EditDeviceGroups screen is not refreshed with the newly added widgets because when the Back button is pressed, another instance of EditDeviceGroupScreen was instantiated.
#Solution#
With the following changes, when the user clicked the back button to return to the EditDeviceGroups screen, the on_enter method refreshed the widgets to include the new element added. Please refer to the example and output for details.
##soundclout.kv##
Deleted #:import main soundclout
Replaced main.EditDeviceGroupsScreen().create_group() with root.create_group()
##soundclout.py##
Replace all occurrence of EditDeviceGroupsScreen(). with self.
#Example#
##main.py##
from kivy.app import App
from kivy.properties import ObjectProperty, ListProperty, StringProperty
from kivy.uix.listview import ListItemButton
from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.button import Button, Label
from kivy.graphics import Color, Rectangle, InstructionGroup
class GroupTemplateScreen(Screen):
def remove(self):
pass
class HomeScreen(Screen):
skipBuild = 'build_timeline_screen_6'
# skips build option if already timeline is already built
def skip_build_screen(self, value):
if value is 1:
print('HomeScreen.skip_build_screen')
self.skipBuild = 'edit_timeline_screen_7'
class EditDeviceGroupsScreen(Screen):
# Groups = [GroupNo, null]
Groups = [[1, 10], [2, 20]]
def on_enter(self):
print("EditDeviceGroupsScreen.on_enter:")
self.ids.glayout2.clear_widgets()
for i in range(0, len(self.Groups)):
##THISPRINT##
print(str(self.Groups[i][0]))
addedGroup = BoxLayout(size_hint_y=None, height='120sp', orientation='horizontal')
addedButton = Button(text="Group " + str(self.Groups[i][0]) + " Settings", font_size=25)
addedGroup.add_widget(addedButton)
self.ids.glayout2.add_widget(addedGroup)
# Removes all widget on leaving to prevent the creation of duplicate widgets
def nav_to_group(self):
self.manager.current = 'edit_group_behaviour_screen_9'
def create_group(self):
base = 1
for i in range(0, len(self.Groups)):
if base < self.Groups[i][0]:
base = self.Groups[i][0]
self.Groups.append([base+1, (base+1)*10])
# manages screens
class Manager(ScreenManager):
home_screen = ObjectProperty()
edit_device_groups_screen = ObjectProperty()
group_template_screen= ObjectProperty()
def update(self):
self.connected_device_list._trigger_reset_populate()
self.current_screen.update()
class SoundCloutApp(App):
def build(self):
return Manager(transition=WipeTransition())
if __name__ == '__main__':
SoundCloutApp().run()
##soundclout.kv##
#:kivy 1.10.0
#:import hex kivy.utils.get_color_from_hex
#:import ListAdapter kivy.adapters.listadapter.ListAdapter
#:import ListItemButton kivy.uix.listview.ListItemButton
#:import ScrollView kivy.uix.scrollview
<GroupTemplateScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 20
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
orientation: "horizontal"
height: 50
spacing: 10
padding: 0
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_x: None
size_hint_y: None
height: 50
width:100
text: 'Back'
on_release: root.manager.current = 'edit_device_groups_screen_5'
Button:
size_hint_x: None
size_hint_y: None
height: 50
width:100
text: 'Remove'
#have to change first argument, for now assume switch is on
on_press: root.remove()
on_release:root.manager.current = 'edit_device_groups_screen_5'
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#ffffff')
Rectangle:
pos: self.pos
size: self.size
#Devices connected
BoxLayout:
orientation: "horizontal"
canvas:
Color:
rgba: hex('#98a6b3')
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Name:'
font_size: 24
#TODO
Label:
text: 'Group 1'
font_size: 24
#Devices connected
BoxLayout:
orientation: "horizontal"
canvas:
Color:
rgba: hex('#98a6b3')
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Devices:'
font_size: 24
#TODO
Label:
text: '1,2,3,4'
font_size: 24
<HomeScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 50
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
text: "Start"
font_size: 20
Button:
text: "Device Tester"
font_size: 20
Button:
text: "Connect Devices"
font_size: 20
Button:
text: "Edit Device Groups"
font_size: 20
on_press: root.manager.current = 'edit_device_groups_screen_5'
Button:
text: "Edit Group Behavior"
font_size: 20
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Label:
text: "Connected Devices"
font_size: 30
<EditDeviceGroupsScreen>:
rows: 2
spacing: 10
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
#ToolBar
BoxLayout:
size_hint_y: None
height: 50
spacing: 10
pos: root.x, (root.height-50)
# Make the background for the toolbar blue
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
on_press: root.manager.current = 'homescreen_1'
background_normal: 'icons/home.png'
size_hint_x: None
width:50
BoxLayout:
size_hint_y: None
height: 500
spacing: 50
padding: 20
pos: root.x, (root.height-560)
BoxLayout:
orientation: "vertical"
spacing: 10
padding: 10
canvas:
Color:
rgba: hex('#0099cc')
Rectangle:
pos: self.pos
size: self.size
Button:
size_hint_x: None
size_hint_y: None
height: 50
size: self.size
text: 'create group'
on_press: root.create_group()
on_release: root.manager.current = 'group_template_screen_11'
#Groups holder
BoxLayout:
orientation: "vertical"
spacing: 5
padding: 5
canvas:
Color:
rgba: hex('#ffffff')
Rectangle:
pos: self.pos
size: self.size
#Adds Scrollability
ScrollView:
do_scroll_x:False
do_scroll_Y:True
BoxLayout:
id: glayout2
orientation: 'vertical'
spacing: 5
size_hint_y: None
height: self.minimum_height
<Manager>:
id: screen_manager
home_screen: home_screen
edit_device_groups_screen: edit_device_groups_screen
group_template_screen: group_template_screen
HomeScreen:
id: home_screen
name: 'homescreen_1'
manager: screen_manager
EditDeviceGroupsScreen:
id: edit_device_groups_screen
name: 'edit_device_groups_screen_5'
manager: screen_manager
GroupTemplateScreen:
id: group_template_screen
name: 'group_template_screen_11'
manager: screen_manager
#Output#

Categories

Resources