Pieter-Jan
Pieter-Jan

Reputation: 540

Kivy - Use text from TextInput of one screen in another screen in .py file

I have a TextInput on my first screen and I want to use the received text in a Label on my second screen. How can I do this? Since there can be different players, I created a class Players which stores for every player a name and his/her points. In the second screen, I also tried to create a button which can edit the points (text of Label), but when I click it, nothing happens. (I am also new to classes.)

In the code below, I marked the relevant lines.

So overview:

I know there is a similar case here, but it doesn't help me for my .py file: How to ref a TextInput from one screen in another screen in Kivy/Python?

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"
        self.layout = "layout_welcome_window"

        global_layout = GridLayout(rows=3)
        self.add_widget(global_layout)

        label_player_i = Label(text="Name Player ")
        global_layout.add_widget(label_player_i)

        name_input_player_i = TextInput(id="player ", text="player", multiline=False) # <--- user inputs name here
        global_layout.add_widget(name_input_player_i)

        self.player1 = Player(name_input_player_i.text) # <--- name is assigned to player here

        # 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):
        self.manager.current = "firstround"
        self.manager.transition.direction = "left"

class FirstRound(Screen):
    #Give explanation of first round + option to add points for every player

    def __init__(self, **kwargs):
        super(FirstRound, self).__init__(**kwargs)
        self.name = "firstround"
        self.layout = "layout_first_round"

        #Create layout
        global_layout = GridLayout(rows=4)
        self.add_widget(global_layout)

        #Create Labels
        label_player_name_i = Label(text=WelcomeWindow().player1.name) # <--- Label should get the name of the player here
        global_layout.add_widget(label_player_name_i)

        label_player_points_i = Label(text=str(WelcomeWindow().player1.points)) # <--- Label should get points of player
        global_layout.add_widget((label_player_points_i))

        #Create Buttons
        button_minus = Button(text="-", font_size=100, id="minus_button")
        button_minus.bind(on_release=WelcomeWindow().player1.subtract_point) # <--- When button pushed: should subtract point
        global_layout.add_widget(button_minus)

        button_plus = Button(text="+", font_size=100, id="plus_button")
        button_plus.bind(on_release=WelcomeWindow().player1.add_point) # <--- When button pushed: should add point
        global_layout.add_widget(button_plus)


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

class KingenApp(App):

    def build(self):
        return WindowManager

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

Upvotes: 1

Views: 1146

Answers (1)

John Anderson
John Anderson

Reputation: 38937

Several problems with your code:

  • The __init__() method of any Widget is called when you create an instance of that Widget. So the __init__() method of FirstRound is called at the line WindowManager.add_widget(FirstRound()). At that time no text can have been entered into the TextInput of WelcomeWindow , so you cannot get the player name at that time.
  • The creation of the Player instance (self.player1 = Player(name_input_player_i.text)) creates the Player instance before the user has a chance to enter a player name.
  • The use of WelcomeWindow() in the __init__() method of FirstRound creates a new instance of WelcomeWindow that is unrelated to the one in your GUI. So any info extracted from that instance is of no use.
  • In your FirstRound, the player points label gets its data from the Player class instance at the time that the Label is created. Changing the the points attribute of Player after that will have no effect on the Label.

The first issue can be handled by moving most of your code out of the __init__() method of FirstRound, and place it in an on_enter() method that is run when that Screen is displayed.

The second issue can be handled by moving the creation of the Player instance into the go_further() method, since it gets executed when leaving the WelcomeWindow.

The third issue can be handled by replacing those uses of WelcomeWindow() with self.manager.get_screen('welcomewindow') to access the actual instance of WelcomeWindow that is in your GUI.

Here is a modified version of your code that does those three things:

from kivy.app import App
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


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"
        self.layout = "layout_welcome_window"

        global_layout = GridLayout(rows=3)
        self.add_widget(global_layout)

        label_player_i = Label(text="Name Player ")
        global_layout.add_widget(label_player_i)

        self.name_input_player_i = TextInput(id="player ", text="player", multiline=False) # <--- user inputs name here
        global_layout.add_widget(self.name_input_player_i)

        # 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):
        self.player1 = Player(self.name_input_player_i.text) # <--- name is assigned to player here
        self.manager.current = "firstround"
        self.manager.transition.direction = "left"


class FirstRound(Screen):
    #Give explanation of first round + option to add points for every player

    def __init__(self, **kwargs):
        super(FirstRound, self).__init__(**kwargs)
        self.name = "firstround"
        self.layout = "layout_first_round"

    def on_enter(self, *args):
        #Create layout
        global_layout = GridLayout(rows=4)
        self.add_widget(global_layout)

        #Create Labels
        welcome_window = self.manager.get_screen('welcomewindow')  # get a reference to the WelcomeWindow instance
        label_player_name_i = Label(text=welcome_window.player1.name) # <--- Label should get the name of the player here
        global_layout.add_widget(label_player_name_i)

        label_player_points_i = Label(text=str(welcome_window.player1.points)) # <--- Label should get points of player
        global_layout.add_widget((label_player_points_i))

        #Create Buttons
        button_minus = Button(text="-", font_size=100, id="minus_button")
        button_minus.bind(on_release=welcome_window.player1.subtract_point) # <--- When button pushed: should subtract point
        global_layout.add_widget(button_minus)

        button_plus = Button(text="+", font_size=100, id="plus_button")
        button_plus.bind(on_release=welcome_window.player1.add_point) # <--- When button pushed: should add point
        global_layout.add_widget(button_plus)


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


class KingenApp(App):

    def build(self):
        return WindowManager


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

The fourth issue deserves a question of its own, but likely involves using kivy language.

Upvotes: 1

Related Questions