Kivy A to Z -- Kivy的消息处理机制

外面一直在下雨,比较无聊,顺便总结了下Kivy的消息的处理过程。

总的来说,在Kivy里,处理的消息一共有四种:按键消息,鼠标消息,触屏消息,还有自定义消息。下面来看下整个消息的处理流程。

先来看张图:

先来解释下这几个类都是干嘛的:

1、EventDispatcher:看名称就知道这是一个消息分发类,在这个类中通过了以下的主要方法:

register_event_type : 注册一种消息类型

bind                :将一个方法绑定到一个消息类型,用于保存方法的是一个list类型。

dispatch            :调用相应的已经注册到指定消息类型的方法。

2、WindowBase:Window的基类,定义了Window的一些常用的方法,如add_wdiget,on_draw。

WindowPygame,WindowX11,WindowSDL这三个类是WindowBase的子类,在某一平台上只会初始化一种,并且只有一个实例,主要用于接收消息和处理消息。具体的初始化代码在kivy/core/__init__.py:

      #: Instance of a :class:`WindowBase` implementation

Window = core_select_lib('window', (

    ('egl_rpi', 'window_egl_rpi', 'WindowEglRpi'),

    ('pygame', 'window_pygame', 'WindowPygame'),

    ('sdl', 'window_sdl', 'WindowSDL'),

    ('x11', 'window_x11', 'WindowX11'),

), True)

如果没有特别指定,Kivy将会实例化WindowPygame,作为Kivy的主窗口。所有的画图,创建widget的操作都将在这个主窗口上进行。

再来解释下主要变量和方法。EventDispatcher.__event_stack,这是一个用于保存所有已经注册的消息。添加一个消息到__event_stack有两种方法:

1、一种是通过调用EventDispatcher.register_event_type

2、另一种方法是在子类中声明一个类变量__events__,如在WindowBase中就有关于__events__的声明:

            __events__ = ('on_draw', 'on_flip', 'on_rotate', 'on_resize', 'on_close',

                  'on_motion', 'on_touch_down', 'on_touch_move', 'on_touch_up',

                  'on_mouse_down', 'on_mouse_move', 'on_mouse_up',

                  'on_keyboard', 'on_key_down', 'on_key_up', 'on_dropfile')

并在EventDispatcher.__cinit__时把这些事件类型加到__event_stack变量中。

有了事件的类型,接下来要做的事就是通过EventDispatcher.bind添加事件的处理方法:

例如,在input/providers/mouse.py的MouseMotionEventProvider中,就有下面的bind代码:

    def start(self):

        '''Start the mouse provider'''

        if not EventLoop.window:

            return

        EventLoop.window.bind(

            on_mouse_move=self.on_mouse_motion,

            on_mouse_down=self.on_mouse_press,

            on_mouse_up=self.on_mouse_release)

好,注册了消息类型和消息的处理过程,按下来就要等消息上门了。

