GEF入門

1 必須具備知識:
在學習GEF之前必須瞭解Eclipse這個平臺的架構體系,所以先講述Eclipse平臺的架構體系.
1.1 Eclipse架構體系:
圖表 1 1 eclipse架構體系
正如上面所敘述:
 Eclipse Platform包括以下插件:
1. platform runtime: 注意這個插件是必須要的,啓動eclipse需要他.
2. workspace
3. debug
4. help
5. team
6. workbench:其中workbench 主要有由SWT和JFace組成.
 JDT插件在Eclipse Platform的基礎上爲Java開發環境提供的一個插件,使用這個插件可以做Java開發,同時他也提供訪問Java一些資源的API(擴展點),可以利用這些擴展點爲將來自己做插件開發提供用處.
 PDE插件開發則是在JDT插件和Eclipse Platform兩個基礎上爲開發插件提供一個環境,提供一個API.
 Eclipse Project這個東西包括了JDT,PDE,Eclipse Platform.
 然後我們可以在Eclipse Platform的基礎上做自己的插件開發,比如:another tool, your tool, their tool 就是利用eclipse platform開發出來的插件.

圖表 1 2 Platform的API上分佈情況
從上圖我們可以看到:
org.eclipse.core 這個包涉足到的插件領域有:
platform runtime,workspace,team,help,debug.
Org.eclipse.ui 這個包涉足到的插件領域有:
Workbench, team, help,debug.


圖表 1 3 eclipse插件的層次結構
從上圖我們可以看到:
Java virtual Machine位於最低層
Platform在 JVM之上
JDT在Platform基礎上開發出來的.
PDE又是在JDT的基礎上開發出來.
1.2 Plugin開發平臺
首先要弄明白,弄熟悉Plugin開發環境,這方面資料見eclipse的幫助,或者<<eclipse從入門到精通>>這本書.
Plugin開發中最重要的一個文件文件就是plugin.xml這個文件,下面對這個文件做一個講述.

圖表 1 4 plugin.xml的分析
從上面這個圖中我們可以看到plugin.xml主要做如下工作:
 Requires: 提出該插件開發的情況下必須需要那些其他的插件,在PDE上開發需要import進來的包.
 Runtime: 表明該插件真正在eclipse平臺上運行起來需要哪些插件.
 Extension point: 在哪些其他插件上的擴展點上作出的二次開發
 Extension-Point: 向外界提供哪些擴展點,使得別人可以在我開發的插件基礎上再做二次開發.

圖表 1 5 extension與extension point的概念
Extension point: 插件A向外界提供一個擴展點,使得其他人可以在A的基礎上再做二次開發,
Extension: 對 extension point的延生, 再extension point的基礎上做的二次開發.
1.3 Eclipse開發文檔-非常重要

圖表 1 6 eclipse的help文檔
從上面我們可以看到eclipse提供了各種各樣的文檔,基本上分爲兩類:
 用戶文檔: -----針對軟件使用者,相當於使用手冊
Workbench User Guide
Java Development User Guide
PDE guide
 開發文檔: -----針對插件開發人員
Platform Plug-in Developer Guide
JDT Plug-in Developer Guide
GEF Developer Guide
Draw2D Developer Guide
EMF Programmer’s Guide
EMF Service Data Objects(SDO) Programmer’s Guide
XSD Programmer’s Guide
以上這些文檔是非常重要的,時刻是要查詢的,必備手冊.
1.4 插件開發中的一些重要概念:

圖表 1 7 一些插件中的重要概念
從上圖中我們熟悉了一些什麼是workbench, workbench window, workbenchpage, view.現在來講述一下eclipse的構成.
 Platform PlatformUI 類
 WorkbenchIWorkbench接口,分爲host與target兩種類型
Host 爲插件開發的workbench,
Target爲對開發出來的插件進行debug,run時的workbench.
 WorkbenchWindow IWorkbenchWindow接口
 PagesIWorkbenchPage接口 ,類似perspective概念
 PartsIWorkbenchPart接口, 包括了viewpart,editorpart
 ViewsIViewPart接口
 EditorsIEditorPart ,常常與IEditorInput關聯
Platform啓動/訪問workbench;
workbench下面包含1..*個workbenchwindow(可曾記得eclipse的window菜單下new window);
workbenchwindow下面包含menu bar, toolbar, 1..*個workbenchpage.
Workbenchpage 下面包括1..* parts
Parts裏面包含了0..*個viewpart,0..*editorpart.
 Display: SWT與底層OS交互的一個紐帶,用來負責SWT和OS的通信
 Shell: 一個開發出來的可視化的window
 IAction:
 IActionDelegate:
 IWorkbenchAction:
 IWorkbenchActionDelegate:
 ISelection:
 IAdaptable:
 IPageService:
 IPartService:
 ISelectionService:
 IWorkbenchSite:
 IWorkbenchPartSite:
 IEditorSite:
