事件分发器

Kivy 中所有产生事件的对象都实现了 EventDispatcher,该类为注册和操作事件处理器提供了一致的接口。

在 1.0.9 版本发生变更: 属性发现和方法已从 Widget 移至 EventDispatcher

class kivy.event.EventDispatcher(**kwargs)

基类:ObjectWithUid

请参阅模块文档字符串以了解用法。

apply_property(self, **kwargs)

在运行时向类添加属性。该函数接受形式为 prop_name=prop 的关键字参数,其中 prop 是一个 Property 实例,prop_name 是属性的属性名。

在 1.9.1 版本加入.

警告

此方法不建议用于常规用途,因为您应该在类中声明属性,而不是使用此方法。

例如:

>>> print(wid.property('sticks', quiet=True))
None
>>> wid.apply_property(sticks=ObjectProperty(55, max=10))
>>> print(wid.property('sticks', quiet=True))
<kivy.properties.ObjectProperty object at 0x04303130>
bind(self, **kwargs)

将事件类型或属性绑定到回调函数。

用法:

# With properties
def my_x_callback(obj, value):
    print('on object', obj, 'x changed to', value)
def my_width_callback(obj, value):
    print('on object', obj, 'width changed to', value)
self.bind(x=my_x_callback, width=my_width_callback)

# With event
def my_press_callback(obj):
    print('event on object', obj)
self.bind(on_press=my_press_callback)

一般来说,属性回调会接收两个参数(对象和属性的新值),而事件回调则接收一个参数(对象)。上述示例正好说明了这一点。

以下示例展示了在一个完整应用程序中使用bind函数的各种方式:

from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.uix.button import Button
from functools import partial


class DemoBox(BoxLayout):
    """
    This class demonstrates various techniques that can be used for binding to
    events. Although parts could me made more optimal, advanced Python concepts
    are avoided for the sake of readability and clarity.
    """
    def __init__(self, **kwargs):
        super(DemoBox, self).__init__(**kwargs)
        self.orientation = "vertical"

        # We start with binding to a normal event. The only argument
        # passed to the callback is the object which we have bound to.
        btn = Button(text="Normal binding to event")
        btn.bind(on_press=self.on_event)

        # Next, we bind to a standard property change event. This typically
        # passes 2 arguments: the object and the value
        btn2 = Button(text="Normal binding to a property change")
        btn2.bind(state=self.on_property)

        # Here we use anonymous functions (a.k.a lambdas) to perform binding.
        # Their advantage is that you can avoid declaring new functions i.e.
        # they offer a concise way to "redirect" callbacks.
        btn3 = Button(text="Using anonymous functions.")
        btn3.bind(on_press=lambda x: self.on_event(None))

        # You can also declare a function that accepts a variable number of
        # positional and keyword arguments and use introspection to determine
        # what is being passed in. This is very handy for debugging as well
        # as function re-use. Here, we use standard event binding to a function
        # that accepts optional positional and keyword arguments.
        btn4 = Button(text="Use a flexible function")
        btn4.bind(on_press=self.on_anything)

        # Lastly, we show how to use partial functions. They are sometimes
        # difficult to grasp, but provide a very flexible and powerful way to
        # reuse functions.
        btn5 = Button(text="Using partial functions. For hardcores.")
        btn5.bind(on_press=partial(self.on_anything, "1", "2", monthy="python"))

        for but in [btn, btn2, btn3, btn4, btn5]:
            self.add_widget(but)

    def on_event(self, obj):
        print("Typical event from", obj)

    def on_property(self, obj, value):
        print("Typical property change from", obj, "to", value)

    def on_anything(self, *args, **kwargs):
        print('The flexible function has *args of', str(args),
            "and **kwargs of", str(kwargs))


class DemoApp(App):
    def build(self):
        return DemoBox()

if __name__ == "__main__":
    DemoApp().run()

如果某个回调已经绑定到了特定的事件或属性上,那么它不会被再次添加。

当将方法绑定到事件或属性时,会保存回调的 kivy.weakmethod.WeakMethod。也就是说,它存储的不是常规引用,而是对实例的弱引用(参见 Python 的 weakref)。