前面讲到,Kivy实例化了WindowPygame作为主窗口,并且通过调用App.run最终进入WindowPygame._mainloop这个消息循环方法。接下来看下_mainloop都做了些什么:


   def _mainloop(self):
        EventLoop.idle()
        for event in pygame.event.get():
            # kill application (SIG_TERM)
            if event.type == pygame.QUIT:
                EventLoop.quit = True
                self.close()
            # mouse move
            elif event.type == pygame.MOUSEMOTION:
                x, y = event.pos
                self.mouse_pos = x, self.system_size[1] - y
                # don't dispatch motion if no button are pressed
                if event.buttons == (0, 0, 0):
                    continue
                self._mouse_x = x
                self._mouse_y = y
                self._mouse_meta = self.modifiers
                self.dispatch('on_mouse_move', x, y, self.modifiers)

            # mouse action
            elif event.type in (pygame.MOUSEBUTTONDOWN,
                                pygame.MOUSEBUTTONUP):
                self._pygame_update_modifiers()
                x, y = event.pos
                btn = 'left'
                if event.button == 3:
                    btn = 'right'
                elif event.button == 2:
                    btn = 'middle'
                elif event.button == 4:
                    btn = 'scrolldown'
                elif event.button == 5:
                    btn = 'scrollup'
                elif event.button == 6:
                    btn = 'scrollright'
                elif event.button == 7:
                    btn = 'scrollleft'
                eventname = 'on_mouse_down'
                if event.type == pygame.MOUSEBUTTONUP:
                    eventname = 'on_mouse_up'
                self._mouse_x = x
                self._mouse_y = y
                self._mouse_meta = self.modifiers
                self._mouse_btn = btn
                self._mouse_down = eventname == 'on_mouse_down'
                self.dispatch(eventname, x, y, btn, self.modifiers)

            # keyboard action
            elif event.type in (pygame.KEYDOWN, pygame.KEYUP):
                self._pygame_update_modifiers(event.mod)
                # atm, don't handle keyup
                if event.type == pygame.KEYUP:
                    self.dispatch('on_key_up', event.key,
                                  event.scancode)
                    continue
                # don't dispatch more key if down event is accepted
                if self.dispatch('on_key_down', event.key,
                                 event.scancode, event.unicode,
                                 self.modifiers):
                    continue
                self.dispatch('on_keyboard', event.key,
                              event.scancode, event.unicode,
                              self.modifiers)
            # video resize
            elif event.type == pygame.VIDEORESIZE:
                self._size = event.size
                self.update_viewport()

            elif event.type == pygame.VIDEOEXPOSE:
                self.canvas.ask_update()
            # ignored event
            elif event.type == pygame.ACTIVEEVENT:
                pass
            # drop file (pygame patch needed)
            elif event.type == pygame.USEREVENT and                     hasattr(pygame, 'USEREVENT_DROPFILE') and                     event.code == pygame.USEREVENT_DROPFILE:
                self.dispatch('on_dropfile', event.filename)
            '''
            # unhandled event !

            else:

                Logger.debug('WinPygame: Unhandled event %s' % str(event))

在这个消息循环里,通过pygame.event.get()获取消息,消息的类型有:按键,鼠标,这两种,通过dispatch将消息发送到相应的方法中去处理,这里有一个疑问:怎么没有看到Kivy对触屏消息的处理?答案是触屏消息的处理是在函数开始的EventLoop.idle()里进行的。这篇讲的就要是消息的处理机制,所以这里就不再展来。其内容留着以后再讲。

Kivy A to Z -- Kivy的消息处理机制

时间: 2024-10-11 18:03:15

Kivy A to Z -- Kivy的消息处理机制的相关文章

Kivy A to Z -- Kivy 示例演示自带名单

所有的样品已经在Android 4.04 手机正常进行 1.demo/kivycatalog 这个例子说明了如何使用主控件,例如Layout,Button,MediaPlayer,Progress Bar等等 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvSTJDYnVz/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" > 2.demo/Pic

Kivy A to Z -- Kivy之Properties

在像VB.net,C#这样的语言中,都有Property的概念,可以通过get获取属性的值,也可以通过set来设置一个属性的值,Kivy也提供了类似的功能.在Kivy里,提供了以下的属性类: ? StringProperty ? NumericProperty ? BoundedNumericProperty ? ObjectProperty ? DictProperty ? ListProperty ? OptionProperty ? AliasProperty ? BooleanPrope

Kivy A to Z -- 如何实现焦点切换效果

Kivy是面向触屏设备的,对键盘,遥控器等输入设备的处理比较弱,但是有时候我们又需要实现对按键的处理,如通过方向键切换焦点,这篇文章来讨论下如何去实现. 在看下面的代码之前,最好是对Kivy的UI系统有一个基本的了解. 按照惯例,我们先上代码,然后再对代码进行解释: focustest.py import kivy kivy.require('1.8.0') from kivy.app import App from kivy.properties import StringProperty,B

Kivy A to Z -- 如何从python代码中直接访问Android的Service

在Kivy中,通过pyjnius扩展可以间接调用Java代码,而pyjnius利用的是Java的反射机制.但是在Python对象和Java对象中转来转去总让人感觉到十分别扭.好在android提供了binder这个进程间通信的功能,Java中的Service也是基于Binder的C++代码封装来实现进程间通信的,这也为从Python代码中绕开pyjnius直接访问Java代码提供了可能,既然Java的Service是基于C++的封装来实现的,也同样可以在Python中封装同样的C++代码,这篇文

Kivy a to Z -- 一个简单的通过adb同步Android系统文件的工具

来兴趣时写了些Kivy的代码,调试却总感觉不是很方便.直接打包到public.mp3的方式太繁锁,用文件共享的软件又发现没有一个好用的, 用samba filesharing本来也只是慢,但是更新的版本之后就一直提示说wifi没有tethering,意思是wifi热点没有打开,但是打开了还是提示没有tethering. 找了个叫什么卓*力的文件管理器,下载了samba插件后输入用户名和密码死活不对,被搞得实在恼火,花了点时间写了个通过adb同步安卓文件的工具,用着也挺爽的. 事件为什么总是要搞得

Kivy A to Z -- 如何从Python创建一个基于Binder的Service及如何从Java访问Python创建的Service

<Kivy A to Z -- 如何从python代码中直接访问Android的Service> 一文中讲到了如何从python访问java的service,这一篇再来讲下如何创建一个基于Binder的Python Service以及如何从Java代码中访问这个Python创建的Service. 先来看代码,再作下解释: 接<Kivy A to Z -- 如何从python代码中直接访问Android的Service>一文,我们在相关的文件中增加代码: binder_wrap.cp

13.安卓消息处理机制

1.Android消息处理机制(★★★★必会) 1.1.Looper.Message.Handler的关系 当我们的Android应用程序的进程一创建的时候,系统就给这个进程提供了一个Looper,Looper是一个死循环,它内部维护这个一个消息队列.Looper不停地从消息队列中取消息(Message),取到消息就发送给了Handler,最后Handler根据接收到的消息去修改UI.Handler的sendMessage方法就是将消息添加到消息队列中. 1.2.runOnUiThread Ac

Android Learning:多线程与异步消息处理机制

在最近学习Android项目源码的过程中,遇到了很多多线程以及异步消息处理的机制.由于之前对这块的知识只是浅尝辄止,并没有系统的理解.但是工程中反复出现让我意识到这个知识的重要性.所以我整理出这篇博客,主要介绍了线程和异步处理机制的意义和用法,目的在于帮助初学者能够加深对异步消息处理机制的理解,在实际Android工程中能够更多地使用AsyncTask工具类在子线程中进行UI更新. 一.Android当中的多线程[1] 在Android当中,当一个应用程序的组件启动的时候,并且没有其他的应用程序

Android异步消息处理机制(3)asyncTask基本使用

本文翻译自android官方文档,结合自己测试,整理如下. 概述 AsyncTask抽象类,翻译过来就是异步任务,能够合理并方便的使用UI线程.该类可以实现将后台操作结果显示在UI线程中,而不需要我们自己实现子线程或者handler(当然它内部也是借助这两者实现的). 虽然AsyncTask可以提供后台运行并将结果显示在UI上,但是理想情况应该是后台操作最多只能是几秒钟,若要执行长时间的操作强烈建议使用java中的Executor,ThreadPoolExecutor,FutureTask等.