Small corrections and improvements to the docs, 'guide2/events.rst'.

This commit is contained in:
Zen-CODE 2013-03-16 21:46:23 -05:00
parent 0aca105887
commit 71e98b6f20
1 changed files with 67 additions and 67 deletions

View File

@ -4,32 +4,31 @@
Events and Properties
=====================
Events are a big part of kivy programming, that may not be surprising to those
having done GUI development before, but it's an important concept to get for
newcomers, and the specifics of how to use these in kivy. Once you understand
how events and ways to bind to them, are everywhere in kivy, it becomes easy to
build about whatever you want with kivy.
Events are an important part of kivy programming. That may not be surprising to those
with GUI development experience, but it's an important concept for
newcomers. Once you understand how events work and how to bind to them,
you will see them everywhere in kivy. They make it easy to
build whatever behaviour you want into kivy.
The following illustration tries to represent the relationship between the
events and the rest of kivy.
The following illustration shows how events are handled in the kivy framework.
.. image:: images/Events.*
Introduction to Event Dispatcher
--------------------------------
Introduction to the Event Dispatcher
------------------------------------
One of the most important base classes of the framework is the
:class:`~kivy.event.EventDispatcher` class, this class allows to register event
types, and to dispatch them to interested parties (usually other event
dispatchers). :class:`~kivy.uix.widget.Widget`,
:class:`~kivy.animation.Animation` and :obj:`~kivy.clock.Clock` for example are
event dispatchers.
:class:`~kivy.event.EventDispatcher` class. This class allows you to register
event types, and to dispatch them to interested parties (usually other event
dispatchers). The :class:`~kivy.uix.widget.Widget`,
:class:`~kivy.animation.Animation` and :obj:`~kivy.clock.Clock` classes are
examples of event dispatchers.
Creating custom events
----------------------
To create an event dispatcher with custom events, you need to register the name
of the event in the class, and to create a method of the same name.
of the event in the class and then create a method of the same name.
See the following example::
@ -50,13 +49,13 @@ See the following example::
Attaching callbacks
-------------------
To use events, you have to bind callbacks to them, when the event is
dispatched, your callbacks will be called with the various data the event has
to pass around.
To use events, you have to bind callbacks to them. When the event is
dispatched, your callbacks will be called with the parameters relevant to
that specific event.
A callback can be any python callable, but you need to be sure it can accept
the arguments the event will use, for this, it's usually safer to accept the
`*args` argument, that will catch any remaining arguments in the `args` list.
A callback can be any python callable, but you need to ensure it accepts
the arguments that the event emits. For this, it's usually safest to accept the
`*args` argument, which will catch all arguments in the `args` list.
Example::
@ -72,12 +71,12 @@ Example::
Introduction to properties
--------------------------
Properties are an awesome way to define events and bind to them, it basically
produce events when the attributes of your object changes, so you can bind
actions to the change of these values.
Properties are an awesome way to define events and bind to them. Essentially,
they produce events such that when an attribute of your object changes,
all properties that reference that attribute are automatically updated.
There are different kind of properties to describe the type of data you want to
describe.
There are different kinds of properties to describe the type of data you want to
handle.
- :class:`~kivy.properties.StringProperty`
- :class:`~kivy.properties.NumericProperty`
@ -94,9 +93,9 @@ describe.
Declaration of a Property
-------------------------
To declare a property, you must create it at class level, the class will do the
work to instantiate the real attributes when the object will be created, the
properties is not the attribute, it's a mechanism to create events for your
To declare properties, you must declare them at the class level. The class will then do
the work to instantiate the real attributes when your object is created. These properties
are not attributes: they are mechanisms for creating events based on your
attributes::
class MyWidget(Widget):
@ -104,8 +103,8 @@ attributes::
text = StringProperty('')
When overriding `__init__`, *always* accept `**kwargs` and use super() to call
the parents `__init__` with it::
When overriding `__init__`, *always* accept `**kwargs` and use `super()` to call
the parents `__init__` method, passing in your class instance::
def __init__(self, **kwargs):
super(MyWidget, self).__init__(**kwargs)
@ -114,14 +113,14 @@ the parents `__init__` with it::
Dispatching a Property event
----------------------------
Kivy properties by default provide a on_<property_name> event. This event is
Kivy properties, by default, provide an `on_<property_name>` event. This event is
called when the value of the property is changed.
.. note::
if the new value for the property is equal to the older value then the
on_<property_name> event will not be called.
If the new value for the property is equal to the current value, then the
`on_<property_name>` event will not be called.
For example consider the following code.
For example, consider the following code:
.. code-block:: python
:linenos:
@ -139,13 +138,13 @@ For example consider the following code.
def on_pressed(self, instance, pos):
print ('pressed at {pos}'.format(pos=pos))
In the code above at line: 3 ::
In the code above at line 3::
pressed = ListProperty([0, 0])
We define `pressed` Property of type :class:`~kivy.properties.ListProperty`,
giving it a default value of `[0, 0]`. from this point on-wards the `on_pressed`
event will be called when ever the value of this property is changed.
We define the `pressed` Property of type :class:`~kivy.properties.ListProperty`,
giving it a default value of `[0, 0]`. From this point onwards, the `on_pressed`
event will be called whenever the value of this property is changed.
At Line 5::
@ -155,39 +154,39 @@ At Line 5::
return True
return super(CustomBtn, self).on_touch_down(touch)
We override the :meth:`on_touch_down` method of the Widget class. Here we check
We override the :meth:`on_touch_down` method of the Widget class. Here, we check
for collision of the `touch` with our widget.
If it falls inside our widget, we change the value of `pressed` to touch.pos
and return True indicating that we have consumed the touch and don't want it
propagating any further.
If the touch falls inside of our widget, we change the value of `pressed` to touch.pos
and return True, indicating that we have consumed the touch and don't want it
propagate any further.
Then finally if the touch falls outside our widget, we call the original event
using super(...)... and return the result so as to allow propagation of touch
to continue as it would otherwise have.
Finally, if the touch falls outside our widget, we call the original event
using `super(...)` and return the result. This allows the touch event propagation
to continue as it would normally have occured.
Finally on line 11::
def on_pressed(self, instance, pos):
print ('pressed at {pos}'.format(pos=pos))
We define `on_pressed` function that will be called by the property whenever the
We define an `on_pressed` function that will be called by the property whenever the
property value is changed.
.. Note::
This `on_<prop_name>` event is called within the class that the property is
defined in. To monitor/observe the change to a property outside of a class
it's defined in you should bind to the property.
it's defined in, you should bind to the property.
**Binding to the property**
How to monitor changes to a property when all you have access to is a widget's
instance? You Bind to the property::
instance? You *bind* to the property::
your_widget_instance.bind(property_name=function_name)
For example consider the following code.
For example, consider the following code:
.. code-block:: python
:linenos:
@ -205,7 +204,7 @@ For example consider the following code.
def btn_pressed(self, instance, pos):
print ('pos: printed from root widget: {pos}'.format(pos=.pos))
If you run the code as is you will notice two print statements in the console.
If you run the code as is, you will notice two print statements in the console.
One from the `on_pressed` event that is called inside the `CustomBtn` class and
one from the `btn_pressed` function that we bind to the property change.
@ -213,15 +212,15 @@ The reason that both the functions are called is simple. Binding doesn't mean
overriding. Having both of these functions is redundant and you should generally
only use one of the methods of listening/reacting to property changes.
You should also take note about the parameters that are passed to the
on_<property_name> event or the function bound to the property.
You should also take note of the parameters that are passed to the
`on_<property_name>` event or the function bound to the property.
.. code-block:: python
def btn_pressed(self, instance, pos):
The first parameter is self which is the instance of the class this function is
defined in. If you use a in-line function like so.
The first parameter is `self`, which is the instance of the class this function is
defined in. You can use an in-line function as follows:
.. code-block:: python
:linenos:
@ -234,13 +233,13 @@ defined in. If you use a in-line function like so.
cb.bind(pressed=_local_func)
self.add_widget(cb)
Then the first parameter would be `instance` of the class the property is
The first parameter would be `instance` of the class the property is
defined in.
The last parameter is the `value` which is the new value of the property.
The second parameter would be the `value`, which is the new value of the property.
This is the complete runnable code derived from the snippets above that you can
use to copy and paste into a editor to experiment with.
Here is the complete example, derived from the snippets above, that you can
use to copy and paste into an editor to experiment with.
.. code-block:: python
:linenos:
@ -289,18 +288,19 @@ use to copy and paste into a editor to experiment with.
TestApp().run()
Running the code above will give you the following output.
Our CustomBtn has no visual representation and thus appears black. You can
touch/click on the black area to see the output on your console
Running the code above will give you the following output:
.. image:: images/property_events_binding.png
Some Gotchas in AliasProperty and ReferenceListProperty.
Our CustomBtn has no visual representation and thus appears black. You can
touch/click on the black area to see the output on your console.
While defining a AliasProperty you normally define a getter and a setter
function yourself. Here It falls on to you to define when the getter and the
setter functions are called using the `bind` argument.
Some Gotchas in :class:`~kivy.properties.AliasProperty` and
:class:`~kivy.properties.ReferenceListProperty`.
When defining an :class:`~kivy.properties.AliasProperty`, you normally define
a getter and a setter functions yourself. Here, it falls on to you to define
when the getter and the setter functions are called using the `bind` argument.
Consider the following code.