Pieter-Jan
Pieter-Jan

Reputation: 540

Kivy - Access instance created in other Screen

I created some instances of a class (Player class) in my first Screen, and would like to access these instances (and their data) in another Screen. The idea is this:

I marked in the code below where I tried to access the instances, but got the error:

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

My question is: How can I access the player points in ThirdRound(Screen) class in order to display their points on a label and to change the points when +/- Button is pressed?

(I searched for similar cases but was not able to apply them to my case.)

.py file:

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 file:

<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')

Upvotes: 3

Views: 282

Answers (1)

John Anderson
John Anderson

Reputation: 39002

The __init__() method of ThirdRound is called at the line:

WindowManager.add_widget(ThirdRound())

Specifically, the ThirdRound() is executed before the WindowManager.add_widget, so the ThirdRound instance does not have its manager yet set when its __init__() is executed, so it is still None. Try moving the code that accesses the manager till it is needed. Something like this:

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)

Upvotes: 1

Related Questions