Search code examples
pythonkivy

How to make a variable in python that can be accessed and modified by any screens in kivy?


I want to make a variable that can be modified by one screen, then the variable can change the text of different screen. Here is the python file

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

value = NumericProperty(0)

class MainWindow(Screen):

    def vval(self, root):
        root.value = 1

    def vvval(self, root):
        root.value = 2

class SecondWindow(Screen):
    pass
    
class WindowManager(ScreenManager):
    pass

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

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

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

and here is the kivy file

WindowManager:
    MainWindow:
    SecondWindow:

<MainWindow>:
    name: "main"
    GridLayout:
        size: root.width, root.height
        rows: 2

        Button:
            text: "print 1"
            on_release:
                root.vval(root)
                app.root.current = "second"

        Button:
            text: "print 2"
            on_release:
                root.vvval(root)
                app.root.current = "second"

<SecondWindow>:
    name: "second"
    Label:
        text: "successfully printed ", root.value

What I expected to happens is when I click one of the button in the the MainWindow, the variable, which I named it "value" will be modified to 1 or 2 depending on what button i click, then the screen changed to the SecondWindow and display the text "successfully printed x", the value of x is depends to the "value" variable.

I'm still new on kivy, if there is some error or ambiguity, I am sorry. Please share me your knowledge about this, it will be appreciated.


Solution

  • Generally, one would do this with a StringProperty object. The code below shows a working example, although I did take liberties in restructuring some things about your code. I admit I had some challenges with .bind of the StringProperty which I ended up resolving by building the ScreenManager object in the Python code instead of the .kv lines.

    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.screenmanager import Screen, ScreenManager
    from kivy.properties import NumericProperty, StringProperty
    
    value = NumericProperty(0)
    
    Builder.load_string('''
    <MainWindow>
        name: "main"
        GridLayout:
            size: root.width, root.height
            rows: 2
            Button:
                text: "print 1"
                on_release:
                    # arguments can be passed, including a 'self' of the button object
                    app.kv_button("1", "second", self)
                    # app.root.current = "second"
            Button:
                text: "print 2"
                on_release:
                    # arguments can be passed, including a 'self' of the button object
                    app.kv_button("2", "second", self)
                    # app.root.current = "second"
    <SecondWindow>
        name: "second"
        Label:
            # maps to a StringProperty, root. would be the widget, this is app. which is the App()
            text: app.result_text
    ''')
    
    
    class MainWindow(Screen):
        pass
    
    
    class SecondWindow(Screen):
        value: str
        pass
    
    
    class WindowManager(ScreenManager):
        pass
    
    
    # Builder.load_file("testing.kv")
    
    
    class testing(App):
        result_text = StringProperty()
    
        def kv_button(self, _value: str, next_screen: str, *args):
            print(f"{self} {_value} {args}")
            self.result_text = _value
            # change the screen using the WindowManager object that has been kept as a reference
            self._main.current=next_screen
    
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
            self._main = WindowManager()
            self._main.add_widget(MainWindow())
            self._main.add_widget(SecondWindow())
    
        def build(self):
            return self._main
    
    
    if __name__ == "__main__":
        testing().run()