Search code examples
pythonkivy

Update Kivy settings panel values with changed Config


Question:

I am building an App and using the kivy settingspanel to change settings. Some of the settings are stored in ConfigParserProperties and can also be changed outside of the settings panel. When I reopen the settings panel the values in the settings panel are still the old ones.
How can I update the settings panel with the most recent values (in the ConfigParserProperties)?

What I have Tried:

  • I found this Dynamically updated Kivy settings entry But here only 1 widget is created which updates (a list popup). I am looking for a way to update multiple settings items of different types.

  • The only way I got the settings panel to update is by destroying it and recreating it every time it is opened (for code see below). This is a (noticeably) slow process if the panel contains multiple pages (which is not the case in this example to keep things simple).

Example:

This example generates a random value for variable test, which is the only item in the settings panel (open it by clicking the button or pressing f1). As you can see the value will not change from the start value.

from kivy.app import App
from kivy.properties import ConfigParserProperty
from random import randint
from kivy.clock import Clock
from kivy.uix.button import Button
import json


class MyApp(App):
    test = ConfigParserProperty(0, 'testing', 'test_par', 'app_config', val_type=int)
    use_kivy_settings = False   # disable kivy settings in options

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        Clock.schedule_interval(self.new_number, 1)

    def build(self):        
        self.config.read("test.ini")
        self.config.name = "app_config"
        _app = super().build()
        _app.add_widget(Button(text='open settings', 
                               size=_app.size, 
                               pos=_app.pos, 
                               on_release=self.open_settings))
        return _app

    def build_settings(self, settings):
        _setts = json.dumps([
        {
            "type": "title",
            "title": "Test Settings"
        },
        {
            "type": "numeric",
            "title": "Test Var",
            "desc": "Randomly changing test var, wish it would change here too",
            "section": "testing",
            "key": "test_par"
        }])
        settings.add_json_panel('Test Panel', self.config, data=_setts)
        self.settings = settings

    def new_number(self, *args, **kwargs):
        # generate random new values for test
        self.test = randint(0, 0xff)
        print(self.test)

if __name__ == "__main__":
    app = MyApp()
    app.run()

What I tried:
Adding this code will change the value every time the panel is opened. But also destroys and recreates the panel everytime you open it. Which is slow with multiple panel items.

    def open_settings(self, *args):
        self.destroy_settings()  # clear settings
        return super().open_settings(*args)

If anyone knows a way to change/update specific panel items with changes in the ConfigParserProperties, much appreciated.


Solution

  • Had the same problem. My solution was to manually update the value of each SettingItem after changing the ConfigParser object. For this you can simply iterate over the panels of your settings widget:

    from kivy.uix.settings import SettingItem
    
    # ...
    
    settings = <my setting widget instance>
    panels = settings.interface.content.panels
        
    for panel in panels.values():        
        children = panel.children
    
        for child in children:
            if isinstance(child, SettingItem):                    
                child.value = panel.get_value(child.section, child.key)
    
    # ...
    

    Maybe you have to adjust the path to the panels (.interface.content.panels), depending of the type of settings widget you use (I used default SettingsWithSidebar). The panel.get_value method gets the actual value directly out of the initially assigned ConfigParser instance.