Very new to Kivy and trying to dynamically add widgets, but despite all the examples I have followed, I can't get mine to work.
My .kv file is...
ScreenManager:
MainScreen:
LoginScreen:
<MainScreen>:
name: 'MainScreen'
id: ms
BoxLayout:
id: rc_display
orientation: "vertical"
padding: 10
spacing: 10
Label:
id: ms_label1
text: 'Oh Hell Yeah'
<LoginScreen>:
name: 'LoginScreen'
id: ls
Button:
on_release: app.root.current
text: 'Click to Login'
font_size: 20
and my python code is...
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
import requests
class MainScreen(Screen):
def on_pre_enter(self, *args):
show_view = self.ids.rc_display # error here
show_view.clear_widgets()
buttons = BoxLayout(orientation = 'vertical')
pr = requests.get('http://127.0.0.1:5000/stageplanning/api/v1.0/shows')
for show in pr.json():
buttons.add_widget(Button(text = show['show_title']))
show_view.add_widgets(buttons)
class LoginScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class StagePlanningApp(App):
def build(self):
sm = Builder.load_file('StagePlanning.kv')
# sm.add_widget(MainScreen())
# sm.add_widget(LoginScreen())
return sm
sp_app = StagePlanningApp()
sp_app.run()
When I run the above I get the following error...
File "*pathtoFile*/StagePlanning.py", line 12, in on_pre_enter
show_view = self.ids.rc_display
File "kivy\properties.pyx", line 839, in kivy.properties.ObservableDict.__getattr__ (kivy\properties.c:12654)
AttributeError: 'super' object has no attribute '__getattr__'
If I add the widgets directly to the Screen object they display, but are on top of each other. Its only when I try and reference the id I get an error.
I have even printed to the console the list of ids, and they are there as expected.
The problem is caused because the on_pre_enter
event is done before adding the BoxLayout
so it does not exist, a possible solution is to use Clock
:
class MainScreen(Screen):
def __init__(self, *args, **kwargs):
Screen.__init__(self, *args, **kwargs)
Clock.schedule_once(self.finished_init)
def finished_init(self, *args):
show_view = self.ids.rc_display # error here
show_view.clear_widgets()
buttons = BoxLayout(orientation = 'vertical')
pr = requests.get('http://127.0.0.1:5000/stageplanning/api/v1.0/shows')
for show in pr.json():
buttons.add_widget(Button(text = show['show_title']))
show_view.add_widget(buttons)
Another option is to define it in the BoxLayout constructor:
*.py
class MainBoxLayout(BoxLayout):
def __init__(self, *args, **kwargs):
BoxLayout.__init__(self, *args, **kwargs)
self.clear_widgets()
buttons = BoxLayout(orientation = 'vertical')
pr = requests.get('http://127.0.0.1:5000/stageplanning/api/v1.0/shows')
for show in pr.json():
buttons.add_widget(Button(text = show['show_title']))
self.add_widget(buttons)
*.kv
ScreenManager:
MainScreen:
LoginScreen:
<MainScreen>:
name: 'MainScreen'
id: ms
MainBoxLayout:
id: rc_display
orientation: "vertical"
padding: 10
spacing: 10
<LoginScreen>:
name: 'LoginScreen'
id: ls
Button:
on_release: app.root.current
text: 'Click to Login'
font_size: 20