Python Kivy:向屏幕动态添加小部件

Python Kivy: Dynamic addition of widgets to a screen

从 python 代码(动态)向屏幕添加小部件的好方法是什么?

我的目标是拥有两个 'main' 屏幕。第二个屏幕的内容取决于 select 在主屏幕上编辑的内容。为简单起见,可以将此内容视为可变数量的按钮(所有内容,如按钮数量、背景图像等都存储在数据库中并独立更新)。所以我想象的逻辑如下:当按下 MainScreen 按钮时,我转到数据库并通过键 'button N' 检索数据,并以自定义 Button/Label 小部件的形式在第二个屏幕上显示。如果需要,我还想返回主屏幕 select 另一个按钮。

假设我有两个在 KV 文件中定义了静态图形的屏幕:

<MainScreen>
    BoxLayout:
        orientation: "vertical"
        Label:
            text: "SELECT BUTTON"
        Button:
            on_press: root.show_buttons(self)
            text: "Button 1"
        Button:
            on_press: root.show_buttons(self)
            text: "Button 2"

<AnotherScreen>:
    BoxLayout:
        orientation: 'vertical'
        Label:
            text: "Select BUTTON"
        Button: 
            on_press: root.manager.current = 'Main'
            text: "BACK"

主屏幕是完全静态的。按下按钮时,我需要调用 AnotherScreen 并根据按下的按钮向其添加内容。 我尝试按如下方式进行(但失败了):

class MainScreen(Screen):
    def show_buttons(self, btn):
        if btn.text == 'Button 1':
            another_screen.add_widget(Label(text="Button 1 pressed"))
            sm.current = "Another"
            return sm

class AnotherScreen(Screen):
    pass

class CoolApp(App):
    def build(self): 
        global sm
        sm = ScreenManager()
        main_screen = MainScreen(name='Main')
        sm.add_widget(main_screen)
        global another_screen
        another_screen = AnotherScreen(name='Another')
        sm.add_widget(another_screen)
        return sm


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

在这种情况下,动态小部件 another_screen.add_widget(Label(text="Button pressed")) 被添加到根据定义只能有一个子项(已在 KV 中定义)的屏幕。我没有得到异常,但我同时呈现了两个不同的小部件,这同样糟糕。

我想我需要将动态小部件添加到 BoxLayout 中,因为它是该屏幕的根小部件。但是,我不知道是否可以从不同的 class 引用小部件,如果可以,是否合适?

谢谢!

一种方法是使用 ID。

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

class MainScreen(Screen):
    first_btn_press = True
    def show_buttons(self, btn):
        if btn.text == 'Button 1':
            print(self.manager.ids)
            if self.first_btn_press:
                self.manager.ids.another.ids.box.add_widget(Label(text="Button 1 pressed"))
                self.first_btn_press = False
            self.manager.current = "another"

class AnotherScreen(Screen):
    pass

kv_str = Builder.load_string("""
ScreenManager:
    MainScreen:
        id: main
    AnotherScreen:
        id: another


<MainScreen>
    name: "main"
    BoxLayout:
        orientation: "vertical"
        Label:
            text: "SELECT BUTTON"
        Button:
            on_press: root.show_buttons(self)
            text: "Button 1"
        Button:
            on_press: root.show_buttons(self)
            text: "Button 2"

<AnotherScreen>:
    id: another
    name: "another"
    BoxLayout:
        id: box
        orientation: 'vertical'
        Label:
            text: "Select BUTTON"
        Button: 
            on_press: root.manager.current = 'main'
            text: "BACK"


""")



class CoolApp(App):
    def build(self):
        return kv_str


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

最后由你决定。另一种可能性是在 ScreenManager 中或直接在应用程序中使用 ObjectProperties class。上面的解决方案是我的首选方法。