Border with Kivy/KivyMD - python

I am looking to add a border to the main screen of my application but I'm not sure how.
I tried to take some tips from this question:
Kivy-how can i make my canvas height smaller than the parent height
But I can't seem to figure it out.
The issue is that I am also using a KivyMD's Navigation Drawer, I would like the border be separate from the top bar, enclosing everything below the bar. Please let me know if I'm not being clear.
Here is some sample code that replicates my setup.
Perhaps I could add some random rectangles to act as a border?
EDIT:
Okay almost there, I got the 'border' but I now need the size_hint added in the AnchorLayout to ignore the top portion of the screen where the menu bar is. Here is the updated code.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.app import MDApp
kv = '''
#:import hex kivy.utils.get_color_from_hex
NavigationLayout:
canvas.before:
Color:
rgb: hex('#C0C0C0')
Rectangle:
size: self.size
pos: self.pos
ScreenManager:
id: screen_manager
Screen:
name: "home_screen"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Name of the App!'
elevation: 10
Widget:
FloatLayout:
orientation: 'vertical'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgb: hex('#F5F5F5')
Rectangle:
size: self.size
pos: self.pos
size_hint: .95, .95
MDLabel:
text: "Some More Text"
halign: "center"
color: 0,0,0,1
pos_hint: {"center_x": .5, "center_y": .75}
size_hint: .7, .1
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
source: "image.jpg"
MDLabel:
text: "Text here"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]
'''
class ContentNavigationDrawer(BoxLayout):
pass
class MyApp(MDApp):
def build(self):
return Builder.load_string(kv)
MyApp().run()

I think you will get what you want if you indent the FloatLayout so that it is in the BoxLayout. Like this:
#:import hex kivy.utils.get_color_from_hex
NavigationLayout:
canvas.before:
Color:
rgb: hex('#C0C0C0')
Rectangle:
size: self.size
pos: self.pos
ScreenManager:
id: screen_manager
Screen:
name: "home_screen"
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Name of the App!'
elevation: 10
# Widget: # not needed
FloatLayout:
orientation: 'vertical'
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
Widget:
canvas.before:
Color:
rgb: hex('#F5F5F5')
Rectangle:
size: self.size
pos: self.pos
size_hint: .95, .95
MDLabel:
text: "Some More Text"
halign: "center"
color: 0,0,0,1
pos_hint: {"center_x": .5, "center_y": .75}
size_hint: .7, .1
MDNavigationDrawer:
id: nav_drawer
ContentNavigationDrawer:
orientation: "vertical"
padding: "8dp"
spacing: "8dp"
AnchorLayout:
anchor_x: "left"
size_hint_y: None
height: avatar.height
Image:
id: avatar
# source: "image.jpg"
source: 'tester.png'
MDLabel:
text: "Text here"
font_style: "Button"
size_hint_y: None
height: self.texture_size[1]

Related

MDCard covers its content, problem with kivyMD inheritance

