Draw2D設計--3. LightweightSystem設計和實現剖析(1)

draw2d設計內幕之一:LightweightSystem設計和實現剖析

        
        作者:餘學鋒      編輯:javamxj   發佈:javamxj    源站點:分享Java快樂
     
    這篇文章假設讀者在瀏覽本章之前,已經對LightweightSystem有了一定的瞭解,基本上應該要明白LightweightSystem究竟是個什麼?在 分享Java快樂 的 Draw2d專欄 中有關於LightweightSystem介紹的文章。在本文章中,提供了一個dxf文件解析器和dxf瀏覽器。dxf瀏覽器就是利用draw2d編寫的。本文章力圖言簡意賅的解釋與LightweightSystem相關的設計和實現,所以對一些基本的技術名詞和術語並沒有或沒有詳細的解釋。
 
 
 
1. LightweightSystem設計和實現

1.1 LightweightSystem設計
             LightWeightSystem設計圖
 
    設計圖表明,一個LightweightSystem由四個不可缺少的部分組成:畫布控件、圖形元素更新管理器、事件分發器、根圖形元素。內容是需要在畫布上顯示的與應用相關的圖新元素,並不要求LightweightSystem一定就要擁有內容圖形元素;對LightweightSystem而言,內容圖形元素可有可無,但如果內容圖形元素爲空,那麼LightweightSystem就什麼也不顯示。向LightweightSystem設置內容的動作,實際上就是將內容圖形元素作爲孩子增加到根圖形元素中,並且在LightweightSystem中記錄下對內容圖形元素的直接引用(由變量contents引用)。
 
    UpdateManager是一個抽象類,它爲具體的更新管理器提供基本實現。DeferredUpdateManager是UpdateManager類的具體實現,它以異步更新圖形元素的方式執行更新過程,這種方式在許多軟件中,被叫做多線程呈現;如果讀者有MFC或win32開發經驗,比較容易瞭解DeferredUpdateManager的實現原理了:在MFC或Win32中,如果要使某個區域無效,需要調用Invalidate通知系統某個區域無效,在系統接到這個通知後,並不是立即去更新無效區域而是將無效區域放入到系統保持的一個無效區域列表中,以後在程序空閒時再一併處理無效區域列表中的所有髒區域(取它們的並集),所以有時即使在程序中調用許多次invalidate,但並不會顯著影響系統的呈現效率,原因就是如此。當使用DeferredUpdateManager管理圖形元素的更新時,圖形元素的更新總是要延遲於使圖形元素無效的動作,例如,如果用戶用鼠標resize化應用程序窗口,就會發現窗口在被resize後,在靠近被鼠標一側的窗口區域有一塊灰色區域,但隨即該區域就被正常的被填充上了;這塊灰色區域就是用戶resize窗口過程中產生的髒區域,在拖動的過程中,應用程序已經向DeferredUpdateManager報告了有髒區域產生的事實,但DeferredUpdateManager僅僅只是創建一個線程,但因爲涉及到更新UI的問題,該線程必須在UI線程中被執行;但此時UI主線程正忙於處理用戶的resize動作,所以不會執行DeferredUpdateManager的更新請求;無論用戶以多快的速度執行resize動作,在兩次resize過程中總會有空隙,在這個空隙中,UI主線程就會執行DeferredUpdateManager的更新請求。異步更新圖形元素的方式並不會提高圖形元素呈現的速度,但它會極大的改善UI界面的響應能力。

    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看成一個擁有繪圖表面、能夠管理圖形元素的繪製並處理各種用戶交互事件的控件。
 
 
 
1.2 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的作用進行了描述,但爲了保持文章的完整性,這裏在重複一下對它的描述。根圖形的職責如下:
 
  1.  作爲應用程序的背景。根圖形元素完全覆蓋在畫布上,用戶可以設置根圖形元素的顯示屬性,改變根圖形元素的顯示屬性就可以改變應用程序的背景。
  2.  作爲內容圖形元素的父親。
  3.  作爲搜索某個圖形元素的搜索入口點。
  4.  具備佈局屬性。因爲它是內容圖形元素的父親,所以可以對內容圖形元素進行佈局。在當前的LightWeightSystem實現中,根圖形元素的默認佈局是堆疊佈局(StackLayout)。
  5.  通過繪製根圖形元素中某個區域,可以繪製位置落在這個區域之內所有的圖形元素。
 
應用程序不要期望重新定義LightWeightSystem中的根圖形元素,這是不允許的。
 
實際上,從1.1節中的LightWeightSystem中的設計圖中,比較容易理解LightWeightSystem爲什麼要定義這些變量。在某些可將設計轉換成代碼的CASE工具中,可以直接生成這些變量定義。
 
從LightWeightSystem的初始化過程中,可以對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中事件的接收、分發過程。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章