这有两个后果。

首先,绑定不会阻止方法所属对象的垃圾回收。客户端必须在所需生命周期内保持对该实例的引用。如果回调引用变得无效,它将被静默移除。

第二点是,当使用装饰器方法时,例如::

@my_decorator
def callback(self, *args):
    pass

这里的装饰器(此处为 my_decorator)必须在内部使用 wraps

create_property(self, unicode name, value=None, default_value=True, *largs, **kwargs)

在运行时创建一个新属性。

在 1.0.9 版本加入.

在 1.8.0 版本发生变更: 新增了 value 参数,可用于设置属性的默认值。同时,该值的类型用于特化所创建的属性。

在 1.9.0 版本发生变更: 过去,如果`value`的类型是`bool`,会创建一个`NumericProperty`,现在则会创建一个`BooleanProperty`。

此外,现在创建属性时,位置参数和关键字参数也会传递给该属性。

在 2.0.0 版本发生变更: default_value 已添加。

警告

此函数专为Kivy语言设计,请勿在您的代码中使用。您应在类中声明属性,而非使用此方法。

参数:
name:字符串

属性的名称

value:对象,可选

属性的默认值。该类型也用于创建更合适的属性类型。默认为None。

default_value:布尔值,默认为 True

如果为True,则`value`将成为该属性的默认值。否则,该属性将使用其类型正常的默认值进行初始化,随后再设置为``value``。

>>> mywidget = Widget()
>>> mywidget.create_property('custom')
>>> mywidget.custom = True
>>> print(mywidget.custom)
True
dispatch(self, event_type, *largs, **kwargs)

在 bind/fbind() 中添加的所有处理器之间分发事件。一旦某个处理器返回 True,分发即停止。

该函数收集所有位置参数和关键字参数,并将它们传递给处理程序。

备注

处理程序被调用的顺序与它们通过 bind() 注册时的顺序相反。

参数:
event_type: str

要分发的事件名称。

在 1.9.0 版本发生变更: 新增了关键字参数的收集与转发功能。此前,仅支持收集和转发位置参数。

dispatch_children(self, event_type, *largs, **kwargs)
dispatch_generic(self, event_type, *largs, **kwargs)
events(self)

返回该类中的所有事件。可用于内省。

在 1.8.0 版本加入.

fbind(self, name, func, *largs, **kwargs)

一种高级且通常更快的绑定方法。此方法与 bind() 不同,面向更高级的用户及内部使用。只要遵循以下几点,即可使用。

  1. bind() 不同,它不会检查该函数及参数/关键字参数是否已绑定到此名称。因此,多次绑定同一回调只会不断添加它。

  2. 尽管 bind() 在绑定到事件或属性时会为回调创建一个 WeakMethod,但此方法直接存储回调,除非提供了值为 True 的关键字参数 ref,此时会保存一个 WeakMethod。这在直接存储回调不会导致内存泄漏风险的情况下非常有用。

  3. 如果找到并绑定了`name`,此方法返回一个唯一的正数;否则返回`0`。与:meth:`bind`不同,当属性`name`未找到时,它不会抛出异常。如果返回值不为零,则返回的uid对于该`name`和回调是唯一的,可用于:meth:`unbind_uid`进行解绑。

当使用largs和/或kwargs绑定回调时,必须使用:meth:funbind`进行解绑。如果未提供largs和kwargs,也可以使用:meth:`unbind。在两种情况下,都可以使用:meth:unbind_uid

该方法会将捕获到的所有位置参数和/或关键字参数传递给回调函数,从而无需调用 partial。在调用回调时,展开的 *args 会先传递,随后是 instance/value`(对于关键字参数仅为 `instance),最后是展开的 **kwargs

以下是类似于 bind() 中示例的使用示例:

