四、编程向导(4.6输入管理)

编程向导4.6输入管理

一、输入架构

Kivy能处理很多类型的输入:鼠标、触摸屏、加速器、陀螺仪等等。它在下列的平台中能处理多点触摸协议:Tuio,WM_Touch, MacMultitouchSupport, MT Protocol A/B and Android.

输入全局架构可以被描述为:

输入提供者(Input Providers) -> 运动事件(Motion event) -> 投递处理(Post processing) -> 发送到窗口(Dispatch to Window)

所有管理输入事件的类是运动事件(MotionEvent)。它派生成两种类型的事件类:

  • 触摸事件:一个运动事件能至少包含X和Y坐标。所有的触摸事件通过部件树进行发送。

  • 非触摸事件:剩下的,例如加速器是一个连续事件,没有坐标。它没有开始和停止状态。这些事件不通过部件树发送。

一个运动事件被一个输入提供者(Input Provider)生成。一个输入提供者负责从操作系统、网络或其他应用程序读取输入事件。下是几个输入提供者:

  • TuioMotionEventProvider:创建一个UDP服务并监听TUIO/OSC消息。

  • WM_MotionEventProvider:使用窗口API读取多点触摸信息并发送到Kivy。

  • ProbeSysfsHardwareProbe:在Linux系统下,迭代所有连接到计算机上的硬件,并附着一个多点输入提供者为每一个被发现的多点触摸设备。

  • 更多:...
    当你写一个应用程序时,你不必创建一个输入提供者,Kivy会尝试自动检测可用的硬件。但是,如果你想支持定制的硬件,你就需要配置Kivy并使它工作。

在新创建的运动事件被传递到用户之前,Kivy应用投递处理(post-processing)到输入。每一个运动事件被分析并纠正错误输入,做出有意义的解释:

  • 通过距离和时间临界值,检测双击/三击(Double/triple-tap detection)。
  • 当硬件不是太精确时,使得事件更精确。
  • 如果本地触摸硬件在基本相同的位置发送多个事件时,降低事件的数量。

当处理事件后,运动事件被发送到窗口。正如前面解释的那样,不是所有的事件都发送到事件树:窗口过滤它们。对于一个事件:

  • 如果它仅仅是一个运动事件,它会被发送到on_motion()

  • 如果它是一个触摸事件,则触摸点的(x, y)坐标(在0-1范围内)会被重新转换为屏幕尺寸(宽/高),并发送到:

    • on_touch_down()
    • on_touch_move()
    • on_touch_up()

二、运动事件配置

依赖你的硬件和使用的输入提供者,也许有更多的信息可以被使用。例如,触摸输入有(x, y)坐标,但是也许还有压力信息,触摸尺寸,加速度等等。

一个运动事件配置是一个标识事件里面有什么特征可用字符串,让我们想象一下你在on_touch_move方法中:

def on_touch_move(self, touch):
    print(touch.profile)
    return super(..., self).on_touch_move(touch)

打印信息为:

['pos', 'angle']

注意:很多人将配置的名字和属性对应的名字混淆在了一块。在可用的配置文件里的'angle'不意味着触摸事件对象有一个angle对象。

对于'pos'配置,属性pox, x, y是可用的。对于'angle'配置,属性 a 是可用的。正如我们所说,对于触摸事件,'pos'是一个托管的配置,但'angle'不是。你能通过检测'angle'配置是否存在来扩展你的交互:

def on_touch_move(self, touch):
    print('the touch is at position', touch.pos)
    if 'angle' in touch.profile:
        print('the touch angle is', touch.a)

你能在motionevent文档中找到一个关于可用的配置的列表。

三、触摸事件

一个触摸事件是一个特殊的运动事件,它的属性is_touch被设置为True。对于所有的触摸事件,你会自动拥有X和Y坐标,对应着窗口的宽和高。换句话说,所有的触摸事件有'pox'配置。

(一)触摸事件基础

默认情况下,触摸事件被发送到当前所有的可显示的部件。这意味着无论事件发生在部件的内部与否,它都能收到事件。

如果你有关于其他GUI的开发经验,这可能是反直觉的。一般典型的做法是划分屏幕为几何区域,并且只有坐标在部件区域内部时才发送触摸或鼠标事件到部件。

当使用触摸事件工作时,这个要求变得非常的有限制性。强击,缩放和长按可能来自想了解部件及其如何反应的外部。

为了提供最大的灵活性,Kivy发送事件到所有的部件,并让它们决定是否响应它们。如果你仅想在部件内部响应触摸事件,你可以简单的进行检测:

