Search code examples
pythonkivyglobal-variables

How to make changes to global object attribute with Kivy TextInput and have it save for later use?


My app currently has 10 "players" with a name, offensive rating, and defensive rating. I want to give the user the opportunity to change the names of the players before running my game simulation code, but it appears I can only temporarily change the name inside of the current screen. Here's my current python code for when the user inputs the name from the gui:

class SecondWindow(Screen):
    def pg1_name_val(self, widget):
    pg1.name = widget.text

If I code in a print(pg1.name) right below that, it will print the correct name, but when the user hits "play" to shift to a results screen, the names go back to the default names.

How do I make pg1.name from my SecondWindow(Screen) become the global pg1.name? Is there a simple line of code I can use to return pg1.name as the global variable?

EDIT ----

So I've came a long way with my app this week, but now that I want to have a separate "results" screen, I've realized that I lost all of my data from the previous screen. It looks like all of the changes I make to my "players" are going back to defaults once the screen changes. I'll paste some code below for reference. Basically, my question now is this: Is there a way to keep the objects from one screen and return them back as the global instance of the object. Not just the local instance of the object.

.py -

class Player():
def __init__(self,name,off,deff):
    self.name = name
    self.off = off
    self.deff = deff
    self.stats = 0

class Team(): def init(self,pg, sg, sf, pf, c): self.pg = pg self.sg = sg self.sf = sf self.pf = pf self.c = c self.score = 0 self.results = None self.to = 0

On the screen where I'm creating my team, I have a button to run the simulation. This button runs the sim correctly, records all of the game results in a string, prints all of the results to the console, attributes, and score correctly. The button also changes the screen to where I want to display a scroll view of the results string, but the results are empty.

I'd really appreciate any help on this, as I'm at a roadblock. Thanks!


Solution

  • It would kinda look the same. Depending on how exactly you wanna keep the 10 different players.

    class Player():
        def __init__(self, name, off, deff):
            self.name = name
            self.off = off
            self.deff = deff
            self.stats = 0
    
    player = [Player('', 0, 0)] * 10
    
    
    class SecondWindow(Screen):
        def __init__(self, **kwargs):
            super(SecondWindow, self).__init__(**kwargs)
            self.player = player
    
        def name_change(self):
            self.player[0].name = self.ids.name.text
            player[0].name = self.player[0].name
    
    
        def next_screen(self):
            self.manager.current = 'result'
    
    
    class ResultWindow(Screen):
        def __init__(self, **kwargs):
            super(ResultWindow, self).__init__(**kwargs)
    
        def on_enter(self, *args):
            print(player[0].name)
    
    
    class Manager(ScreenManager):
        pass
    
    
    class Player(App):
        def build(self):
            sm = ScreenManager()
            sm.add_widget(SecondWindow(name='second'))
            sm.add_widget(ResultWindow(name='result'))
            return sm
    
    
    if __name__ == '__main__':
        Player().run()
    

    You would have to work with OOP, here I created a list of you player object for all ten players it is an easy way to keep the code short. You might like to keep them as 10 different objects the good part of a list it is easy to iterate through in a for loop and then get all the data for a stats board on a screen and also easy to expand later if you need 20 players or more.

    I didn't change anything in the .kv file.

    .kv

    <SecondWindow>:
        TextInput:
            id: name
            hint_text: 'Player name'
            size: 260, 32
            pos: (root.width / 2) - (self.width / 2), 248
            multiline: False
            on_text_validate: root.name_change()
        Button:
            id: create_btn
            text: 'Next Screen'
            size: 260, 32
            pos: (root.width / 2) - (self.width / 2), 206
            color: utils.get_color_from_hex('#ffffff')
            background_color: utils.get_color_from_hex('#016bf8')
            on_press: root.next_screen()
    
    <ResultWindow>:
        Label:
            id: name
    

    The on_text_validate only works with multiline false and when enter is pressed if you don't want to press enter user on_text instead.

    --Edit--

    I did some research this morning and thought maybe to update this a bit with my findings. You could instead of doing it the import to all screens do it in the screenmanager and just call it from the screen like this:

    pyhon.py

    import kivy
    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.screenmanager import ScreenManager, Screen
    
    
    class Player:
        def __init__(self, name, off, deff):
            self.name = name
            self.off = off
            self.deff = deff
            self.stats = 0
    
    
    class SecondWindow(Screen):
        def __init__(self, **kwargs):
            super(SecondWindow, self).__init__(**kwargs)
    
        def name_change(self):
            self.manager.player.name = self.ids.name.text
    
    
        def next_screen(self):
            self.manager.current = 'result'
    
    
    class ResultWindow(Screen):
        def __init__(self, **kwargs):
            super(ResultWindow, self).__init__(**kwargs)
    
        def on_enter(self):
            self.ids.name.text = self.manager.player.name
    
    
    class Manager(ScreenManager):
        player = Player('', 0, 0)
    
        def __init__(self, **kwargs):
            super(Manager, self).__init__(**kwargs)
    
    
    class PlayerApp(App):
        def build(self):
            return Builder.load_file('test.kv')
    
    
    if __name__ == '__main__':
        PlayerApp().run()
    

    the kv file would look something like this:

    .kv

    #:import utils kivy.utils
    Manager:
        SecondWindow:
            name: 'second'
        ResultWindow:
            name: 'result'
    
    <SecondWindow>:
        TextInput:
            id: name
            hint_text: 'Player name'
            size: 260, 32
            size_hint: None, None
            pos: (root.width / 2) - (self.width / 2), 248
            multiline: False
            on_text_validate: root.name_change()
        Button:
            id: create_btn
            text: 'Next Screen'
            size_hint: None, None
            size: 260, 32
            pos: 0, 0
            color: utils.get_color_from_hex('#ffffff')
            background_color: utils.get_color_from_hex('#016bf8')
            on_press: root.next_screen()
    
    <ResultWindow>:
        Label:
            id: name
    

    hope it helps