运动事件

MotionEvent 是指点设备(触摸和非触摸)所提供事件的基础类。该类定义了处理二维和三维运动所需的所有属性和方法,但还具备更多功能。

通常你不需要自己创建 MotionEvent,因为这是 providers 的职责。

运动事件流程

  1. : MotionEventEventLoopBase 从输入提供者处收集。

  2. 后处理由已注册的处理器 postproc 执行。

  3. EventLoopBase 通过 on_motion 事件将所有运动事件分发给所有已注册的监听器,包括 WindowBase

  4. 一旦在 on_motion() 事件中接收到(触摸或非触摸),所有已注册的管理器都会处理这些事件。如果触摸事件未被至少一个管理器处理,则它会通过 on_touch_down()on_touch_move()on_touch_up() 进行分发。

  5. Widgets 在 on_motion() 方法中接收事件(如果由管理器传递),或者在 on_touch_xxx 方法中接收事件。

运动事件与事件管理器

运动事件如果其 MotionEvent.is_touch 属性被设置为 True,则视为触摸事件。除了 is_touch 属性外,还可以使用 MotionEvent.type_id 来检查事件的通用类型。目前,输入提供者会分发两种类型的事件:“touch”和“hover”。

事件管理器可用于在整个控件树中分发任何运动事件,管理器通过 type_id 来指定其希望接收的事件类型。请参阅 eventmanager 了解如何定义和注册事件管理器。

管理器还可以在将事件分发给控件之前,为 MotionEvent.type_id 分配一个新的 type_id。这在分派特定事件时非常有用,例如:

class MouseTouchManager(EventManagerBase):

    type_ids = ('touch',)

    def dispatch(self, etype, me):
        accepted = False
        if me.device == 'mouse':
            me.push() # Save current type_id and other values
            me.type_id = 'mouse_touch'
            self.window.transform_motion_event_2d(me)
            # Dispatch mouse touch event to widgets which registered
            # to receive 'mouse_touch'
            for widget in self.window.children[:]:
                if widget.dispatch('on_motion', etype, me):
                    accepted = True
                    break
            me.pop() # Restore
        return accepted

监听运动事件

如果你希望接收所有运动事件,无论是否为触摸事件,可以将 Window 中的 MotionEvent 绑定到你自己的回调函数中,如下所示:

def on_motion(self, etype, me):
    # will receive all motion events.
    pass

Window.bind(on_motion=on_motion)

你也可以通过监听 mouse_pos 来获取鼠标位置的变化。

配置文件

:类 MotionEventprofile 中列出的各种属性中存储设备特定信息。例如,您可以接收到一个具有角度、基准ID甚至形状的 MotionEvent。您可以检查 profile 属性,以了解 MotionEvent 提供程序当前支持哪些内容。

以下是默认支持的配置文件值的简短列表。请检查 MotionEvent.profile 属性以查看可用的配置文件值。

配置文件值

描述

角度

2D 角度。通过 a 属性访问。

按钮

鼠标按钮('left'、'right'、'middle'、'scrollup' 或 'scrolldown')。通过 button 属性访问。

markerid

标记或基准点ID。通过`fid`属性访问。

位置

2D位置。可通过 xypos 属性访问。

pos3d

3D位置。可通过 xyz 属性访问。

压力

接触压力。通过 pressure 属性访问。

形状

接触形状。通过 shape 属性访问。

如果您想知道当前的 MotionEvent 是否具有角度:

def on_touch_move(self, touch):
    if 'angle' in touch.profile:
        print('The touch angle is', touch.a)

如果您只想选择 fiducials:

def on_touch_move(self, touch):
    if 'markerid' not in touch.profile:
        return
class kivy.input.motionevent.MotionEvent(device, id, args, is_touch=False, type_id=None)[源代码]

基类:MotionEvent

表示输入事件的抽象类。

参数:
id:字符串

MotionEvent 的唯一标识符。

args:列表

传递给depack()函数的参数列表

apply_transform_2d(transform)[源代码]

对 x、y、z、px、py、pz、ox、oy、oz、dx、dy、dz 应用变换。

button

当前按下的按钮。

copy_to(to)[源代码]

将某些属性复制到另一个运动事件对象中。

depack(args)[源代码]

args 解包为类的属性。

device

用于创建此事件的设备。

dispatch_done()[源代码]

通知分发到监听器已完成。

EventLoopBase.post_dispatch_input() 调用。

在 2.1.0 版本加入.

dispatch_mode

(实验性)由事件管理器或控件用于指定分发模式。默认值为 MODE_DEFAULT_DISPATCH。有关可用模式,请参阅 eventmanager

在 2.1.0 版本加入.

distance(other_touch)[源代码]

返回两个事件之间的距离。

double_tap_time

如果触摸是 is_double_tap,则这是上一次点击与当前触摸之间的时间。

property dpos

返回屏幕坐标系中最后位置与当前位置之间的差值(self.dx, self.dy)。

dsx

self.sx 与 self.psx 之间的差值,范围在 0 到 1 之间。

dsy

self.sy 与 self.psy 之间的差值,范围在 0-1 之间。

