draw2d設計內幕之一:LightweightSystem設計和實現剖析
1.1 LightweightSystem設計
UpdateManager持有根圖形元素的應用,因爲只有通過根圖形元素,才能夠獲取待更新的圖形元素,請參見對根圖形元素作用的描述。
EventDispatcher是一個抽象類,它爲具體的事件分發器提供基本實現。SWTEventDispatcher是EventDispatcher類的具體實現。顧名思義,SWTEventDispatcher與SWT控件套件有關。draw2d的SDK文檔是這樣描述SWTEventDispatcher的:SWTEventDispatcher使draw2d具有分發SWT事件的能力;LightweightSystem增加SWT事件監聽器到它的畫布控件;當畫布控件接受到一個SWT事件後,它就調用SWTEventDispatcher中定義的一個合適的分發器方法。在設計良好的圖形系統中,自定義一套於平臺無關的事件處理機制是一種通行的做法。Draw2d也不例外,在Draw2d中定義了與操作系統無關的事件序列,SWTEventDispatcher的主要職責之一就是要將來自於SWT的事件轉換層draw2d中定義的內部事件,然後再將內部事件分發給恰當的圖形元素。
可以LightweightSystem看成一個Canvas的適配器,它擴展了canvas的功能,並完全隱藏了與canvas的通信過程。可以直接將LightweightSystem看成一個擁有繪圖表面、能夠管理圖形元素的繪製並處理各種用戶交互事件的控件。
在LightweightSystem中定義瞭如下的變量:
private Canvas canvas; //充當繪圖表面
IFigure contents; //需要在Canvas中顯示的圖形元素
private IFigure root; //LightweightSystem中的根元素
private EventDispatcher dispatcher; //事件分配器
private UpdateManager manager = new DeferredUpdateManager(); //更新管理器
private Rectangle oldControlSize = new Rectangle(); //畫布控件的舊大小
除root外,其它幾個圖形元素外都比較容易理解。在前幾篇文章中,已經對root的作用進行了描述,但爲了保持文章的完整性,這裏在重複一下對它的描述。根圖形的職責如下:
2. 作爲內容圖形元素的父親。
3. 作爲搜索某個圖形元素的搜索入口點。
4. 具備佈局屬性。因爲它是內容圖形元素的父親,所以可以對內容圖形元素進行佈局。在當前的LightWeightSystem實現中,根圖形元素的默認佈局是堆疊佈局(StackLayout)。
5. 通過繪製根圖形元素中某個區域,可以繪製位置落在這個區域之內所有的圖形元素。
應用程序不要期望重新定義LightWeightSystem中的根圖形元素,這是不允許的。
實際上,從1.1節中的LightWeightSystem中的設計圖中,比較容易理解LightWeightSystem爲什麼要定義這些變量。在某些可將設計轉換成代碼的CASE工具中,可以直接生成這些變量定義。
從LightWeightSystem的初始化過程中,可以對LightWeightSystem的邏輯結構有一個比較好的理解,
public LightWeightSystem(Canvas c)
{
//首先創建根圖形元素並用該根圖形元素初始化更新管理器和LightweightSystem對象的根圖形元素。
RootFigure tmpRoot = createRootFigure();
GetUpdateManager().SetRoot( tmpRoot );
This.root = tmpRoot;
//更新管理器要更新圖形元素時,需要一個具體的繪圖上下文。爲getUpdateManager設置圖形上下文來源的目的就是
//告知更新管理器,當其執行更新時,如何獲取圖形上下文。通常,圖形上下文是從控件中獲取的。
canvas = c;
getUpdateManager().setGraphicsSource(new BufferedGraphicsSource(canvas));
//根據canvas的大小調整root圖形元素的約束範圍(使root與canvas的客戶區一樣大)
controlResized();
//接下來將LightweightSystem作爲監聽器註冊到Canvas
addListeners();
}
· controlResized()方法方法體如下:
{
Rectangle r = new Rectangle(canvas.getClientArea());
r.setLocation(0, 0);
root.setBounds(r); //重新設置根圖形元素的範圍,使其大小等於畫布控件的客戶區大小,並完全覆蓋在畫布之上。
//使根圖新元素重新有效,該調用會使根圖新元素重新佈局內容圖形元素。
root.revalidate();
//通知更新管理器,更新根圖形元素。
manager.performUpdate();
oldControlSize = r; //保存老的控件大小。
}
· addListeners()方法要負責將LightweightSystem對象作爲監聽器註冊到Canvas中,該方法方法體如下:
protected void addListeners()
{
//首先創建一個事件處理器,這個事件處理器實現了許多的接口,這些接口中方法負責接受SWT的各種交互事件。
EventHandler handler = createEventHandler();
//處理輔助交互事件(爲殘疾人準備的)
canvas.getAccessible().addAccessibleListener(handler);
canvas.getAccessible().addAccessibleControlListener(handler);
//處理鼠標按下
canvas.addMouseListener(handler);
//處理鼠標移動等事件。
canvas.addMouseMoveListener(handler);
//處理鼠標跟蹤事件。
canvas.addMouseTrackListener(handler);
//處理鍵盤事件。
canvas.addKeyListener(handler);
//處理遍歷事件(模擬控件被遍歷的情況)
canvas.addTraverseListener(handler);
//處理聚焦事件。
canvas.addFocusListener(handler);
//重新設置根圖形元素的約束範圍。
root.setBounds(oldControlSize);
//通知更新管理器,更新根圖形元素。
getUpdateManager().performUpdate();
//初始化事件分發器。
setEventDispatcher(getEventDispatcher());
}
//GetEventDispatcher()函數體
protected EventDispatcher getEventDispatcher()
{
if (dispatcher == null)
dispatcher = new SWTEventDispatcher();
return dispatcher;
}
· EventHandler類(事件處理器)的定義
protected class EventHandler implements MouseMoveListener, MouseListener, AccessibleControlListener, KeyListener, TraverseListener, FocusListener, AccessibleListener, MouseTrackListener
{
…
}
在EventHandler類中的各個方法實現基本上都是直接調用getEventDispatcher().dispatchMouseMoved(event)分發事件。這個過程實際上就是,LightweightSystem接收SWT事件(通過EventHandler類事件的諸多接口方法),然後EventHandler再直接將事件轉發到事件分發器中;然後事件分發器將swt事件轉換成draw2d事件並分發到恰當的圖形元素中。
通過對LightweightSystem類初始化過程的跟蹤分析,基本上可以瞭解到組成LightweightSystem的各個部分是如何被創建的,更重要的是,通過跟蹤分析,可以很清晰的瞭解到draw2d中事件的接收、分發過程。