简体   繁体   中英

Why am I getting a Kivy KeyError: with my code?

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'

Asthe 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

...

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"

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'))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM