首页 > 解决方案 > 如何在 Kivy 中为我的根屏幕调用 on_pre_enter 函数?

问题描述

好的,目前我正在编写一个程序。它有多个通过 ScreenManager 控制的屏幕。根屏幕(加载程序时显示的屏幕)有一个标签,其文本根据外部文件的上下文而有所不同。最初,我打算使用这样的东西:

if __name__ == "__main__":
    with open(*file*) as f:
        data = eval(f.read())
    App.run()

并且,在所述根屏幕内部:

def on_pre_enter(self):
    if data == *something*:
        self.ids.*widget_id*.text = *something else*

它适用于除根屏幕以外的任何其他屏幕。我做了一些研究并了解到由于 event_dispatch 的工作方式,给定的函数(以及 on_enter)在根屏幕上不起作用。那么,有什么办法可以解决它,或者我能做些什么吗?

编辑:最小可重现示例。

main.py

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.label import Label

class Manager(ScreenManager):
    pass

class WindowOne(Screen):
    def on_pre_enter(self):
        self.ids.label_one.text = data

class WindowTwo(Screen):
    def on_pre_enter(self):
        self.ids.label_two.text = data

class TestApp(App):
    def build(self):
        return design

data = ''
if __name__ == "__main__":
    with open('design.kv') as f:
        design = Builder.load_string(f.read())
    with open('data.txt') as f:
        data = eval(f.read())
    TestApp().run()

design.kv

Manager:
    WindowOne:
    WindowTwo:

<WindowOne>:
    name: "one"
    Label:
        pos_hint: {"x": 0.15, "y": 0.15}
        id: label_one
        font_size: 40
        text: "This Is Window One"
    Button:
        size_hint: (0.2, 0.2)
        on_release:
            app.root.current = 'two'

<WindowTwo>:
    name: "two"
    Label:
        pos_hint: {"x": 0.15, "y": 0.15}
        id: label_two
        font_size: 40
    Button:
        size_hint: (0.2, 0.2)
        on_release:
            app.root.current = 'one'

如果您将 WindowOne 的 on_pre_enter 更改为 on_pre_leave,代码就可以正常工作,但会返回

AttributeError: 'super' object has no attribute '__getattr__'

除此以外。

标签: pythonkivy

解决方案


您的on_pre_enter()方法正在按预期调用。问题是您ids在该方法中引用字典,并且ids尚未设置(导致您看到的错误)。因此,您需要延迟on_pre_enter调用直到ids定义。一种方法是创建一个DummyScreen作为您的初始Screen,然后使用Clock.schedule_once()切换到您原来的根Screen。为此,定义DummyScreen为:

class DummyScreen(Screen):
    def on_enter(self):
        Clock.schedule_once(self.switch_screen)

    def switch_screen(self, dt):
        self.manager.transition = NoTransition()
        self.manager.current = "one"
        self.manager.transition = SlideTransition()

在您的kv文件中,添加DummyScreen

Manager:
    DummyScreen:
    WindowOne:
    WindowTwo:

推荐阅读