class DemoBox(BoxLayout):

    def __init__(self, **kwargs):
        super(DemoBox, self).__init__(**kwargs)
        self.orientation = "vertical"

        btn = Button(text="Normal binding to event")
        btn.fbind('on_press', self.on_event)

        btn2 = Button(text="Normal binding to a property change")
        btn2.fbind('state', self.on_property)

        btn3 = Button(text="A: Using function with args.")
        btn3.fbind('on_press', self.on_event_with_args, 'right',
                       tree='birch', food='apple')

        btn4 = Button(text="Unbind A.")
        btn4.fbind('on_press', self.unbind_a, btn3)

        btn5 = Button(text="Use a flexible function")
        btn5.fbind('on_press', self.on_anything)

        btn6 = Button(text="B: Using flexible functions with args. For hardcores.")
        btn6.fbind('on_press', self.on_anything, "1", "2", monthy="python")

        btn7 = Button(text="Force dispatch B with different params")
        btn7.fbind('on_press', btn6.dispatch, 'on_press', 6, 7, monthy="other python")

        for but in [btn, btn2, btn3, btn4, btn5, btn6, btn7]:
            self.add_widget(but)

    def on_event(self, obj):
        print("Typical event from", obj)

    def on_event_with_args(self, side, obj, tree=None, food=None):
        print("Event with args", obj, side, tree, food)

    def on_property(self, obj, value):
        print("Typical property change from", obj, "to", value)

    def on_anything(self, *args, **kwargs):
        print('The flexible function has *args of', str(args),
            "and **kwargs of", str(kwargs))
        return True

    def unbind_a(self, btn, event):
        btn.funbind('on_press', self.on_event_with_args, 'right',
                        tree='birch', food='apple')

备注

由于kv语言使用此方法进行绑定,因此在创建基于非:class:EventDispatcher`的类并与kv语言一起使用时,必须实现此方法,而不是使用:meth:`bind。参见:class:`Observable`中的示例。

在 1.9.0 版本加入.

在 1.9.1 版本发生变更: ref 关键字参数已添加。

funbind(self, name, func, *largs, **kwargs)

类似于 fbind()

在解绑时,unbind() 会解绑所有匹配的回调,而此方法仅解绑第一个。

要解除绑定,必须将传递给 fbind() 的相同位置参数和关键字参数传递给 funbind。

备注

只要在调用 funbind() 时未提供关键字参数和位置参数,就可以安全地使用它来解绑通过 bind() 绑定的函数。

在 1.9.0 版本加入.

get_property_observers(self, name, args=False)

返回绑定到作为*name*参数传入的属性/事件的方法列表:

widget_instance.get_property_observers('on_release')
参数:
name:字符串

事件或属性的名称。

args:布尔值

是否返回绑定的参数。为了保持兼容性,当 argsFalse 时,列表中仅返回回调函数,而不包含它们提供的参数。

如果为 True,则列表中的每个元素都是一个 5 元组 (callback, largs, kwargs, is_ref, uid),其中 is_ref 表示 callback 是否为弱引用,uid 是由 fbind() 提供的 uid,如果使用 bind() 则为 None。默认为 False

返回:

绑定的回调函数列表。详情请参阅 args

在 1.8.0 版本加入.

在 1.9.0 版本发生变更: args 已添加。

getter(self, name)

返回属性的getter。

在 1.0.9 版本加入.

is_event_type(self, event_type)

如果 event_type 已经注册,则返回 True。

在 1.0.4 版本加入.

properties(self) dict

以键/属性类的字典形式返回类中的所有属性。可用于内省。

在 1.0.9 版本加入.

property(self, name, quiet=False)

根据属性名获取属性实例。如果 quietTrue,当 name 不是属性时,返回 None 而不是抛出异常。默认值为 False

在 1.0.9 版本加入.

返回:

与名称对应的 Property 派生实例。

在 1.9.0 版本发生变更: 已添加 quiet。

proxy_ref

返回一个指向 EventDispatcherWeakProxy 引用。

在 1.9.0 版本加入.

在 2.0.0 版本发生变更: 之前它只是返回自身,现在它实际上返回一个 WeakProxy

register_event_type(self, event_type)

向调度器注册一个事件类型。