XXXService接口主要用來跟蹤信息用的
XXXSite 接口用來獲取周圍的環境
還有其他的一些重要接口可以通過Platform Plug-in Developer Guide來獲得幫助.下面再簡要的展現一些概念.

圖表 1 8 一些其他的概念
2 GEF開發教程
 學習GEF的一些參考資料:
http://bjzhanghao.cnblogs.com/ ---該blog中有很多關於GEF&EMF入門的教程.
http://javaspider.sourceforge.net/updatesite ---一個記載當前workbench下的各種類,及其相關的方法和調用流程.
 初級學者適合的例子:
http://jtauber.com/2004/gef/gef.zip
http://bjzhanghao.cnblogs.com/Files/bjzhanghao/Six GEF snapshots from James Tauber.zip
上面兩個包就是一個東西,非常適合入門者,一步一步的提高技術水平.
http://www.cnblogs.com/Files/bjzhanghao/gefpractice.zip
 一些經典的例子程序(比較難,不適合入門)
GEF SDK Examples自帶的四個case:
1. org.eclipse.gef.examples.flow
2. org.eclipse.gef.examples.logic
3. org.eclipse.gef.examples.shapes
4. org.eclipse.gef.examples.text
 初步學習GEF和Draw2D必須要看的資料:
1. GEF Developer Guide裏面的一篇整體概括文章,包括: Introduction,EditPartViewers,Model View Controller Architecture, EditParts, EditPolicies Requests, and Roles, Tools and the Palette, The Steps to Building a GEF application.
2. Draw2D Developer Guide 裏面的一篇整體概括文章,包括: Introduction, Visual Overview, LayoutManager Demo, Clicking and Scrolling Demo, Connections and Anchors Demo.
2.1 Draw2D知識

圖表 2 1 Draw2D體系結構
Draw2D是基於SWT的圖形處理包,它適合用作GEF的View層:
Draw2D通過被稱爲LightweightSystem(以下簡稱LWS)的部件與SWT中的某一個Canvas實例相連,這個Canvas在Draw2D應用程序裏一般是應用程序的Shell,在GEF應用程序裏更多是某個Editor的Control(createPartControl()方法中的參數),在界面上我們雖然看不到LWS的存在,但其他所有能看到的圖形都是放在它裏面的,這些圖形按父子包含關係形成一個樹狀的層次結構。
LWS是Draw2D的核心部件,它包含三個主要組成部分:RootFigure是LWS中所有圖形的根,也就是說其他圖形都是直接或間接放在RootFigure裏的;EventDispatcher把Canvas上的各種事件分派給RootFigure,這些事件最終會被分派給適當的圖形,請注意這個RootFigure和你應用程序中最頂層的IFigure不是同一個對象,前者是看不見的被LWS內部使用的,而後者通常會是一個可見的畫布,它是直接放在前者中的;UpdateManager用來重繪圖形,當Canvas被要求重繪時,LWS會調用它的performUpdate()方法。
LWS是連接SWT和Draw2D的橋樑,利用它,我們不僅可以輕鬆創建任意形狀的圖形(不僅僅限於矩形),同時能夠節省系統資源(因爲是輕量級組件)。一個典型的純Draw2D應用程序代碼具有類似下面的結構:
//創建SWT的Canvas(Shell是Canvas的子類)
Shell shell = new Shell();
shell.open();
shell.setText("A Draw2d application");
//創建LightweightSystem,放在shell上
LightweightSystem lws = new LightweightSystem(shell);
//創建應用程序中的最頂層圖形
IFigure panel = new Figure();
panel.setLayoutManager(new FlowLayout());
//把這個圖形放置於LightweightSystem的RootFigure裏
lws.setContents(panel);

//創建應用程序中的其他圖形,並放置於應用程序的頂層圖形中
panel.add( );
while (!shell.isDisposed ()) {
if (!display.readAndDispatch ())
display.sleep ();
}
接下來說說圖形,Draw2D中的圖形全部都實現IFigure(org.eclipse.draw2d.IFigure)接口,這些圖形不僅僅是你看到的屏幕上的一塊形狀而已,除了控制圖形的尺寸位置以外,你還可以監聽圖形上的事件(鼠標事件、圖形結構改變等等,來自LWS的EventDispatcher)、設置鼠標指針形狀、讓圖形變透明、聚焦等等,每個圖形甚至還擁有自己的Tooltip,十分的靈活。
Draw2D提供了很多缺省圖形,最常見的有三類:1、形狀(Shape),如矩形、三角形、橢圓形等等;2、控件(Widget),如標籤、按鈕、滾動條等等;3、層(Layer),它們用來爲放置於其中的圖形提供縮放、滾動等功能,在3.0版本的GEF中,還新增了GridLayer和GuideLayer用來實現"吸附到網格"功能。在以IFigure爲根節點的類樹下有相當多的類,不過我個人感覺組織得有些混亂,幸好大部分情況下我們只用到其中常用的那一部分。
2.2 GEF框架
GEF框架中很多東西,主要得關注它的流程和結構.
2.2.1 GEF結構圖:

