【问题标题】:Kivy references across screens跨屏幕的 Kivy 引用
【发布时间】:2016-03-06 23:09:51
【问题描述】:

我想从其他根小部件访问根小部件 ID,但我似乎无法完全掌握在 Kivy 中引用的工作原理,并且使用具有不同屏幕的 ScreenManager 对我来说更加困难。

我想实现以下目标:

编辑:单个文件版本

(这段代码假设你要构建一个复杂的应用程序,所以我不想在启动时加载所有代码。因此在切换屏幕时加载kv_strings,而不是放入ScreenManager的kv代码中。代码基于 Kivy Showcase。)

代码 main.py,编辑 2:工作代码(查看答案原因)

#!/usr/bin/kivy
# -*- coding: utf-8 -*-

from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.clock import Clock
from kivy.properties import StringProperty, ObjectProperty


kv_foo = '''
<FooScreen>:
    id: fooscreen_id

    BoxLayout:
        id: content
        orientation: 'vertical'
        spacing: '20dp'
        padding: '8dp'
        size_hint: (1, 1)

BoxLayout:
    orientation: 'vertical'

    Label:
        id: important_text
        size_hint_y: 0.3
        text: app.imp_text

    Button:
        id: magic_change
        size_hint_y: 0.3
        text: "Change text above to text below (after screen switch)"
        on_press: app.change_text()

    ScreenManager:
        id: sm
        on_current_screen:
            idx = app.screen_names.index(args[1].name)
'''


class FooScreen(Screen):
    # 'content' refers to the id of the BoxLayout in FooScreen in foo.kv
    def add_widget(self, *args):
        if 'content' in self.ids:
            return self.ids.content.add_widget(*args)
        return super(FooScreen, self).add_widget(*args)


class FooApp(App):
    imp_text = StringProperty("Should change to text from id: magic_text")
    screen_magic = ObjectProperty()
    magic_layout = ObjectProperty()

    def build(self):
        self.title = 'Foo'
        self.root = root = Builder.load_string(kv_foo)

        # Trying stuff with References
        self.sm = self.root.ids.sm  # ScreenManager

        # Setting up screens for screen manager
        self.screens = {}
        self.available_screens = [kv_mainmenu, kv_magic]
        self.screen_names = ['MainMenu', 'Magic']
        self.go_screen(0)

    # Go to other screen
    def go_screen(self, idx):
        print("Change MainScreen to: {}".format(idx))
        self.index = idx
        # Go to not main menu
        if idx == 0:
            self.root.ids.sm.switch_to(self.load_screen(idx), direction='right')
        # Go to main menu
        else:
            self.root.ids.sm.switch_to(self.load_screen(idx), direction='left')

    # Load kv files
    def load_screen(self, index):
        if index in self.screens:
            return self.screens[index]
        screen = Builder.load_string(self.available_screens[index])
        self.screens[index] = screen
        # if index refers to 'Magic' (kv_magic), create reference
        if index == 1:
            Clock.schedule_once(lambda dt: self.create_reference())
        return screen

    # Trying to get id's
    def create_reference(self):
        print("\nrefs:")
        # Get screen from ScreenManager
        self.screen_magic = self.sm.get_screen(self.screen_names[1])
        # screen.boxlayout.magiclayout
        self.magic_layout = self.screen_magic.children[0].children[0]

    def change_text(self):
        # Get text from id: magic_text
        if self.magic_layout:
            self.imp_text = self.magic_layout.ids['magic_text'].text


kv_mainmenu = '''
FooScreen:
    id: mainm
    name: 'MainMenu'

    Button:
        text: 'Magic'
        on_release: app.go_screen(1)
'''

kv_magic = '''
<MagicLayout>
    id: magic_layout
    orientation: 'vertical'

    Label:
        id: magic_text
        text: root.m_text

FooScreen:
    id: magic_screen
    name: 'Magic'

    MagicLayout:
        id: testmagic
'''


class MagicLayout(BoxLayout):
    m_text = StringProperty("Reference between widgets test")


if __name__ == '__main__':
    FooApp().run()

问题

如何设置正确的引用以使“更改上面的文本...”按钮可以检索 magic_text.text(“小部件之间的引用测试”)并将 self.imp_text 更改为 magic_text.text

【问题讨论】:

  • 你的代码乱七八糟,难怪你对这么简单的任务有问题。将屏幕添加到 kv 中的屏幕管理器,并使用 id 引用它们。
  • @jiligeza,代码怎么乱了?此示例假设您要制作一个大程序,因此将所有 Screens 都放在 .kv 中的 ScreenManager 中,这违背了不必在您的应用中加载所有代码的目的。
  • 我不明白为什么必须拆分kv。它被设计为独立模块化。无论如何,如果您想在全球范围内引用小部件,您可以看看我想出了什么:stackoverflow.com/questions/35792621/…
  • @kilbee,对于这个例子,确实没有必要拆分,但是当你制作一个更大的应用程序时,你不希望所有代码都在 1 个 .py 文件和 1 个 .kv 文件中,也不需要您的应用程序中的所有小部件都在启动时呈现(应用程序启动的 10 秒有点长)。在这里,我尝试设置这样一个更大的应用程序的基本框架,同时仍然可以通过引用访问所有小部件(请参阅答案)。

标签: python kivy


【解决方案1】:

我找到了一种在不使用全局变量的情况下引用未在应用启动时加载的 Kivy 小部件的方法。感谢@inclement ScreenManager.get_screen()

我必须添加以下代码:

class FooApp(App):
    screen_magic = ObjectProperty()
    magic_layout = ObjectProperty()

    ...

    # Trying to get id's
    def create_reference(self):
        print("\nrefs:")
        # Get screen from ScreenManager
        self.screen_magic = self.sm.get_screen(self.screen_names[1])
        # screen.boxlayout.magiclayout
        self.magic_layout = self.screen_magic.children[0].children[0]

    def change_text(self):
        # Get text from id: magic_text
        if self.magic_layout:
            self.imp_text = self.magic_layout.ids['magic_text'].text

self.screen_magic 分配了我需要的屏幕 (&lt;FooScreen&gt;),self.magic_layout 分配了我需要的小部件 (&lt;MagicLayout&gt;)。然后我可以使用来自&lt;MagicLayout&gt; 的ID 来访问标签magic_text 的文本。

(完整代码见更新问题)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多