注册事件类型允许调度器在附加事件处理器时验证其名称,并在附加的对象中搜索合适的处理器。每个事件类型的声明必须:

  1. on_ 前缀开头。

  2. 在类中有一个默认处理器。

自定义事件创建示例:

class MyWidget(Widget):
    def __init__(self, **kwargs):
        super(MyWidget, self).__init__(**kwargs)
        self.register_event_type('on_swipe')

    def on_swipe(self):
        pass

def on_swipe_callback(*largs):
    print('my swipe is called', largs)
w = MyWidget()
w.dispatch('on_swipe')
setter(self, name)

返回属性的setter。用法:instance.setter('name')。这个setter是一个便捷的回调函数,适用于直接绑定一个属性到另一个属性的场景。它返回一个部分函数,该函数接受`(obj, value)`参数,并将`instance`的`'name'属性设置为`value

在 1.0.9 版本加入.

例如,要在Python中将number2绑定到number1,你可以这样做:

class ExampleWidget(Widget):
    number1 = NumericProperty(None)
    number2 = NumericProperty(None)

    def __init__(self, **kwargs):
        super(ExampleWidget, self).__init__(**kwargs)
        self.bind(number1=self.setter('number2'))

这等同于kv绑定:

<ExampleWidget>:
    number2: self.number1
unbind(self, **kwargs)

使用与 bind() 类似的方式,从回调函数中解绑属性。

如果某个回调被多次绑定到同一事件或属性上,仅首次绑定的回调会被解除绑定。

备注

只要函数最初绑定时不带任何关键字和位置参数,那么在通过 fbind() 绑定的函数上使用 unbind() 是安全的。否则,该函数将无法解绑,此时应改用 funbind()

unbind_uid(self, name, uid)

使用 fbind() 返回的 uid 来解绑回调。

此方法比 funbind() 高效得多。如果 uid 的值为假(例如 0),则会引发 ValueError。此外,只有通过 fbind() 绑定的回调才能使用此方法解除绑定。

由于每次调用 fbind() 都会生成一个唯一的 uid,因此只会移除一个回调。如果在回调中未找到 uid,不会引发任何错误。

例如:

btn6 = Button(text="B: Using flexible functions with args. For hardcores.")
uid = btn6.fbind('on_press', self.on_anything, "1", "2", monthy="python")
if not uid:
    raise Exception('Binding failed').
...
btn6.unbind_uid('on_press', uid)

在 1.9.0 版本加入.

unregister_event_type(self, event_type)

在调度器中注销一个事件类型。

在 2.1.0 版本发生变更: 方法名从 unregister_event_types 改为 unregister_event_type

unregister_event_types(self, event_type)
class kivy.event.ObjectWithUid

基类:object

(内部)此类用于为类实例提供唯一标识符。它并非设计用于直接使用。

class kivy.event.Observable

基类:ObjectWithUid

Observable 是一个存根类,定义了绑定所需的方法。EventDispatcher 是实现绑定接口的类的一个示例。详见 EventDispatcher

在 1.9.0 版本加入.

bind(self, **kwargs)
fbind(self, name, func, *largs, **kwargs)

参见 EventDispatcher.fbind()

备注

为了保持与之前可能继承自 Observable 的派生类的向后兼容性,添加了 fbind() 方法。fbind() 的默认实现是创建一个部分函数,并将其传递给 bind,同时保存 uid 和 largs/kwargs。然而,funbind`(以及 :meth:`unbind_uid())的效率相对较低,因为我们必须首先使用 largs/kwargs 或 uid 查找这个部分函数,然后对返回的函数调用 unbind()。建议在派生类中重写这些方法,直接进行绑定以获得更好的性能。

EventDispatcher.fbind() 类似,此方法在失败时返回 0,在成功时返回一个正数的唯一 uid。该 uid 可用于 unbind_uid()

funbind(self, name, func, *largs, **kwargs)

参见 fbind()EventDispatcher.funbind()

unbind(self, **kwargs)
unbind_uid(self, name, uid)

参见 fbind()EventDispatcher.unbind_uid()