def on_touch_down(self, touch):
    if self.collide_point(*touch.pos):
        #触摸发生在部件区域的内部,做自己的相应
        pass
(二)坐标

一旦你使用了一个带有矩阵转换的部件,你必须注意矩阵转换。一些部件,例如分散(Scatter)有它们自己的矩阵转换,这意味着触摸必须能正确的传递触摸坐标到Scatter的子部件。

  • 从父空间到局部空间获取坐标使用to_local()
  • 从局部空间到父空间获取坐标使用to_parent()
  • 从局部空间到window空间使用:to_window()
  • 从window空间到局部空间使用:to_widget()

你必须根据上下文使用上面的一个来转换相应的坐标。看分散(scatter)的实现:

def on_touch_down(self, touch):
    #将当前的坐标压入,为了后面能存储它
    touch.push()

    #转换触摸坐标到局部坐标
    touch.apply_transform_2d(self.to_local)

    #像平时一样,发送触摸到子部件
    #在touch里面的坐标是局部坐标
    ret = super(..., self).on_touch_down(touch)

    #无论结果如何,不要忘记调用之后弹出你的转换,
    #这样,坐标会变成父坐标
    touch.pop()

    #返回结果(依赖于你的所需)
    return ret

(三)触摸形状

如果触摸有一个形状,它可以在'shape'属性中体现。现在,仅仅ShapeRect被暴露:

from kivy.input.shape import ShapeRect

def on_touch_move(self,touch):
    if isinstance(touch.shape, ShapeRect):
        print('My touch have a rectangle shape of size', 
            (touch.shape.width, touch.shape.height))
(四)双击

双击是指在一段时间和范围内轻点两次。它由doubletap post-processing模块来计算。你能测试当前的触摸是双击或不是:

def on_touch_down(self, touch):
    if touch.is_double_tap:
        print('touch is a double tap!')
        print('- interval is', touch.double_tab_time)
        print('- distance between previous is', touch.double_tap_distance)
(五)三击

三击是只在一段时间和一定范围内轻击三次。它由tripletap post-processing模块来计算。你能测试当前的触摸是否为三击:

def on_touch_down(self, touch):
    if touch.is_triple_tap:
        print('Touch is a triple tap !')
        print(' - interval is', touch.triple_tap_time)
        print(' - distance between previous is', touch.triple_tap_distance)
(六)捕获触摸事件

对于父部件使用on_touch_down发送一个触摸事件到子部件,它是可能的,但通过on_touch_moveon_touch_up就不可以。这可能发生在特定的场景下,例如当一个触摸事件发生在父部件边框外部时,父部件决定不通知它的子部件。

当你捕获了一个事件,你会总是收到移动(move)和弹起(up)事件,但是对于捕获有一些限制:

  • 你将会收到事件至少两次:一次来自你的父部件(正常事件),一次来自window(捕获)。
  • 你可能收到一个事件,但是不是来自你:它可能因为父部件发送给它的子部件。
  • 触摸坐标没有转换到你的部件空间,因为触摸是来自Window。你需要收动转换它们。

下面是一个例子来演示如何使用捕获:

def on_touch_down(self, touch):
    if self.collide_point(*touch.pos):

        #如果触摸检测来自我们自己的部件,让我们捕获它。
        touch.grab(self)
        # 并响应这次触摸.
        return True

def on_touch_up(self, touch):
    #这里,你不用检测触摸碰撞或类似操作,
    #你仅需要检测是否它是一个捕获的触摸事件
    if touch.grab_current is self:
        #OK,当前触摸事件被派发给我们
        #做一些感兴趣的操作
        print('Hello world!')
        #不要忘记释放掉,否则可能会有副作用
        touch.ungrab(self)
        #最后响应这次触摸
        return True
(七)触摸事件管理

为了了解触摸事件如何在部件间被控制和传播,请参阅部件触摸事件冒泡机制(Widget touch event bubbling)

下节预告:编程向导4.7部件

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容

  • 编程向导4.4架构预览 我们将要花费一些时间以软件管理的角度来解释如何设计Kivy。这将是理解每一部分如何一起工作...
    gthank阅读 599评论 0 0
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 172,091评论 25 707
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,654评论 18 139
  • 感恩今天的凉爽天气。人胃口也变的特别好了。 感恩今天看了一位佛学大师的文章。说的是关于婴灵的。婴灵的年龄会直到他...
    悦心慧儿阅读 193评论 0 2
  • 末日微澜(1) 第二章 星航 若仰望夜空,辽阔天幕下,我们肉眼所见的最远星辰,已经存在了138亿年,那些闪耀着的光...
    太阳能植物阅读 152评论 0 0