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中的這些事件發生,這些外部對象就會得到通知。