Kivy - 在其他屏幕中创建的访问实例

Posted

技术标签:

【中文标题】Kivy - 在其他屏幕中创建的访问实例【英文标题】:Kivy - Access instance created in other Screen 【发布时间】:2020-07-15 01:15:04 【问题描述】:

我在我的第一个 Screen 中创建了一个类(Player 类)的一些实例,并希望在另一个 Screen 中访问这些实例(及其数据)。思路是这样的:

Player class:这个类的实例包含玩家的名字和他们的分数。 (完成) WelcomeWindow(Screen) class:通过 TextInput 提取玩家名称 + 创建 Player 类的实例并分配名称。 (完成) ThirdRound(Screen) class:访问玩家实例的名称和分数,在标签上显示名称并在按下 +/- 按钮时更改玩家分数。 (问题)

我在下面的代码中标记了我尝试访问实例的位置,但出现了错误:

AttributeError: 'NoneType' object has no attribute 'get_screen'

我的问题是:我如何访问ThirdRound(Screen) class 中的玩家积分,以便在标签上显示他们的积分并在按下 +/- 按钮时更改积分?

(我搜索了类似的案例,但无法将它们应用到我的案例中。)

.py 文件:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.textinput import TextInput
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.properties import ObjectProperty, NumericProperty


class Player:
    def __init__(self, name):
        self.name = name
        self.points = 0

    def reset_points(self):
        self.points = 0

    def add_point(self, *args):
        self.points += 1

    def subtract_point(self, *args):
        self.points -= 1


class WelcomeWindow(Screen):
    # Introduce names of the 4 players
    def __init__(self, **kwargs):
        super(WelcomeWindow, self).__init__(**kwargs)
        self.name = "welcomewindow"

        # Create global layout of HOME screen
        global_layout = GridLayout(rows=3)
        self.add_widget(global_layout)

        # Some code with labels and buttons

        # Create button to go to next screen
        go_further_button = Button(text="Go to first round")
        go_further_button.bind(on_release=self.go_further)
        global_layout.add_widget(go_further_button)

    def go_further(self, *args):
        #Give names to players
        self.player1 = Player("name1") # <--- 4 player instances are created here
        self.player2 = Player("name2")
        self.player3 = Player("name3")
        self.player4 = Player("name4")

        self.manager.current = "thirdround"
        self.manager.transition.direction = "left"


class ThirdRound(Screen):
    def __init__(self, **kwargs):
        super(ThirdRound, self).__init__(**kwargs)
        self.name = "thirdround"

        welcome_window = self.manager.get_screen('welcomewindow') # <--- Trying to access player instances here but failed
        self.player1_points = welcome_window.player1.points


    def change_label(self, add_sub, *args): # <--- method which will change the points of the player instance

        label = self.ids['testlabel']
        if add_sub == 'add':
            label.text = 'should add one point'
        elif add_sub == 'sub':
            label.text = 'should subtract one point'


kv = Builder.load_file("Kingen.kv")

WindowManager = ScreenManager()
WindowManager.add_widget(WelcomeWindow())
WindowManager.add_widget(ThirdRound())


class KingenApp(App):

    def build(self):
        return WindowManager


if __name__ == "__main__":
    KingenApp().run()

.kv 文件:

<ThirdRound>:

    GridLayout:
        rows: 3

        Label:
            id: testlabel
            text: 'shows number of points here'

        Button:
            text: "+"
            on_release: root.change_label('add')

        Button:
            text: "-"
            on_release: root.change_label('sub')

【问题讨论】:

【参考方案1】:

ThirdRound__init__()方法在该行被调用:

WindowManager.add_widget(ThirdRound())

具体来说,ThirdRound()WindowManager.add_widget 之前执行,所以ThirdRound 实例在其__init__() 执行时还没有设置它的manager,所以它仍然是None。尝试移动访问manager 的代码直到需要它为止。像这样的:

class ThirdRound(Screen):
    def __init__(self, **kwargs):
        super(ThirdRound, self).__init__(**kwargs)
        self.name = "thirdround"

    def change_label(self, add_sub, *args): # <--- method which will change the points of the player instance
        welcome_window = self.manager.get_screen('welcomewindow')

        label = self.ids['testlabel']
        if add_sub == 'add':
            welcome_window.player1.points += 1
            label.text = str(welcome_window.player1.points)
        elif add_sub == 'sub':
            welcome_window.player1.points -= 1
            label.text = str(welcome_window.player1.points)

【讨论】:

谢谢,你解释清楚了,现在说得通了!

以上是关于Kivy - 在其他屏幕中创建的访问实例的主要内容,如果未能解决你的问题,请参考以下文章

您如何使用 Kivy GUI 访问其他类方法和函数?

如何在 Kivy 屏幕小部件中初始化实例

难以访问在 Interface Builder .xib 文件中创建的 UITableViewCell

如何在颤动的另一个有状态小部件中访问在一个有状态小部件中创建的对象

Httpd 只允许访问直接在 /var/www/html 文件夹中创建的文件

您如何将 main 中创建的实例传递给类?