Skip to content
Advertisement

Change Value of a Kivy Property from a seperate File

So at the moment im having a problem with Kivy, which i cant resolve. I have a situation where i want to change the Value of a Kivy NumericProperty in a File “A” from another programm “B”, thus that the program “C”, where all the Kivy interface stuff is, detects the change and updates the value on the screen.

File “A” (called Testvars) is just a file where i want to declare and store Kivy propertys for better clarity.

from kivy.properties import BoundedNumericProperty
    
value = BoundedNumericProperty(20, min = 0, max = 24)

File “B” should later on able to access and change the values of these propertys.

import testvars as testvars

testvars.value = testvars.value + 1

File “C” is my actuall Kivy program, but has also the ability to change values in “A”

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager
from kivy.properties import NumericProperty
from kivy.lang import Builder
import testvars as testvars

class test(ScreenManager):
    value = testvars.value
     
        
class Main(App):

    def build(self):
        Builder.load_file('test.kv')
        return test()
        

Main().run()

and the KV-File:

<test>:
Screen:
    Label:
        text: str(root.value)
        halign: "center"
    Button:
        text: "++"
        size_hint: .1, .08
        pos_hint: {"center_x":.5}
        on_release: root.value = root.value +1

My problem is in file “B”. So far i managed to give Kivy in “C” access to the propertys in “A” and modify these values and detect and display changes i make from “C”. However, when i try to change the values in “A” from “B”, i get back a Error, saying i cant add an integer to an BoundedNumericProperty Object. So far i didnt find a function in the Kivy manual, that does that for me.

Thanks in advance.

Advertisement

Answer

A kivy Property must be defined inside an EventDispatcher. The documentation says:

The Properties classes are used when you create an EventDispatcher.

and

Property objects live at the class level and manage the values attached to instances. Re-assigning at class level will remove the Property.

So, your BoundedNumericProperty must be defined within an EventDispatcher class. Typically, this would be a Widget, but any EventDispatcher will work.

Here are two possible approaches for you. The first is to define the BoundedNumericProperty in the test class, and just use the testvars to store an initial value. That would look something like this, in the testvars class:

INITIAL_BOUNDED_VALUE = 20

And used in test as:

class test(ScreenManager):
    value = BoundedNumericProperty(testvars.INITIAL_BOUNDED_VALUE, min = 0, max = 24)

You can modify the value of the Property from a third location by accessing the the test class instance. Probably by using the App.get_running_app() method and the get_screen() method of ScreenManager.

The second approach, if you need to have the BoundedNumericProperty actually in testvars, is to define a class in testvars that contains the Property:

from kivy.event import EventDispatcher
from kivy.properties import BoundedNumericProperty

class TestVars(EventDispatcher):
    value = BoundedNumericProperty(20, min=0, max=24)

    def __new__(cls):
        # ensure this is a singleton
        if not hasattr(cls, 'instance'):
            cls.instance = super(TestVars, cls).__new__(cls)
        return cls.instance

tv = TestVars()

The above code defines a singleton class TestVars and creates the instance as tv. In this approach, there is no longer any Property in the test class:

class test(ScreenManager):
    # value = ObjectProperty(testvars.tv.value, rebind=True)
    pass

And the Property is referenced directly from the kv file:

#:import testvars testvars
<test>:
    Screen:
        Label:
            text: str(testvars.tv.value)
            halign: "center"
        Button:
            text: "++"
            size_hint: .1, .08
            pos_hint: {"center_x":.5}
            on_release: testvars.tv.value += 1

And in a third place you can change the value as:

import testvars as testvars

testvars.tv.value = testvars.tv.value + 1

The first approach is the simpler and more straightforward approach.

User contributions licensed under: CC BY-SA
1 People found this is helpful
Advertisement