如何跨小部件和屏幕使用 KIVY 和 Python 中的变量

How to work with variables in KIVY and Python across widgets and screens

我是一名想要提高的初学者程序员 - 我用 pyGame 制作了一些非常酷的 Python 游戏 - 现在对 KIVY 产生了兴趣!逻辑和布局的分离很棒。但作为 OOP 领域的经验不足的老手,在这一点上我快要发疯了。我不知道如何连接所有不同的部分。我可以遵循的大多数 KIVY 教程都是基础的,主要集中在设计上——这很好,但是当涉及到真正的骨头上的肉时,就没有太多可做的了。

(还有一些看似为火星好奇号漫游者构建 GUI 的工具——这些让我难以理解)。我确实在这个过程中获取了点点滴滴的知识,但我的代码和我的大脑最终会因为太多不同的方法和程序员风格相互冲突而受苦。 [希望这是有道理的]我想知道我是否需要从根本上从头开始并抛出不好的建议?

在下面的代码中,我设置了一个带有两个屏幕的简单 KIVY gui。第一页递增变量“A”,第二页递增变量“B”。我能够从每个 KV 'screen' 检索并显示两个变量的值,因为它们属于同一个根屏幕管理器 class。但是我一直无法弄清楚如何在弹出窗口 window 中获取和操作相同的变量,因为这不在屏幕管理器的管辖范围内。 (在某些教程的某处,我学会了使用 Factory 导入在 KVlang 中创建一个弹出窗口。)但是如果我想在弹出窗口中设置“A”= 0,我就很难过了。我应该使用 __init__、全局变量、app、App.get_screen、parent/child 断言、id、kv 属性、绑定。

从任一屏幕上的弹出窗口将“A”和“B”重置为零是否很容易完成?我离基地很远吗?如何更改第一页按钮的“B”值或第二页按钮的“A”值?

test.py

from kivy.app import App
from kivy.properties import NumericProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder


class WindowManager(ScreenManager):
    pass

class Screen1(Screen):
    a = NumericProperty(0)
    varB = NumericProperty(0)

    def add_1(self):
        self.a += 1

    def min_1(self):
        self.a -= 1

class Screen2(Screen):
    b = NumericProperty(0)
    varA = NumericProperty(0)

    def add_1(self):
        self.b += 1

    def min_1(self):
        self.b -= 1

class SampleApp(App):
    def build(self):
        return kv

kv = Builder.load_file('my.kv')

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

my.kv

#: import Factory kivy.factory.Factory

WindowManager:
    Screen1:
        id: S1
        varB:S2.b
    Screen2:
        id: S2
        varA:S1.a              # THIS IS HOW I GRAB DATA FROM DIFFERENT CLASS
                               # STRUCTURES UNDER THE WINDOWMANAGER

<PopupMenu@Popup>:
    size_hint: (.25,.25)
    title: "MENU"
    Button:
        text: "RESET"
        on_release:
            print("Now What?")            # HOW DO I BRING VARIABLES INTO THIS?

<Screen1>:
    name: 'Screen_1'
    BoxLayout:
        orientation: "vertical"
        BoxLayout:
            size_hint: (1,.4)
            Button:
                size_hint: (.25,1)
                text: "A +1"
                color: 1,1,1,1
                font_size: self.width/5
                background_normal: ''
                background_color: 0,191/255,1,1
                on_release:
                    root.add_1()
            Label:
                canvas:
                    Color:
                        rgba: 1,0,1,.25
                    Rectangle:
                        pos: self.pos
                        size: self.size
                text: "A = " + str(root.a)
                underline: True
                pos_hint: {"center_x":.5,"center_y":.5}
                font_size: self.width/5
                color: 1,1,1,1
        BoxLayout:
            size_hint: (1,.4)
            Button:
                size_hint: (.25,1)
                text: "A -1"
                color: 1,1,1,1
                font_size: self.width/5
                background_normal: ''
                background_color: 0,191/255,1,1
                on_release:
                    root.min_1()     # IT'S EASY TO CALL THIS FUNCTION SINCE IT'S IN ITS ROOT.
                                     # BUT WHAT IF I WANTED TO MANIPULATE VARIABLE "B" FROM
                                     # SCREEN TWO?
            Label:
                canvas:
                    Color:
                        rgba: 1,0,1,.25
                    Rectangle:
                        pos: self.pos
                        size: self.size
                text: "B = " + str(root.varB)
                underline: True
                pos_hint: {"center_x":.5,"center_y":.5}
                font_size: self.width/5
                color: 1,1,1,1
        BoxLayout:
            size_hint: (1,.2)
            Button:
                text: "popup"
                color: 1,1,1,1
                font_size: self.width/6
                on_release:
                    Factory.PopupMenu().open()   # IS THIS THE RIGHT WAY TO MAKE A POPUP?
            Button:
                text: "Page 2"
                color: 1,1,1,1
                font_size: self.width/6
                on_release:
                    app.root.current = 'Screen_2'
                    root.manager.transition.direction = 'left'

<Screen2>:
    name: 'Screen_2'
    BoxLayout:
        orientation: "vertical"
        BoxLayout:
            size_hint: (1,.4)
            Button:
                size_hint: (.25,1)
                text: "B +1"
                color: 1,1,1,1
                font_size: self.width/5
                background_normal: ''
                background_color: 0,191/255,1,1
                on_release:
                    root.add_1()
            Label:
                canvas:
                    Color:
                        rgba: 0,0,1,.3
                    Rectangle:
                        pos: self.pos
                        size: self.size
                text: "A = " + str(root.varA)
                underline: True
                pos_hint: {"center_x":.5,"center_y":.5}
                font_size: self.width/5
                color: 1,1,1,1
        BoxLayout:
            size_hint: (1,.4)
            Button:
                size_hint: (.25,1)
                text: "B -1"
                color: 1,1,1,1
                font_size: self.width/5
                background_normal: ''
                background_color: 0,191/255,1,1
                on_release:
                    root.min_1()
            Label:
                canvas:
                    Color:
                        rgba: 0,0,1,.3
                    Rectangle:
                        pos: self.pos
                        size: self.size
                text: "B = " + str(root.b)
                underline: True
                pos_hint: {"center_x":.5,"center_y":.5}
                font_size: self.width/5
                color: 1,1,1,1
        BoxLayout:
            size_hint: (1,.2)
            Button:
                text: "popup"
                color: 1,1,1,1
                font_size: self.width/6
                on_release:
                    Factory.PopupMenu().open()
            Button:
                text: "Page 1"
                color: 1,1,1,1
                font_size: self.width/6
                on_release:
                    app.root.current = 'Screen_1'
                    root.manager.transition.direction = 'right'

您可以在 <PopupMenu@Popup> 规则中使用 app 关键字来引用 SampleApp 实例,然后 ids 到达 Screens。像这样:

<PopupMenu@Popup>:
    size_hint: (.25,.25)
    title: "MENU"
    Button:
        text: "RESET"
        on_release:
            print("Now What?", app.root.ids.S1.varB)            # HOW DO I BRING VARIABLES INTO THIS?