dsz

self.sz 与 self.psz 之间的差值,范围在 0-1 之间。

dx

self.x 与 self.px 之间的差值,在窗口范围内。

dy

self.y 与 self.py 之间的差值,处于窗口范围内。

dz

self.z 与 self.pz 之间的差值,位于窗口范围内。

grab(class_instance, exclusive=False)[源代码]

抓取此运动事件。

如果这是一个触摸事件,你可以抓取它,以便接收后续的 on_touch_move()on_touch_up() 事件,即使该触摸不是由父级分发的。

def on_touch_down(self, touch):
    touch.grab(self)

def on_touch_move(self, touch):
    if touch.grab_current is self:
        # I received my grabbed touch
    else:
        # it's a normal touch

def on_touch_up(self, touch):
    if touch.grab_current is self:
        # I receive my grabbed touch, I must ungrab it!
        touch.ungrab(self)
    else:
        # it's a normal touch
        pass

在 2.1.0 版本发生变更: 允许非触摸事件进行抓取。

grab_current

用于确定事件被分发到哪个控件。更多信息请参阅 grab() 函数。

id

事件的ID,并非唯一。这通常是由输入提供者设置的ID,如TUIO中的ID。如果你有多个TUIO源,那么相同的ID可能会被使用。建议优先使用:attr:`uid`属性。

is_double_tap

指示触摸事件是否为双击。

property is_mouse_scrolling

如果触摸事件是鼠标滚轮滚动,则返回 True。

在 1.6.0 版本加入.

is_touch

如果MotionEvent是触摸事件,则为True。

is_triple_tap

指示该触摸事件是否为三次点击。

在 1.7.0 版本加入.

move(args)[源代码]

移动到另一个位置。

property opos

返回运动事件在屏幕坐标系中的初始位置(self.ox, self.oy)。

osx

原点X位置,范围在0-1之间。

osy

原点Y位置,范围在0-1之间。

osz

原点Z位置,范围在0-1之间。

ox

窗口范围内的原点X坐标。

oy

窗口范围内的原点Y位置。

oz

窗口范围内的原始Z轴位置。

pop()[源代码]

从堆栈中弹出属性值。

pos

窗口范围内的位置(X,Y)。

property ppos

返回运动事件在屏幕坐标系中的上一个位置(self.px, self.py)。

profile

事件中当前使用的配置文件。

psx

之前的X位置,范围在0-1之间。

psy

之前的Y位置,范围在0-1之间。

psz

之前的Z位置,范围在0-1之间。

push(attrs=None)[源代码]

attrs 中的属性值压入栈中。

push_attrs_stack

默认情况下,当我们使用 push() 时,需要推送的属性有:x、y、z、dx、dy、dz、ox、oy、oz、px、py、pz。

px

之前的X位置,在窗口范围内。

py

之前的Y位置,位于窗口范围内。

pz

之前的Z位置,在窗口范围内。

scale_for_screen(w, h, p=None, rotation=0, smode='None', kheight=0)[源代码]

屏幕缩放位置。

在 2.1.0 版本发生变更: xyz 的最大值分别改为 w - 1、h - 1 和 p - 1。

shape

触摸事件的形状,是 Shape 的子类。默认情况下,该属性设置为 None。

property spos

返回在0-1坐标系中的位置(self.sx, self.sy)。

sx

X 位置,范围在 0-1 之间。

sy

Y 位置,范围为 0-1。

sync_with_dispatch

如果设置为 True`(默认值),则保留第一个先前位置(X、Y、Z 在 0-1 范围内),并忽略所有其他位置,直到从 `EventLoop 调用 MotionEvent.dispatch_done() 为止。

该属性是必需的,因为事件提供者可以对 MotionEvent.move() 进行多次调用,但对于所有这些调用,事件仅向监听器分发一次。将值设为 False 将保留最新的先前位置。参见 MotionEvent.move()

在 2.1.0 版本加入.

sz

Z 位置,范围在 0-1 之间。

time_end

结束事件的时间(最后一次事件使用的时间)。

time_start

事件创建的初始时间。

time_update

最后一次更新的时间。

to_absolute_pos(nx, ny, x_max, y_max, rotation)[源代码]

使用`x_max`、`y_max`和`rotation`将归一化(0-1)坐标`nx`和`ny`转换为绝对坐标。

引发:

ValueError:如果 rotation 不是以下值之一:0、90、180 或 270。

在 2.1.0 版本加入.

triple_tap_time

如果触摸是 is_triple_tap,则这是第一次点击与当前触摸之间的时间。

在 1.7.0 版本加入.

type_id

(实验性)用于标识事件类型的字符串。

在 2.1.0 版本加入.

ud

用户数据字典。使用此字典在事件上保存您自己的数据。

uid

事件的唯一标识符。您可以放心使用此属性,它在所有现有事件中绝不会重复。

ungrab(class_instance)[源代码]

释放先前捕获的运动事件。

x

X 位置,位于窗口范围内。

y

窗口范围内的Y位置。

z

窗口范围内的Z轴位置。