Table Of Contents
Properties¶
The Properties classes are used when you create an
EventDispatcher
.
Warning
Kivy’s Properties are not to be confused with Python’s
properties (i.e. the @property
decorator and the <property> type).
Kivy’s property classes support:
- Value Checking / Validation
- When you assign a new value to a property, the value is checked against validation constraints. For example, validation for an
OptionProperty
will make sure that the value is in a predefined list of possibilities. Validation for aNumericProperty
will check that your value is a numeric type. This prevents many errors early on.- Observer Pattern
- You can specify what should happen when a property’s value changes. You can bind your own function as a callback to changes of a
Property
. If, for example, you want a piece of code to be called when a widget’spos
property changes, you canbind
a function to it.- Better Memory Management
- The same instance of a property is shared across multiple widget instances.
Comparison Python vs. Kivy¶
Basic example¶
Let’s compare Python and Kivy properties by creating a Python class with ‘a’ as a float property:
class MyClass(object):
def __init__(self, a=1.0):
super(MyClass, self).__init__()
self.a = a
With Kivy, you can do:
class MyClass(EventDispatcher):
a = NumericProperty(1.0)
Depth being tracked¶
Only the “top level” of a nested object is being tracked. For example:
my_list_prop = ListProperty([1, {'hi': 0}])
# Changing a top level element will trigger all `on_my_list_prop` callbacks
my_list_prop[0] = 4
# Changing a deeper element will be ignored by all `on_my_list_prop` callbacks
my_list_prop[1]['hi'] = 4
The same holds true for all container-type kivy properties.
Value checking¶
If you wanted to add a check for a minimum / maximum value allowed for a property, here is a possible implementation in Python:
class MyClass(object):
def __init__(self, a=1):
super(MyClass, self).__init__()
self.a_min = 0
self.a_max = 100
self.a = a
def _get_a(self):
return self._a
def _set_a(self, value):
if value < self.a_min or value > self.a_max:
raise ValueError('a out of bounds')
self._a = value
a = property(_get_a, _set_a)
The disadvantage is you have to do that work yourself. And it becomes laborious and complex if you have many properties. With Kivy, you can simplify the process:
class MyClass(EventDispatcher):
a = BoundedNumericProperty(1, min=0, max=100)
That’s all!
Error Handling¶
If setting a value would otherwise raise a ValueError, you have two options to handle the error gracefully within the property. The first option is to use an errorvalue parameter. An errorvalue is a substitute for the invalid value:
# simply returns 0 if the value exceeds the bounds
bnp = BoundedNumericProperty(0, min=-500, max=500, errorvalue=0)
The second option in to use an errorhandler parameter. An errorhandler is a callable (single argument function or lambda) which can return a valid substitute:
# returns the boundary value when exceeded
bnp = BoundedNumericProperty(0, min=-500, max=500,
errorhandler=lambda x: 500 if x > 500 else -500)
Keyword arguments and __init__()¶
When working with inheritance, namely with the __init__() of an object that
inherits from EventDispatcher
e.g. a
Widget
, the properties protect
you from a Python 3 object error. This error occurs when passing kwargs to the
object instance through a super() call:
class MyClass(EventDispatcher):
def __init__(self, **kwargs):
super(MyClass, self).__init__(**kwargs)
self.my_string = kwargs.get('my_string')
print(MyClass(my_string='value').my_string)
While this error is silenced in Python 2, it will stop the application in Python 3 with:
TypeError: object.__init__() takes no parameters
Logically, to fix that you’d either put my_string directly in the __init__() definition as a required argument or as an optional keyword argument with a default value i.e.:
class MyClass(EventDispatcher):
def __init__(self, my_string, **kwargs):
super(MyClass, self).__init__(**kwargs)
self.my_string = my_string
or:
class MyClass(EventDispatcher):
def __init__(self, my_string='default', **kwargs):
super(MyClass, self).__init__(**kwargs)
self.my_string = my_string
Alternatively, you could pop the key-value pair from the kwargs dictionary before calling super():
class MyClass(EventDispatcher):
def __init__(self, **kwargs):
self.my_string = kwargs.pop('my_string')
super(MyClass, self).__init__(**kwargs)
Kivy properties are more flexible and do the required kwargs.pop()
in the background automatically (within the super() call
to EventDispatcher
) to prevent this distraction:
class MyClass(EventDispatcher):
my_string = StringProperty('default')
def __init__(self, **kwargs):
super(MyClass, self).__init__(**kwargs)
print(MyClass(my_string='value').my_string)
Conclusion¶
Kivy properties are easier to use than the standard ones. See the next chapter for examples of how to use them :)
Observe Property changes¶
As we said in the beginning, Kivy’s Properties implement the Observer pattern. That means you can
bind()
to a property and have your own
function called when the value changes.
There are multiple ways to observe the changes.
Observe using bind()¶
You can observe a property change by using the bind() method outside of the class:
class MyClass(EventDispatcher):
a = NumericProperty(1)
def callback(instance, value):
print('My callback is call from', instance)
print('and the a value changed to', value)
ins = MyClass()
ins.bind(a=callback)
# At this point, any change to the a property will call your callback.
ins.a = 5 # callback called
ins.a = 5 # callback not called, because the value did not change
ins.a = -1 # callback called
Note
Property objects live at the class level and manage the values attached to instances. Re-assigning at class level will remove the Property. For example, continuing with the code above, MyClass.a = 5 replaces the property object with a simple int.
Observe using ‘on_<propname>’¶
If you defined the class yourself, you can use the ‘on_<propname>’ callback:
class MyClass(EventDispatcher):
a = NumericProperty(1)
def on_a(self, instance, value):
print('My property a changed to', value)
Warning
Be careful with ‘on_<propname>’. If you are creating such a callback on a property you are inheriting, you must not forget to call the superclass function too.
Binding to properties of properties.¶
When binding to a property of a property, for example binding to a numeric property of an object saved in a object property, updating the object property to point to a new object will not re-bind the numeric property to the new object. For example:
<MyWidget>:
Label:
id: first
text: 'First label'
Label:
id: second
text: 'Second label'
Button:
label: first
text: self.label.text
on_press: self.label = second
When clicking on the button, although the label object property has changed to the second widget, the button text will not change because it is bound to the text property of the first label directly.
In 1.9.0, the rebind
option has been introduced that will allow the
automatic updating of the text
when label
is changed, provided it
was enabled. See ObjectProperty
.
-
class
kivy.properties.
Property
(defaultvalue, **kw)¶ Bases:
builtins.object
This class handles all the basic setters and getters, None type handling, the observer list and storage initialisation. This class should not be directly instantiated.
By default, a
Property
always takes a default value:class MyObject(Widget): hello = Property('Hello world')
The default value must be a value that agrees with the Property type. For example, you can’t set a list to a
StringProperty
because the StringProperty will check the default value.None is a special case: you can set the default value of a Property to None, but you can’t set None to a property afterward. If you really want to do that, you must declare the Property with allownone=True:
class MyObject(Widget): hello = ObjectProperty(None, allownone=True) # then later a = MyObject() a.hello = 'bleh' # working a.hello = None # working too, because allownone is True.
Parameters: - default:
Specifies the default value for the property.
- **kwargs:
If the parameters include errorhandler, this should be a callable which must take a single argument and return a valid substitute value.
If the parameters include errorvalue, this should be an object. If set, it will replace an invalid property value (overrides errorhandler).
If the parameters include force_dispatch, it should be a boolean. If True, no value comparison will be done, so the property event will be dispatched even if the new value matches the old value (by default identical values are not dispatched to avoid infinite recursion in two-way binds). Be careful, this is for advanced use only.
- comparator: callable or None
When not None, it’s called with two values to be compared. The function returns whether they are considered the same.
- deprecated: bool
When True, a warning will be logged if the property is accessed or set. Defaults to False.
Changed in version 1.4.2: Parameters errorhandler and errorvalue added
Changed in version 1.9.0: Parameter force_dispatch added
Changed in version 1.11.0: Parameter deprecated added
-
bind
(EventDispatcher obj, observer)¶ Add a new observer to be called only when the value is changed.
-
defaultvalue
¶ defaultvalue: object
-
dispatch
(EventDispatcher obj)¶ Dispatch the value change to all observers.
Changed in version 1.1.0: The method is now accessible from Python.
This can be used to force the dispatch of the property, even if the value didn’t change:
button = Button() # get the Property class instance prop = button.property('text') # dispatch this property on the button instance prop.dispatch(button)
-
Property.fbind(EventDispatcher obj, observer, int ref, tuple largs=
Similar to bind, except it doesn’t check if the observer already exists. It also expands and forwards largs and kwargs to the callback. funbind or unbind_uid should be called when unbinding. It returns a unique positive uid to be used with unbind_uid.
-
Property.funbind(EventDispatcher obj, observer, tuple largs=
Remove the observer from our widget observer list bound with fbind. It removes the first match it finds, as opposed to unbind which searches for all matches.
-
get
(EventDispatcher obj)¶ Return the value of the property.
-
link
(EventDispatcher obj, str name)¶ Link the instance with its real name.
Warning
Internal usage only.
When a widget is defined and uses a
Property
class, the creation of the property object happens, but the instance doesn’t know anything about its name in the widget class:class MyWidget(Widget): uid = NumericProperty(0)
In this example, the uid will be a NumericProperty() instance, but the property instance doesn’t know its name. That’s why
link()
is used in Widget.__new__. The link function is also used to create the storage space of the property for this specific widget instance.
-
link_deps
(EventDispatcher obj, str name)¶
-
set
(EventDispatcher obj, value)¶ Set a new value for the property.
-
unbind
(EventDispatcher obj, observer)¶ Remove the observer from our widget observer list.
-
unbind_uid
(EventDispatcher obj, uid)¶ Remove the observer from our widget observer list bound with fbind using the uid.
-
class
kivy.properties.
NumericProperty
(defaultvalue=0, **kw)¶ Bases:
kivy.properties.Property
Parameters: - defaultvalue: int or float, defaults to 0
Specifies the default value of the property.
>>> wid = Widget() >>> wid.x = 42 >>> print(wid.x) 42 >>> wid.x = "plop" Traceback (most recent call last): File "<stdin>", line 1, in <module> File "properties.pyx", line 93, in kivy.properties.Property.__set__ File "properties.pyx", line 111, in kivy.properties.Property.set File "properties.pyx", line 159, in kivy.properties.NumericProperty.check ValueError: NumericProperty accept only int/float
Changed in version 1.4.1: NumericProperty can now accept custom text and tuple value to indicate a type, like “in”, “pt”, “px”, “cm”, “mm”, in the format: ‘10pt’ or (10, ‘pt’).
-
get_format
(EventDispatcher obj)¶ Return the format used for Numeric calculation. Default is px (mean the value have not been changed at all). Otherwise, it can be one of ‘in’, ‘pt’, ‘cm’, ‘mm’.
-
class
kivy.properties.
StringProperty
(defaultvalue='', **kw)¶ Bases:
kivy.properties.Property
Parameters: - defaultvalue: string, defaults to ‘’
Specifies the default value of the property.
-
class
kivy.properties.
ListProperty
(defaultvalue=0, **kw)¶ Bases:
kivy.properties.Property
Parameters: - defaultvalue: list, defaults to []
Specifies the default value of the property.
Warning
When assigning a list to a
ListProperty
, the list stored in the property is a shallow copy of the list and not the original list. This can be demonstrated with the following example:>>> class MyWidget(Widget): >>> my_list = ListProperty([]) >>> widget = MyWidget() >>> my_list = [1, 5, {'hi': 'hello'}] >>> widget.my_list = my_list >>> print(my_list is widget.my_list) False >>> my_list.append(10) >>> print(my_list, widget.my_list) [1, 5, {'hi': 'hello'}, 10] [1, 5, {'hi': 'hello'}]
However, changes to nested levels will affect the property as well, since the property uses a shallow copy of my_list.
>>> my_list[2]['hi'] = 'bye' >>> print(my_list, widget.my_list) [1, 5, {'hi': 'bye'}, 10] [1, 5, {'hi': 'bye'}]
-
link
(EventDispatcher obj, str name)¶
-
set
(EventDispatcher obj, value)¶
-
class
kivy.properties.
ObjectProperty
(defaultvalue=None, rebind=False, **kw)¶ Bases:
kivy.properties.Property
Parameters: - defaultvalue: object type
Specifies the default value of the property.
- rebind: bool, defaults to False
Whether kv rules using this object as an intermediate attribute in a kv rule, will update the bound property when this object changes.
That is the standard behavior is that if there’s a kv rule
text: self.a.b.c.d
, wherea
,b
, andc
are properties withrebind
False
andd
is aStringProperty
. Then when the rule is applied,text
becomes bound only tod
. Ifa
,b
, orc
change,text
still remains bound tod
. Furthermore, if any of them wereNone
when the rule was initially evaluated, e.g.b
wasNone
; thentext
is bound tob
and will not become bound tod
even whenb
is changed to not beNone
.By setting
rebind
toTrue
, however, the rule will be re-evaluated and all the properties rebound when that intermediate property changes. E.g. in the example above, wheneverb
changes or becomes notNone
if it wasNone
before,text
is evaluated again and becomes rebound tod
. The overall result is thattext
is now bound to all the properties amonga
,b
, orc
that haverebind
set toTrue
.- **kwargs: a list of keyword arguments
- baseclass
If kwargs includes a baseclass argument, this value will be used for validation: isinstance(value, kwargs[‘baseclass’]).
Warning
To mark the property as changed, you must reassign a new python object.
Changed in version 1.9.0: rebind has been introduced.
Changed in version 1.7.0: baseclass parameter added.
-
rebind
¶ rebind: ‘int’
-
class
kivy.properties.
BooleanProperty
(defaultvalue=True, **kw)¶ Bases:
kivy.properties.Property
Parameters: - defaultvalue: boolean
Specifies the default value of the property.
-
class
kivy.properties.
BoundedNumericProperty
(*largs, **kw)¶ Bases:
kivy.properties.Property
maximum bound – within a numeric range.
Parameters: - default: numeric
Specifies the default value of the property.
- **kwargs: a list of keyword arguments
If a min parameter is included, this specifies the minimum numeric value that will be accepted. If a max parameter is included, this specifies the maximum numeric value that will be accepted.
-
bounds
¶ Return min/max of the value.
New in version 1.0.9.
-
get_max
(EventDispatcher obj)¶ Return the maximum value acceptable for the BoundedNumericProperty in obj. Return None if no maximum value is set. Check
get_min
for a usage example.New in version 1.1.0.
-
get_min
(EventDispatcher obj)¶ Return the minimum value acceptable for the BoundedNumericProperty in obj. Return None if no minimum value is set:
class MyWidget(Widget): number = BoundedNumericProperty(0, min=-5, max=5) widget = MyWidget() print(widget.property('number').get_min(widget)) # will output -5
New in version 1.1.0.
-
set_max
(EventDispatcher obj, value)¶ Change the maximum value acceptable for the BoundedNumericProperty, only for the obj instance. Set to None if you want to disable it. Check
set_min
for a usage example.Warning
Changing the bounds doesn’t revalidate the current value.
New in version 1.1.0.
-
set_min
(EventDispatcher obj, value)¶ Change the minimum value acceptable for the BoundedNumericProperty, only for the obj instance. Set to None if you want to disable it:
class MyWidget(Widget): number = BoundedNumericProperty(0, min=-5, max=5) widget = MyWidget() # change the minimum to -10 widget.property('number').set_min(widget, -10) # or disable the minimum check widget.property('number').set_min(widget, None)
Warning
Changing the bounds doesn’t revalidate the current value.
New in version 1.1.0.
-
class
kivy.properties.
OptionProperty
(*largs, **kw)¶ Bases:
kivy.properties.Property
options.
If the string set in the property is not in the list of valid options (passed at property creation time), a ValueError exception will be raised.
Parameters: - default: any valid type in the list of options
Specifies the default value of the property.
- **kwargs: a list of keyword arguments
Should include an options parameter specifying a list (not tuple) of valid options.
For example:
class MyWidget(Widget): state = OptionProperty("None", options=["On", "Off", "None"])
-
options
¶ Return the options available.
New in version 1.0.9.
-
class
kivy.properties.
ReferenceListProperty
(*largs, **kw)¶ Bases:
kivy.properties.Property
For example, if x and y are
NumericProperty
s, we can create aReferenceListProperty
for the pos. If you change the value of pos, it will automatically change the values of x and y accordingly. If you read the value of pos, it will return a tuple with the values of x and y.For example:
class MyWidget(EventDispatcher): x = NumericProperty(0) y = NumericProperty(0) pos = ReferenceListProperty(x, y)
-
get
(EventDispatcher obj)¶
-
link
(EventDispatcher obj, str name)¶
-
link_deps
(EventDispatcher obj, str name)¶
-
set
(EventDispatcher obj, _value)¶
-
setitem
(EventDispatcher obj, key, value)¶
-
trigger_change
(EventDispatcher obj, value)¶
-
-
class
kivy.properties.
AliasProperty
(getter, setter=None, rebind=False, **kwargs)¶ Bases:
kivy.properties.Property
If you don’t find a Property class that fits to your needs, you can make your own by creating custom Python getter and setter methods.
Example from kivy/uix/widget.py where x and width are instances of
NumericProperty
:def get_right(self): return self.x + self.width def set_right(self, value): self.x = value - self.width right = AliasProperty(get_right, set_right, bind=['x', 'width'])
If x were a non Kivy property then you have to return True from setter to dispatch new value of right:
def set_right(self, value): self.x = value - self.width return True
Usually bind list should contain all Kivy properties used in getter method. If you return True it will cause a dispatch which one should do when the property value has changed, but keep in mind that the property could already have dispatched the changed value if a kivy property the alias property is bound was set in the setter, causing a second dispatch if the setter returns True.
If you want to cache the value returned by getter then pass cache=True. This way getter will only be called if new value is set or one of the binded properties changes. In both cases new value of alias property will be cached again.
To make property readonly pass None as setter. This way AttributeError will be raised on every set attempt:
right = AliasProperty(get_right, None, bind=['x', 'width'], cache=True)
Parameters: - getter: function
Function to use as a property getter.
- setter: function
Function to use as a property setter. Callbacks bound to the alias property won’t be called when the property is set (e.g. right = 10), unless the setter returns True.
- bind: list/tuple
Properties to observe for changes as property name strings. Changing values of this properties will dispatch value of the alias property.
- cache: boolean
If True, the value will be cached until one of the binded elements changes or if setter returns True.
- rebind: bool, defaults to False
See
ObjectProperty
for details.
Changed in version 1.9.0: rebind has been introduced.
Changed in version 1.4.0: Parameter cache added.
-
dispatch
(EventDispatcher obj)¶
-
get
(EventDispatcher obj)¶
-
link_deps
(EventDispatcher obj, str name)¶
-
rebind
¶ rebind: ‘int’
-
set
(EventDispatcher obj, value)¶
-
trigger_change
(EventDispatcher obj, value)¶
-
class
kivy.properties.
DictProperty
(defaultvalue=0, rebind=False, **kw)¶ Bases:
kivy.properties.Property
Parameters: - defaultvalue: dict, defaults to {}
Specifies the default value of the property.
- rebind: bool, defaults to False
See
ObjectProperty
for details.
Changed in version 1.9.0: rebind has been introduced.
Warning
Similar to
ListProperty
, when assigning a dict to aDictProperty
, the dict stored in the property is a shallow copy of the dict and not the original dict. SeeListProperty
for details.-
link
(EventDispatcher obj, str name)¶
-
rebind
¶ rebind: ‘int’
-
set
(EventDispatcher obj, value)¶
-
class
kivy.properties.
VariableListProperty
(defaultvalue=None, length=4, **kw)¶ Bases:
kivy.properties.Property
list items and to expand them to the desired list size.
For example, GridLayout’s padding used to just accept one numeric value which was applied equally to the left, top, right and bottom of the GridLayout. Now padding can be given one, two or four values, which are expanded into a length four list [left, top, right, bottom] and stored in the property.
Parameters: - default: a default list of values
Specifies the default values for the list.
- length: int, one of 2 or 4.
Specifies the length of the final list. The default list will be expanded to match a list of this length.
- **kwargs: a list of keyword arguments
Not currently used.
Keeping in mind that the default list is expanded to a list of length 4, here are some examples of how VariabelListProperty’s are handled.
- VariableListProperty([1]) represents [1, 1, 1, 1].
- VariableListProperty([1, 2]) represents [1, 2, 1, 2].
- VariableListProperty([‘1px’, (2, ‘px’), 3, 4.0]) represents [1, 2, 3, 4.0].
- VariableListProperty(5) represents [5, 5, 5, 5].
- VariableListProperty(3, length=2) represents [3, 3].
New in version 1.7.0.
-
length
¶ length: ‘int’
-
link
(EventDispatcher obj, str name)¶
-
class
kivy.properties.
ConfigParserProperty
(defaultvalue, section, key, config, **kw)¶ Bases:
kivy.properties.Property
of a
ConfigParser
as well as to bind the ConfigParser values to other properties.A ConfigParser is composed of sections, where each section has a number of keys and values associated with these keys. ConfigParserProperty lets you automatically listen to and change the values of specified keys based on other kivy properties.
For example, say we want to have a TextInput automatically write its value, represented as an int, in the info section of a ConfigParser. Also, the textinputs should update its values from the ConfigParser’s fields. Finally, their values should be displayed in a label. In py:
class Info(Label): number = ConfigParserProperty(0, 'info', 'number', 'example', val_type=int, errorvalue=41) def __init__(self, **kw): super(Info, self).__init__(**kw) config = ConfigParser(name='example')
The above code creates a property that is connected to the number key in the info section of the ConfigParser named example. Initially, this ConfigParser doesn’t exist. Then, in __init__, a ConfigParser is created with name example, which is then automatically linked with this property. then in kv:
BoxLayout: TextInput: id: number text: str(info.number) Info: id: info number: number.text text: 'Number: {}'.format(self.number)
You’ll notice that we have to do text: str(info.number), this is because the value of this property is always an int, because we specified int as the val_type. However, we can assign anything to the property, e.g. number: number.text which assigns a string, because it is instantly converted with the val_type callback.
Note
If a file has been opened for this ConfigParser using
read()
, thenwrite()
will be called every property change, keeping the file updated.Warning
It is recommend that the config parser object be assigned to the property after the kv tree has been constructed (e.g. schedule on next frame from init). This is because the kv tree and its properties, when constructed, are evaluated on its own order, therefore, any initial values in the parser might be overwritten by objects it’s bound to. So in the example above, the TextInput might be initially empty, and if number: number.text is evaluated before text: str(info.number), the config value will be overwritten with the (empty) text value.
Parameters: - default: object type
Specifies the default value for the key. If the parser associated with this property doesn’t have this section or key, it’ll be created with the current value, which is the default value initially.
- section: string type
The section in the ConfigParser where the key / value will be written. Must be provided. If the section doesn’t exist, it’ll be created.
- key: string type
The key in section section where the value will be written to. Must be provided. If the key doesn’t exist, it’ll be created and the current value written to it, otherwise its value will be used.
- config: string or
ConfigParser
instance. The ConfigParser instance to associate with this property if not None. If it’s a string, the ConfigParser instance whose
name
is the value of config will be used. If no such parser exists yet, whenever a ConfigParser with this name is created, it will automatically be linked to this property.Whenever a ConfigParser becomes linked with a property, if the section or key doesn’t exist, the current property value will be used to create that key, otherwise, the existing key value will be used for the property value; overwriting its current value. You can change the ConfigParser associated with this property if a string was used here, by changing the
name
of an existing or new ConfigParser instance. Or throughset_config()
.- **kwargs: a list of keyword arguments
- val_type: a callable object
The key values are saved in the ConfigParser as strings. When the ConfigParser value is read internally and assigned to the property or when the user changes the property value directly, if val_type is not None, it will be called with the new value as input and it should return the value converted to the proper type accepted ny this property. For example, if the property represent ints, val_type can simply be int.
If the val_type callback raises a ValueError, errorvalue or errorhandler will be used if provided. Tip: the getboolean function of the ConfigParser might also be useful here to convert to a boolean type.
- verify: a callable object
Can be used to restrict the allowable values of the property. For every value assigned to the property, if this is specified, verify is called with the new value, and if it returns True the value is accepted, otherwise, errorvalue or errorhandler will be used if provided or a ValueError is raised.
New in version 1.9.0.
-
link_deps
(EventDispatcher obj, str name)¶
-
set
(EventDispatcher obj, value)¶
-
set_config
(config)¶ Sets the ConfigParser object to be used by this property. Normally, the ConfigParser is set when initializing the Property using the config parameter.
Parameters: - config: A
ConfigParser
instance. The instance to use for listening to and saving property value changes. If None, it disconnects the currently used ConfigParser.
class MyWidget(Widget): username = ConfigParserProperty('', 'info', 'name', None) widget = MyWidget() widget.property('username').set_config(ConfigParser())
- config: A