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.