kuix这个项目的功能非常强大,把css和xml在j2me上几乎做到了极致。同时它的事件处理也相当的复杂,好坏与否暂且不说,基于kuix在css和xml模块设计上的造诣,想来事件处理设计的这么复杂也是有些道理的,在此分析一二,方便大家理解。
先插一个图,是kuix官网上的图,图画的相当的精美,使我看了之后有很大的学习画图的冲动,暂时忍住了,过一段时间一定得好好补上,不多说了,见图:
首先kuix并没有在回调Canvas的系统主线程中处理事件,而是采取了将事件记录下来,使用工作线程处理和分发事件的方法。在KuixCanvas的回调函数keyPressed(), keyReleased(),KeyRepeated()等函数中使用了如下的代码:
processKeyEvent(KuixConstants.KEY_PRESSED_EVENT_TYPE, keyCode);
processKeyEvent(KuixConstants.KEY_RELEASED_EVENT_TYPE, keyCode);
processKeyEvent(KuixConstants.KEY_REPEATED_EVENT_TYPE, keyCode);
将事件记录在了一个Vector中,pointer事件也是一样。
而处理事件的工作线程会在KuixMIDlet初始化的时候开始运行,严格来说,这个线程并非只为处理事件而存在,它是一个后台工作线程,维持了一个工作任务列表,它会处理其中每一个任务。而在KuixCanvas初始化的时候,就把事件处理任务丢进去了,并且这个任务的run()函数的返回值是false,也就是说这个任务在运行结束后并不会从任务列表中删除,换句话说,这个任务会被工作线程一次又一次的循环执行。
接下来,我们详细分析这个在程序初始化时加入工作线程的事件处理任务:
该任务每次运行时,会处理keyEvents和pointerEvents列表里面的所有事件。具体的事件处理逻辑,由Desktop的当前focusManager代理完成,因此focusManger实际上或许叫做eventManger更合适一些。
每一个widget都可以有一个focusManager(也可以没有),在Desktop中,包含了一个当前screen对象,和若干个(也许0个)popup的widget。如果存在popup的widget,并且其中有widget设定了focusManager,那么就以最顶层的popup的widget的focusManager对象为Desktop的currentFocusManager,如果没有popup,则返回screen的focusManager对象。
这个逻辑说起来有点绕,实际上符合我们使用窗口系统的习惯,一个应用程序有一个主窗口,然后可能在其上弹出若干个对话框之类的弹出窗口,有弹出窗口的时候,窗口焦点就从主窗口改变到最后一个弹出的窗口上了,所有的用户输入和事件也都发给这个窗口,kuix的Desktop类的这个设计正是如此。
决定了focusManager这个事件处理器,我们再来仔细分析一下它是如何处理事件的:
处理KeyEvent的时候,focusManager实际上有三个逻辑:
- 调用当前焦点控件的keyEvent处理;
- 快捷键处理;
- 默认的上下左右键的处理(当然就是移动焦点了);