Reputation: 151
I'm trying to create a simple login and for the next screen to show the current time, but I just don't understand why I keep getting this error.
*.py file
from kivy.app import App
from datetime import datetime
from datetime import timedelta
from kivy.clock import Clock
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class test(BoxLayout):
pass
class blank_page(Screen):
pass
class ScreenManagement(ScreenManager):
pass
kv = Builder.load_file("delete.kv")
class MyApp(App):
def build(self):
self.now = datetime.now()
Clock.schedule_interval(self.update_clock, 1)
self.my_label = Label(text= self.now.strftime('%H:%M:%S'))
return kv
def update_clock(self, *args):
self.now = self.now + timedelta(seconds = 1)
self.root.ids['my_label'].text = self.now.strftime('%H:%M:%S')
print(self.now.strftime('%H:%M:%S'))
MyApp().run()
*.kv file
#:kivy 1.0
#:import hex kivy.utils.get_color_from_hex
ScreenManagement:
test:
blank_page:
<test>:
BoxLayout:
orintation: 'vertical'
Label:
text: 'test_label'
<blank_page>:
BoxLayout:
orientation:'vertical'
Label:
id: my_label
Button:
text:'next'
on_release: app.root.current = "blank_page"
What I want to happen is to be able to login, click the button where it takes me to the second screen where it will show me the time. But i keep getting the following error:
File "kivy\_clock.pyx", line 384, in kivy._clock.CyClockBase._process_events
File "kivy\_clock.pyx", line 414, in kivy._clock.CyClockBase._process_events
File "kivy\_clock.pyx", line 412, in kivy._clock.CyClockBase._process_events
File "kivy\_clock.pyx", line 167, in kivy._clock.ClockEvent.tick
File "c:/Users/QQQ/Documents/University work/test.py", line 31, in update_clock
self.root.ids['my_label'].text = self.now.strftime('%H:%M:%S')
KeyError: 'my_label'
Upvotes: 2
Views: 1449
Reputation: 243897
As the docs points out:
Referencing Widgets
In a widget tree there is often a need to access/reference other widgets. The Kv Language provides a way to do this using id’s. Think of them as class level variables that can only be used in the Kv language. Consider the following:
<MyFirstWidget>: Button: id: f_but TextInput: text: f_but.state <MySecondWidget>: Button: id: s_but TextInput: text: s_but.state
An id is limited in scope to the rule it is declared in, so in the code above s_but can not be accessed outside the <MySecondWidget> rule.
...
emphasis mine
In other words, the id my_label is only accessible through blank_page. In this case, when root is a ScreenManager, we then set a name to blank_page so that it can be accessed.
You also have the following errors:
The children of ScreenManager must be Screen, in your case test is a BoxLayout so you must place it inside another Screen or delete it.
The names of the classes that are used in kv must be capitalized.
self.my_label created in the build method is different from the one created in the .kv so it is unnecessary.
Considering the above, the solution is:
from kivy.app import App
from datetime import datetime
from datetime import timedelta
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
class Test(BoxLayout):
pass
class Blank_Page(Screen):
pass
class ScreenManagement(ScreenManager):
pass
kv = Builder.load_file("delete.kv")
class MyApp(App):
def build(self):
self.now = datetime.now()
Clock.schedule_interval(self.update_clock, 1)
return kv
def update_clock(self, *args):
self.now = self.now + timedelta(seconds=1)
self.root.get_screen("blank_page").ids["my_label"].text = self.now.strftime(
"%H:%M:%S"
)
print(self.now.strftime("%H:%M:%S"))
if __name__ == "__main__":
MyApp().run()
#:kivy 1.0
#:import hex kivy.utils.get_color_from_hex
ScreenManagement:
Blank_Page:
name: "blank_page"
Screen:
name: "next_page"
Test:
<Test>:
BoxLayout:
orientation: 'vertical'
Label:
text: 'test_label'
<blank_page>:
BoxLayout:
orientation:'vertical'
Label:
id: my_label
Button:
text:'next'
on_release: app.root.current = "next_page"
Upvotes: 2
Reputation: 5405
This is because my_label
is not an id of your root, but blank_page
You can fix this by referencing to blank_page
instead.
I would do something like this.
Make blank_page
an object property of your root.
KV:
ScreenManagement:
bp: bp
test:
blank_page:
id: bp
<test>:
BoxLayout:
orintation: 'vertical'
Label:
text: 'test_label'
<blank_page>:
BoxLayout:
orientation:'vertical'
Label:
id: my_label
Button:
text:'next'
on_release: app.root.current = "blank_page"
Then you can access that property's ids.
Python:
class MyApp(App):
def build(self):
self.now = datetime.now()
Clock.schedule_interval(self.update_clock, 1)
self.my_label = Label(text= self.now.strftime('%H:%M:%S'))
return kv
def update_clock(self, *args):
self.now = self.now + timedelta(seconds = 1)
self.root.bp.ids['my_label'].text = self.now.strftime('%H:%M:%S')
print(self.now.strftime('%H:%M:%S'))
Upvotes: 0