今天只寫了一小部分,先貼出來,以后繼續。
離開GEF項目組已經一個多月了,但是那段日子給我很深的印象,因為那仿佛是我真正下定決心,學習成為一個好的IT人員之路的開始。而且開始積累編程經驗。GEF并不簡單,面對這個攔路虎,我很是興奮,想把那段時間的學習體會以及我們的項目來個大致的介紹。
我們的項目是一個Eclipse平臺上的用于本體建模的圖形編輯器,大家決定采用GEF框架,因為它非常適合開發帶有調色板的以編輯器為主要部件的應用程序。剛開始一個星期,非常迷茫,不知從何下手。這里要非常感謝八進制的blog,他寫的關于GEF的系列給了我很大的幫助,至今我還有很多沒有完全消化的地方。
一. 入門
我們選取了一個GefPractice的例子作為學習的對象。它的結構很清楚,包劃分得很容易理解(現在發現包的劃分基本是按照gef api中包的劃分來的)。它實現了一個簡單得編輯器的功能,可以創建節點、編輯節點和刪除節點,還可以創建節點之間的連接。它一共劃分了10個包:
1. ui包:這里是用戶界面,主要是編輯器editor,編輯器一般是繼承GraphicalEditorWithPalette,這樣我們就可以得到一個GraphicalViewer和一個PaletteViewer。我認為學習從ui入手比較簡單,因為我們一般和editor接觸比較多,對于GEF內部工作機制的了解也應從editor開始,這樣更直觀。Editor中有幾個重要的概念:
① 在editor的構造函數中,調用setEditDomain()方法,而使用的一般就是DefaultEditDomain(),它是EditDomain的一個默認實現。它是一個GEF程序的狀態集合,包括命令棧,一個或多個EditpartViewer,和當前的活動工具。
② 兩個方法:configureGraphicalViewer()和initialGraphicalViewer(). configureCraphicalViewer()方法中替graphicalViewer設置rootEditPart,設置EditPartFactory。InitalGraphicalViewer()方法中,替graphicalViewer設置contentProvider,一般是畫布(model包中),設置拖放監聽器(這個以后還要重點說明)。
③ GetAdapt()方法,應該是視圖之間的切換(這個現在還不太清楚)。
④ 內部類繼承ContentOutlinePage實現大綱視圖。
2.model包:
模型:GEF的模型只與控制器打交道,而不知道任何與視圖有關的東西。為了能讓控制器知道模型的變化,應該把控制器作為事件監聽者注冊在模型中,當模型發生變化時,就觸發相應的事件給控制器,后者負責通知各個視圖進行更新。
類之間的層次關系
在org.sklse.oed本題編輯器項目中,創建了org.sklse.oed.model包來裝載模型,在設計中,我們結合java程序面向對象的特點,將創建的類抽象成三個層次,如下圖:
根類:AbstractModel.class
AbstractModel作為整個模塊的根類,實現模型層接點和連線公用的監聽接口,屬性變化監聽事件。主要是通過implements IpropertySource來實現的,IpropertySource是eclipse中關于屬性視圖開發方面的接口。
結點父類:AbstractNodeModel.class
該類抽象出結點公用的一些屬性和方法,比如:定義了P_CONSTRAINT、P_TEXT、P_SOURCE_CONNECTION、P_TARGET_CONNECTION等屬性,其中P_CONSTRAINT用來布局的,P_TEXT是模型的名字,而P_SOURCE_CONNECTION、P_TARGET_CONNECTION用來存放模型的源連接和目的連接的鏈表。
然后根據這些屬性定義一系列相關的操作,比如:
public void addSourceConnection(Object connx) {
sourceConnections.add(connx);
firePropertyChange(P_SOURCE_CONNECTION, null, null);
}
上面就是一個很典型的方法,目的是給模型對象添加一個源連接,參數connx表示源連接,sourceConnections.add(connx);是源鏈表的添加方法,firePropertyChange(P_SOURCE_CONNECTION, null, null)方法來激活屬性變化事件。正如mvc模式的思想一樣,在模型被修改的同時,通過消息事件通知控制層(firePropertyChange),后者根據模型變化來修改視圖。
連線父類:AbstractConnectionModel.class
該類抽象出連線公用的一些屬性和方法,連線最重要的屬性就是P_BEND_POINT ,我把它理解成拐點,即可以通過拖動這個拐點來折變連線。一條連線就必須有源接點和目的接點,即source, target,在model層增加一個連線,也就等于在source和target的源接點連表和目的接點鏈表上增加這條記錄。有這類方法:
public void attachSource() {
if (!source.getModelSourceConnections().contains(this))
source.addSourceConnection(this);
}
對于P_BEND_POINT屬性的變化也必須有一套方法:
public void addBendpoint(int index, Point point) {
bendpoints.add(index, point);
firePropertyChange(P_BEND_POINT, null, null);
}
畫板模型:ContentModel.class
編輯區的畫板模型,相當于母版,其他圖形都是添加到它上面的。
//定義一個屬性
public static final String P_CHILDREN = "_children";
//定義一個存放孩子接點的鏈表
private List children = new ArrayList();
public void addChild(Object child) {//添加孩子結點
children.add(child);
firePropertyChange(P_CHILDREN, null, null);//激活屬性變化事件
}