2. SWTEventDispatcher实现
EventDispatcher定义了事件分发器的抽象实现,它要监听各种不同的SWT事件并将这些事件分发到感兴趣的draw2d对象。对于任何EventDispatcher的实现者,必须要管理下面的内容:(括号中的内容是实际的变量定义)
· 鼠标是否被捕获(captured)
· 根图形(root)
· 鼠标操作目标(mouseTarget)
· 光标显示针对的目标(cursorTarget)
· 当前的聚焦图形(focusOwner)
· 鼠标悬停源(hoverSource)
· 当前的鼠标事件(currentEvent)
· 需要显示的光标(cursor)
· 引发事件的源控件(事件源control)
· 工具提示创建器(toolTipHelper)
EventDispatcher的实现者要负责将来自于SWT控件的事件转换成draw2d自定义的事件。SWTEventDispatcher就是EventDispatcher的一个具体实现EventDispatcher,它要负责处理SWT事件,并将处理后的事件转发给恰当的图形元素。
因为我自身兴趣的关心在于如何用draw2d中显示图形元素,所以仅仅只对与键盘、鼠标相关的事件做了研究,所以这里只能对SWTEventDispatcher是如何处理键盘、鼠标事件的过程进行了分析。
在读这节内容之前,请参阅draw2d系列文章中与图形元素类层次设计相关的文章,以了解各种draw2d事件的定义和含义。网站:http://blog.csdn.net/javamxj/。
现在首先看SWTEventDispatcher的实现者是如何处理键盘事件的:
1. 键盘按下处理
基本逻辑过程: 如果聚焦图形不等于空,就创建一个draw2d 键盘事件对象(KeyEvent),然后让聚焦图形处理该事件。
核心代码:
if (focusOwner != null)
{
KeyEvent event = new KeyEvent(this, focusOwner, e);
focusOwner.handleKeyPressed(event);
}
2,键盘释放处理
处理逻辑过程与键盘按下处理过程基本一样。
if (focusOwner != null)
{
KeyEvent event = new KeyEvent(this, focusOwner, e);
focusOwner.handleKeyReleased(event);
}
看SWTEventDispatcher的实现者是如何处理鼠标事件的
对于大多数鼠标事件,都要先进行一些初始化动作后才能开始处理这些事件。这个初始化过程被封装在Receive(org.eclipse.swt.events.MouseEvent me)方法中,该方法执行的逻辑过程如下:
/*更新光标下的图形元素,变量cursorTarget记录了当前光标下的图形元素*/
if( 鼠标没有被捕获 )
{
1. 从根图形中找到鼠标点下的图形元素f。
2. 将图形元素f设置成光标显示针对的图形元素(cursorTarget)并更新光标显示。
3. 如果cursorTarget不是鼠标悬停源(hoverSource),就将cursorTarget设置为鼠标悬停源(悬停源一定要能够提供工具提示信息)。
}
if( 鼠标被捕获 )
{
如果鼠标操作目标(mouseTarget)不为空,那么就将SWT事件转换成draw2d事件用它设置当前鼠标事件currentEvent。
}
else
{
首先,从根图形中找到鼠标点下的图形元素f。
if( f == mouseTarget ) //f就是鼠标操作目标
{
if( mouseTarget == null )
{
将SWT鼠标事件转换成draw2d事件用它设置当前鼠标事件currentEvent。
}
Return;
}
if( mouseTarget != null ) //f不是鼠标操作目标并且鼠标操作目标不为空
{
1. 将SWT鼠标事件转换成draw2d事件用它设置当前鼠标事件currentEvent。
2. 对鼠标操作目标调用“鼠标退出处理“操作。
}
mouseTarget = f; //将图形元素f设置为当前鼠标操作目标。
If( mouseTarget != null )
{
1. 将SWT鼠标事件转换成draw2d事件用它设置当前鼠标事件currentEvent。
2. 对鼠标操作目标调用“鼠标进入处理“操作。
}
}
Receive方法的主要目的是:
1,更新鼠标点下的图形元素并更新悬停源。
2,将SWT鼠标事件转换成Draw2d事件。
3,更新鼠标操作目标,在更新鼠标操作目标之前,务必要对上次receive调用中产生的鼠标目标进行“鼠标退出处理”,然后更新鼠标操作目标并对新的鼠标操作目标调用“鼠标进入处理”操作。
对鼠标悬停事件的处理逻辑过程:
1. 调用Receive对鼠标事件进行预处理。
2. 如果鼠标操作目标不为空,那么对鼠标操作目标调用“鼠标悬停处理操作。
3. 如果鼠标悬停源不为空,那么显示鼠标悬停源的工具提示信息。
鼠标双击处理过程:
1. 调用Receive对鼠标事件进行预处理。
2. 如果鼠标操作目标不为空,那么对鼠标操作目标调用“鼠标双击处理操作。
鼠标进入处理过程:
1. 调用Receive对鼠标事件进行预处理。
鼠标退出事件处理过程:
1. 将鼠标悬停源设置为空。
2. 如果鼠标操作目标不为空,那么
a) 将SWT鼠标事件转换成draw2d事件并用它设置当前鼠标事件currentEvent。
b) 如果鼠标操作目标不为空,那么对鼠标操作目标调用“鼠标退出处理“操作。
3. 将鼠标操作目标设置为空
鼠标按下事件处理过程:
1. 调用Receive对鼠标事件进行预处理。
2. 如果鼠标操作目标不为空,那么
a) 对鼠标操作目标调用“鼠标按下处理”操作。
b) 如果当前事件的被消费标志为真,那么就将捕获标志设置为真。
鼠标移动事件处理过程:
1. 调用Receive对鼠标事件进行预处理。
2. 如果鼠标操作目标不为空,那么
如果有任何鼠标键被按下,那么就对鼠标操作目标调用“鼠标拖动处理“操作;否则就对鼠标操作目标调用”鼠标移动处理“操作。
鼠标释放事件处理过程:
1. 调用Receive对鼠标事件进行预处理。
2. 如果鼠标操作目标不为空,那么对鼠标操作目标调用“鼠标释放处理“操作。
3. 释放捕获。
4. 调用Receive对鼠标事件进行预处理。
从上面的事件处理逻辑过程来看,除了Receive事件预处理过程比较复杂外,无论是键盘还是鼠标事件的处理过程都较为简单。
事件分发器在将SWT事件转换成draw2d事件后就将该事件转交给目标图形元素。那么图形元素又是如何处理这个事件的呢?
先看回顾以下SWTEventDispatcher对键盘按下事件的处理代码:
if (focusOwner != null)
{
KeyEvent event = new KeyEvent(this, focusOwner, e);
focusOwner.handleKeyPressed(event);
}
上面的代码表明,如果聚焦拥有者不为空,那么就对聚焦拥有者调用handleKeyPressed()方法。focusOwner是个Figure对象,下面是Figure类中handleKeyPressed()方法的实现代码:
public void handleKeyPressed(KeyEvent event)
{
Iterator iter = eventListeners.getListeners(KeyListener.class);
while (!event.isConsumed() && iter.hasNext())
{
((KeyListener)iter.next()).keyPressed(event);
}
}
从代码中,可以看出Figure类本身并没有具体的处理这个键盘按下事件,而是将这个事件又转交了注册到该Figure对象中的各个键盘按键监听器。至于具体如何处理这个键盘事件完全是监听器的事情了,与图形元素figure一点关系也没有。在Figure类中定义了许多的形如Add***Listener()的方法,对图形元素Figure的鼠标移动等事件感兴趣的对象可以通过调用这些方法将自己作为监听器注册到Figure对象中;只要Figure中的这些事件发生,这些外部对象就会得到通知。