I created this widget in a .kv file that inherits from MDCard:
<ElementCard#MDCard>:
radius: '10dp'
spacing: '10dp'
padding: '10dp'
image: ''
text: ''
sub_text: ''
orientation: 'vertical'
md_bg_color: 0.87, 0, 0.49
ripple_behavior: True # effect
on_release:
app.root.transition = RiseInTransition()
Image:
source: root.image
halign: 'center'
MDBoxLayout:
orientation: 'vertical'
md_bg_color: 'green'
MDLabel:
text: root.text
color: 'white'
halign: 'center'
MDLabel:
text: root.sub_text
halign: 'center'
and I use it:
<ui>:
...
ElementCard:
text: 'IA'
sub_text: 'Inteligencia artificial'
image: 'images/image1.jpg'
on_release:
root.current = 'screen1'
...
The problem is that the ElementCard widget doesn't show the content:
ElementCard is the purple block and it covers all its content.
When I set the transparency in 0.5 the program looks like this:
50% transparency
The versions are these:
Kivy==2.1.0
kivymd==1.1.1
I've tried rebooting the machine, restarting the virtual environment, reinstalling kivy and kivymd but nothing works.
I think the problem is the inheritance because when I use directly the MDCard like in this code:
MDCard:
radius: '10dp'
spacing: '10dp'
padding: '10dp'
orientation: 'vertical'
md_bg_color: 0.87, 0, 0.49,0.6
ripple_behavior: True # effect
on_release:
app.root.transition = RiseInTransition()
Image:
source: 'images/image1.jpg'
halign: 'center'
MDBoxLayout:
orientation: 'vertical'
md_bg_color: 'green'
MDLabel:
text: 'IA'.
color: 'white'
halign: 'center'
MDLabel:
text: 'Inteligencia artificial'
halign: 'center'
With the last code the program works fine:
MDCard works normally.
main.py full code:
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager
from kivymd.app import MDApp
class Ui(ScreenManager):
pass
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style ='Dark'
self.theme_cls.primary_palette ='Teal'
Builder.load_file("design.kv")
return Ui()
def change_style(self, checked, value):
if value:
self.theme_cls.theme_style ='Dark'
pass
else:
self.theme_cls.theme_style ='Light'
pass
if __name__ == "__main__":
MainApp().run()
design.kv full code:
#:kivy 2.1.0
#:import RiseInTransition kivy.uix.screenmanager.RiseInTransition
#:import SlideTransition kivy.uix.screenmanager.SlideTransition
<CustomizeScreen#MDBoxLayout>:
orientation: 'vertical'
text: ''
padding: 100
MDLabel:
text: root.text
halign: 'center'
pos_hint:{'center_x': 0.5}
MDFillRoundFlatButton:
text: 'REGRESAR'
pos_hint: {'center_x': 0.5}
on_release:
app.root.current = 'screen_principal'
app.root.transition = SlideTransition(direction = 'left')
<ElementCard#MDCard>:
radius: '10dp'
spacing: '10dp'
padding: '10dp'
image: ''
text: ''
sub_text: ''
orientation: 'vertical'
md_bg_color: 0.87, 0, 0.49
ripple_behavior: True # effect
on_release:
app.root.transition = RiseInTransition()
Image:
source: root.image
halign: 'center'
MDBoxLayout:
orientation: 'vertical'
md_bg_color: 'green'
MDLabel:
text: root.text
color: 'white'
halign: 'center'
MDLabel:
text: root.sub_text
halign: 'center'
<ui>:
MDScreen:
name: 'screen_principal'
md_bg_color: "black"
MDBoxLayout:
orientation: "vertical"
MDBoxLayout:
size_hint: 1, 0.2 # x=1 ocupa todo, y=0.2 ocupa 20%
orientation: "horizontal"
padding: '10dp'
MDCard:
radius: '10dp'
padding: '10dp'
line_color: 1,0,1,1
MDLabel:
text: 'APLICACIÓN DE TECNOLOGÍA'
halign: 'center'
pos_hint: {'center_y': 0.5}
MDSwitch:
pos_hint: {'center_y': 0.5}
on_active:
app.change_style(*args)
MDGridLayout:
cols: 3
size_hint: 0.8, 0.8 # x=1 ocupa todo, y=0.8 ocupa 80%
pos_hint: {'center_x': 0.5}
padding: ['10dp','10dp','10dp','10dp']
spacing: '10dp'
ElementCard:
text: 'IA'
sub_text: 'Inteligencia artificial'
image: 'images/image1.jpg'
on_release:
root.current = 'screen1'
I commented this problem in the github kivyMD project, they marked as a bug and give me a couple of options to implement, link to github
Edit:
Thanks for pointing out my mistake with my link.
This is the first option:
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.card import MDCard
KV = """
<ElementCard>
MDLabel:
text: "HELLO WORLD"
MDScreen:
ElementCard:
size_hint: 0.5, 0.8
pos_hint: {"center_x": .5, "center_y": .5}
md_bg_color: 0.87, 0, 0.49, 1
"""
class ElementCard(MDCard):
pass
class MainApp(MDApp):
def build(self):
return Builder.load_string(KV)
MainApp().run()
and the 2nd:
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.card import MDCard
KV = """
<ElementCard#MDCard>
MDLabel:
text: "HELLO WORLD"
MDScreen:
ElementCard:
size_hint: 0.5, 0.8
pos_hint: {"center_x": .5, "center_y": .5}
md_bg_color: 0.87, 0, 0.49, 1
"""
class MainApp(MDApp):
def build(self):
return Builder.load_string(KV)
MainApp().run()
I guess that the kivymd developers will repair this bug in the future.

KivyMD Text Field doesn't work, recieve attribute error when pressing clear button and MD Cards arent aligned properly

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

how to bring the box layout to the top in kivy?

I have written a .kv code which I expect to show the boxLayout on the top of the screen, but when I execute it no picture is set on the background and the boxLayout is created at the bottom.
How can I fix this so that the box layout is at the top and shows a picture in the background.
Note: The path of the picture is correct.
here is .kv code
<ScreenOne>:
id: main_win
orientation: "vertical"
spacing: 10
space_x: self.size[0]/3
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: "/home/kiran/Desktop/Kivy-Screen/bg-03.2.jpg"
BoxLayout:
size_hint_y: None
height: 50
canvas.before:
Color:
rgba: (0.06,0.75,0.7,0.8)
Rectangle:
size: self.size
pos: self.pos
Label:
text: "Lend A Hand"
bold: True
<Manager>:
id: screen_manager
screen_one: screen_one
#instances of each screen
ScreenOne:
id: screen_one
name: 'screen1'
manager: screen_manager

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