Search code examples
pythonpython-3.xkivykivy-language

Is it possible to modify variables in different class from within App() without instantiating new instance of class


I'm trying to use kivy's settings panel. However, I can't get it to access and or modify class variables from within App() without instantiating a new object of the class I'm trying to use. Which isn't acceptable for what I want to do. The json file is contained in a file named MyJson.json and my_json is the actual data.I know this works because the settings panel pops up fine.

I'd like to use a settings panel as it's laid out here (or in a comparable manner). But, I need the values changed in the settings panel to change the variables within myScreen as they happen.

Is it possible to access myScreen(Screen) from App() without creating a new object of myScreen() as I've done in the example below?

import sys
import os
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.config import Config
from kivy.config import ConfigParser
from kivy.uix.settings import SettingsWithSidebar
from kivy.uix.button import Button
from MyJson import my_json

class myScreen(Screen):
    def __init__(self, **kwargs):
        super(myScreen, self).__init__(**kwargs)
        self.test_var = 2

    def example_func(self):
        print(str(self.test_var))

class myScreenManager(ScreenManager):
    pass


root_widget = Builder.load_string('''
myScreenManager:
    myScreen:

<myScreen>:
    Button:
        id: test_button
        size_hint: .03, .05 
        pos_hint: {'x': .50, 'y': .50}
        on_press: app.open_settings()

''')

class TestApp(App):
    def build(self):
        self.settings_cls = SettingsWithSidebar
        self.temp = myScreen()
        return root_widget 

    def build_config(self, config):
        config.setdefaults('settings_stuff', {
            'example_one': False, 
            'example_two': True
            })

    def build_settings(self, settings):
        settings.add_json_panel('Example Panel', self.config, data = my_json)

    def on_config_change(self, config, section, key, value):
        if key == 'example_one' and value == '1':
            self.temp.test_var += 1
            self.temp.example_func()
            print(self.temp.test_var)
        elif key == 'example_one' and value == '0':
            self.temp.example_func()
            self.temp.test_var -= 1
            print(self.temp.test_var) 

if __name__ == '__main__':
     TestApp().run()

If I run the above code and "Turn on" the switch it calls the function and prints the value 2 instead of three. It calls the function but it doesn't implement the change in the active screen class.

Json code is here:

import json 
my_json = json.dumps([
    {
         "type": "title",
         "title": "Settings Panel"
    },
    {
         "type": "bool",
         "title": "Add",
         "desc": "increment value",
         "section": "settings_stuff",
         "key": "example_one"  
    },
    {
         "type": "bool",
         "title": "random",
         "desc": "filler",
         "section": "settings_stuff",
         "key": "example_two"  
    }
])

Solution

  • Since the root is the ScreenManager, you can access the Screen through its name using get_screen():

    import sys
    from kivy.app import App
    from kivy.lang import Builder
    from kivy.uix.screenmanager import ScreenManager, Screen
    from kivy.uix.settings import SettingsWithSidebar
    from MyJson import my_json
    
    class MyScreen(Screen):
        def __init__(self, **kwargs):
            super(MyScreen, self).__init__(**kwargs)
            self.test_var = 2
    
        def example_func(self):
            print(str(self.test_var))
    
    class MyScreenManager(ScreenManager):
        pass
    
    
    root_widget = Builder.load_string('''
    MyScreenManager:
        MyScreen:
            name: 'name_of_screen'
    
    <MyScreen>:
        Button:
            id: test_button
            size_hint: .03, .05 
            pos_hint: {'x': .50, 'y': .50}
            on_press: app.open_settings()
    
    ''')
    
    class TestApp(App):
        def build(self):
            self.settings_cls = SettingsWithSidebar
            self.temp = root_widget.get_screen('name_of_screen')
            return root_widget 
    
        def build_config(self, config):
            config.setdefaults('settings_stuff', {
                'example_one': False, 
                'example_two': True
                })
    
        def build_settings(self, settings):
            settings.add_json_panel('Example Panel', self.config, data = my_json)
    
        def on_config_change(self, config, section, key, value):
            if key == 'example_one' and value == '1':
                self.temp.test_var += 1
                self.temp.example_func()
                print(self.temp.test_var)
            elif key == 'example_one' and value == '0':
                self.temp.example_func()
                self.temp.test_var -= 1
                print(self.temp.test_var) 
    
    if __name__ == '__main__':
         TestApp().run()