圖表 2 2 GEF結構圖
這個圖非常重要,體現了GEF的全部框架,必須牢記.
注意: EditorPart 與EditPart 不是一個概念.
 從上圖中我們可以看到WorkbenchPage, EditorPart, OutlineView三者互相作用. 代表他們都可以觸發對方發生響應.
 EditorPart的產生必然會導致IEditorInput的出現,因爲兩者有着緊密的關聯.
 EditorPart的控件中包含了PaletteViewer 控件和EditPartViewers[]控件. PaletteViewer表示是一個工具板,裏面包含了各種各樣的Tool, 但是用戶做操作時只有一個Tool爲Active Tool. EditPartViewers[] 代表editorPart中多個可視Unit. 因爲一個可視Unit包括: 一個editPart,一個ViewPart,一個Application Model . 其中editPart 爲可視Unit的Controller, ViewPart爲可視Unit的View(在EditorPart中可以看到的一些控件), Application Model 爲可視Unit的Model.
 PaletteViewer 與EditPartViewer進行交互中包括一個EditDomain,這個EditDomain代表一次edit session. EditDomain中記載了Active Tool, Command Stack, EditPartViewer[],PaletteViewer, PaletteModel. 使用EditDomain來進行各種交互.



2.2.2 EditPartViewer結構圖:

圖表 2 3 EditorPartViewer結構圖
此圖代表了EditorViewer的具體組成:
從上面途中我們可以看到ViewPart與Application Model不發生關係,他們要發生關係必須通過EditPart這個控制器.
 EditPartController
這個控制器發出命令對viewpart的創建,更改
 VisualPartView
一般由Draw2D中的控件來表現,是一種可視控件.
 Application Model Model
針對visualPart有對應的模型, 模型代表了visualPart中的一種具體數據.
控制流程:
EditPart 來控制VisualPart 的創建修改, Application Model的創建修改.
同時由於在啓動editorPartViewer時,將每一個Application Model和VisualPart一一綁定在一起, 同時application Model中有propertyListener, 所以Application Model發生改變時, 通過PropertyListener告訴editPart, 然後editPart來控制visualPart的改變.

圖表 2 4 EditorPartViewer的MVC圖
注意: Visual Part 與Application Model之間沒有任何關係,他們之間的溝通全部通過EditPart進行. 所以:
 EditPartController
 VisualPartView
 Application Model Model

圖表 2 5 EditPart 與Role,EditPolicies關係
EditPart調整模型是如下來進行的.
EditPart將更改的request轉換爲EditPolicy, 然後在EditPolicy制定詳細的操作, EditPolicy進一步轉換爲Command, 然後由Command來完成具體的操作.

2.2.3 GEF一個大致的流程:
(對照參考GEF Developer Guide中的The Steps to Building a GEF Application)
本流程針對http://jtauber.com/2004/gef/gef.zip中的pt1來說:
1. 系統首先打開一個EditorPart, 然後開始一些初始化操作:
2. EditorPart初始化一個模型Diagram;
3. 在Diagram這個model中PropertyChangeListener, PropertyChangeSupport這些類的存在就是爲了監聽模型的改變,如果模型改變了,那麼要告知模型對應的editPart,讓editPart執行相應的操作. 我們可以注意到在editPart類的代碼中有PropertyChangeEvent, PropertyChangeListener類的存在,這些代碼的存在就是對偵聽到的事件進行處理;
4. EditorPart初始化一個setEditDomain(),將EditDomain聯繫起來;
5. EditorPart通過SetInput() 將IEditorInput聯繫起來, 可以將生成的Diagram模型放入到IEditorInput中來;
6. EditorPart要負責生成一個editPartViewer. editPartViewer的主要作用是:要知道他周圍的所有的editParts, 所有的viewPart, 同時將用戶點擊的熱點區域映射到editPart, 由editPart 創建viewPart.下面開始講解editPartViewer的生成過程;
7. EditorPart的configureGraphicalViewer()方法中首先得到EditPartViewer,然後做下面的一些設置:
getGraphicalViewer().setRootEditPart(new ScalableFreeformRootEditPart()) ----設置頂級別的EditPart,
getGraphicalViewer().setEditPartFactory(new PartFactory())----針對每一個模型制定一個editPart,
PartFactory這個類的作用是 針對不同的model給不同的editPart.
到此就達到了一個目的: 每一個model 一一對應起一個edtipart. 於是editpart就可以操作每一個model, 每一個model的改變首先告知對應的editPart, 由editpart來負責通知viewPart的更改;
8. EditorPart的initializeGraphicalViewer()方法的
getGraphicalViewer().setContents(this.diagram);----含義:
根據前面的
configureGraphicalViewer()中的setEditPartFactory()方法,不同的model得到不同的editPart, editorPart將diagram模型植入到editPartViewer中的同時,將diagram模型對應的editpart(DiagramEditPart)置爲頂級別的editPart, 然後 根據DiagramEditPart中的一些方法getModelChildren()得到整個模型,再根據各自的模型得到對應的editPart(例如NodePart),這些editPart中有createFigure(),createEditPolicies(), 完成各個viewPart的創建.到此時爲止editPartViewer構造完成.
9. 總體觀察: 通過editorPart完成了editPartViewer的整體構造.


