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

来源:互联网 发布:淘宝企业开店店铺名称 编辑:程序博客网 时间:2024/05/15 05:07

外面一直在下雨,比较无聊,顺便总结了下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` implementationWindow = 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()里进行的。这篇讲的就要是消息的处理机制,所以这里就不再展来。其内容留着以后再讲。

 

 

 

  

 

0 0
原创粉丝点击