无法在 Kivy 中引用小部件 ID

Can't reference widget id in Kivy

对 Kivy 很陌生,正在尝试动态添加小部件,但是尽管我已经遵循了所有示例,但我还是无法正常工作。

我的 .kv 文件是...

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

我的 python 代码是...

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

当我 运行 以上时,我得到以下错误...

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

如果我将小部件直接添加到它们显示的 Screen 对象,但会彼此叠加。只有当我尝试引用 id 时才会出现错误。

我什至向控制台打印了 ID 列表,它们如预期的那样存在。

问题是因为 on_pre_enter 事件在添加 BoxLayout 之前完成所以它不存在,一个可能的解决方案是使用 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) 

另一种选择是在 BoxLayout 构造函数中定义它:

*.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