圖表 2 6 流程圖
下面開始講解針對一個特定事件觸發的流程:
1. 一個模型發生改變,例如Node發生移動. PropertyChangeListener, PropertyChangeSupport,用來監聽model的改變.
addPropertyChangeListener(PropertyChangeListener listener)方法用來將偵聽器加入到model中.
removePropertyChangeListener(PropertyChangeListener listener)方法用來刪除model中的偵聽器.
在NodePart的activate(),deactive()方法中
((Node) getModel()).addPropertyChangeListener(this);
((Node) getModel()).removePropertyChangeListener(this);
上面兩個方法把偵聽器加入到model中.因爲NodePart implements PropertyChangeListener,所以NodePart本身也是一個偵聽器.
2. 然後模型對應的NodePart中的
PropertyChangeEvent, PropertyChangeListener, 可以得到偵聽到的事件,開始做事件處理. propertyChange()方法中開始調用refreshVisuals()方法,這個方法首先對本model做更改,然後通過((GraphicalEditPart) getParent()).setLayoutConstraint(this, getFigure(), rectangle);方法來告知父模型Diagram來做相應的處理.
3. 在每一個editPart中有createEditPolicies()方法來安裝editpolicies,例如這個策略爲CustomXYLayoutEditPolicy,在這個策略中有createAddCommand(),createChangeConstraintCommand()執行一些具體的Commmand(例如SetConstraintCommand), 這個command如何執行又在SetConstraintCommand extends Command類中execute()方法中得到真正的執行.


2.2.4 事件流:

圖表 2 7 事件流圖
Tools allow EditParts and their EditPolicies to focus on high-level operations rather than dealing with raw mouse and keyboard event data.
Eventflow是一個event chain, 可以在中間處理掉後,不讓他繼續傳遞下去,也可以繼續將event傳遞下去.
SWT Control 獲得event, 然後event 繼續下傳,可以被EditPartViewer截獲和處理,接着,還可以繼續下傳給EditDomain,EditDomain來決定是否將event繼續下傳給Current tool.

詳細的事件流程:
1. 用戶點擊相關可視化控件,發出鼠標或者鍵盤的事件.
2. SWT Control 捕獲到鍵盤或者鼠標的事件參考SWT的Canvas接口(SWT Events).
3. 然後將事件傳遞到EditPartViewer中進行處理參考GraphicalViewer和IFigure接口.(實現類爲GraphicalViewerImpl,Figure類) Draw2D系統中的LightWeightSystem,Events.
4. 在EditPartViewer中處理完後,然後繼續將事件傳遞到EditDomain中處理參考EditDomain類,
5. 在EditDomain類處理完成後,繼續將事件傳遞到Active Tool來處理參考SelectionTool,SelectEditPartTracker類 (他們superClass爲TargetingTool類)
6. 至此事件的傳遞完成.接着由Tool產生Request接口類型的request參考SelectionRequest類.
7. EditPart來處理產生的request參考AbstractEditPart中的performRequest()方法, AbstractGraphicalEditPart類.
8. 在EditPart中安裝了EditPolicy參考GraphicalNodeEditPolicy類
9. 在EditPolicy類中創建若干Command, 其中關於redo,undo操作的command 形成CommandStack(實際上就是一個ArrayList),參考CompoundCommand類.
10. 到一定的時候執行Command中的execute方法.

發佈了11 篇原創文章 · 獲贊 3 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章