I have an problem with the Kivy library. I'm currently writing the front end for a ShoppinglistApp. I have an main menu, where you can select what you want to do (add List/ Shop) from where you can get to the Shop selection.
I tried this solution:
from kivy.app import App
from kivy.metrics import dp
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.stacklayout import StackLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
# the rest
class Produkt:
def __init__(self, name, amount, market):
self.name = name
self.amount = amount
self.market = market
eklist = []
for i in range(0, 100):
nn = "Banane" + str(i)
eklist.append(Produkt(nn, 0, "Baumarkt"))
# Define Screens
class FirstWindow(Screen):
pass
class SecondWindow(Screen):
pass
class ThirdWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
"""Anfang der Chose"""
class Box(BoxLayout):
pass
# Gvar is a class I created for the purpose of transporting variable(s). Especially the selected shop.
class Gvar:
def __init__(self, var1):
self.var1 = var1
def get(self):
return self.var1
gvar = Gvar("default")
# SetBox ist the Class for changing the variable through the shop selection menu.
class SetBox(BoxLayout):
def set(self, market):
gvar.var1 = market
print("Set")
print(gvar.var1)
class BLE(BoxLayout):
pass
# This is the Menus which makes Problems.
class SLE(StackLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
for p in eklist:
# In theory, this if request should always be triggered. In reality, I made the else Request to debug.
# for Text normally would appear p.name, but I changed it for debugging. Text shown(gvar.var1) is "default".
if p.market == str(gvar.get()):
b = Button(text=str(gvar.get()), size_hint=(None, None), color="blue", size=(dp(200), dp(100)),
on_press=lambda *args: self.test1(*args, str(p.name)))
b.prod = p
self.add_widget(b)
else:
b = Button(text=str(gvar.get()), size_hint=(None, None), color="green", size=(dp(200), dp(100)),
on_press=lambda *args: self.test1(*args, str(p.name)))
b.prod = p
self.add_widget(b)
market = None
# test 1 is a placeholder for a backend function
# Here I print the Produkt and gvar.var1, to debug. Here it get for gvar.var1 the in the GUI selected Value.
def test1(self, b, i):
print("Initialize test2, please wait...")
print(b.prod.name, b.prod.amount, b.prod.market, gvar.var1)
"""Ende der Chose"""
kv = Builder.load_file('einkaufsliste.kv')
class EinkaufsApp(App):
def build(self):
return kv
if __name__ == '__main__':
EinkaufsApp().run()
</code></pre> +
Here is the Kivy file:
WindowManager:
FirstWindow:
SecondWindow:
ThirdWindow:
<FirstWindow>:
name: "first"
Box:
orientation: "vertical"
size :root.width, root.height
Label:
text: "Hauptmenü"
size_hint: 1, .2
font_size: 32
Button:
text: "Einkaufen"
font_size: 32
background_normal: ' '
background_color: "#666e00"
on_release:
app.root.current = "third"
root.manager.transition.direction = "left"
Button:
text: "Einkaufsliste updaten"
font_size: 32
background_normal: ' '
background_color: "#660000"
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "second"
BLE:
id: BLE
orientation: "vertical"
Button:
text: "to first"
size_hint: 1, .1
font_size: 24
on_release:
app.root.current = "first"
root.manager.transition.direction = "right"
TextInput:
multiline: False
size_hint: 1, .1
SVE:
<ThirdWindow>:
name: "third"
SetBox:
orientation: "vertical"
size :root.width, root.height
id:SetBox
Box:
orientation: "horizontal"
size_hint: 1, .4
Button:
text: "to first"
size_hint: .2, 1
font_size: 24
on_release:
app.root.current = "first"
root.manager.transition.direction = "right"
Label:
text: "Markt auswählen"
size_hint: .8, 1
font_size: 32
Button:
text: "Supermarkt"
font_size: 32
background_normal: ' '
background_color: "#a1b2e3"
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
on_press: SetBox.set("Supermarkt")
Button:
text: "Drogerie"
font_size: 32
background_normal: ' '
background_color: "#c7bbc9"
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
on_press: SetBox.set("Drogerie")
Button:
text: "Baumarkt"
font_size: 32
background_normal: ' '
background_color: "#b4eeb4"
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
on_press: SetBox.set("Baumarkt")
Button:
text: "Elektrogerätefachhandel"
font_size: 32
background_normal: ' '
background_color: "#f4c2c2"
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
on_press: SetBox.set("Elektrogerätefachhandel")
<SVE@ScrollView>:
SLE:
id: Scrollwin
size_hint: 1, None
height: self.minimum_height
<SLE>:
# orientation: "rl-bt"
# spacing: "1dp", "1dp"
I think the problem is that kivy creates the whole GUI before I can change the variable.
Is there a way to reload the screen or do I have to make for each market/shop another screen?
It's possible to do what you want. You have to add the items to the corresponidng layout. I'll give you an example with a project I did some time ago:
class ExmapleApp(App):
def build(self):
#Create GridLayout where you will add and remove widgets
self.gridRooms = gridRooms = GridLayout(cols=10, padding=10, spacing=10,
row_force_default=True, row_default_height=50, size_hint_y=None)
gridRooms.bind(minimum_height=gridRooms.setter('height'))
# Generate 10 Rooms items
for i in range(10):
labl = NewLabel() #Instace of NewLabel
labl.num = str(i+1) #Number of room
labl.roomName = "Room "+str(labl.num) # Room name
labl.filename = '12916_sweet_trip_mm_kwik_mod_01.wav'
roomsList.append(labl) #This add the room to a list for further reference
gridRooms.add_widget(labl) #This add the rooms to a grid
Here's an image of how it looks so far:
Finally, you can add widgets to that GridLayout:
#Create the object you want to Add
labl = NewLabel() #Instace of NewLabel
labl.num = str(11) #Number of room
labl.roomName = "Room "+str(labl.num) # Room name
labl.filename = '12916_sweet_trip_mm_kwik_mod_01.wav'
roomsList.append(labl) #This add the room to a list for further reference
#This add the widgets 3 secs after the program starts
Clock.schedule_once(lambda x: gridRooms.add_widget(roomsList[10]), 3) #Add room 11
You can even have a callback to create a new widget everytime you press a button. To remove a widget just:
gridRooms.remove_widget(roomsList[10]) #Removes Room 11