小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

使用圖形編輯框架創(chuàng)建基于 Eclipse 的應(yīng)用程序 [轉(zhuǎn)]

 gujin2006 2007-04-03
使用圖形編輯框架創(chuàng)建基于 Eclipse 的應(yīng)用程序 [轉(zhuǎn)]

Randy Hudson
軟件開發(fā)人員, IBM
2003 年 10 月 10 日

本文描述了使用圖形編輯框架(Graphical Editing Framework,GEF)創(chuàng)建一個(gè)基于 Eclipse 的應(yīng)用程序所涉及的初始步驟。GEF 被用來構(gòu)建各種用于 Eclipse 的應(yīng)用程序,包括狀態(tài)圖、活動圖、類圖、用于 AWT、Swing 和 SWT 的 GUI 構(gòu)建器以及過程流編輯器。Eclipse 和 GEF 都是開放源碼技術(shù)。二者也都包含在 IBM 的 WebSphere Studio 工作臺中。
本文為您從頭到尾地介紹了使用 GEF 的步驟。我們不是完整地完成每個(gè)步驟,而是將使用您的應(yīng)用程序模型的子集,并先使該子集工作。例如,開始我們可能會忽略連接,或者只注重于您應(yīng)用程序中圖形元素類型的子集。

GEF 概述
GEF 假定您擁有一個(gè)希望以圖形方式顯示和編輯的模型。為了做到這一點(diǎn),GEF 提供了可在 Eclipse 工作臺中任何地方使用的查看器(類型為 EditPartViewer )。象 JFace 查看器一樣,GEF 查看器是 SWT 控件上的適配器。但是它們的類似之處僅此而已。GEF 查看器基于模型-視圖-控制器(model-view-controller,MVC)體系結(jié)構(gòu)。

控制器作為視圖和模型之間的橋梁(請參閱圖 1)。每個(gè)控制器(即本文所謂的 EditPart)負(fù)責(zé)將模型映射到它的視圖,也負(fù)責(zé)對模型進(jìn)行更改。EditPart 還觀察模型并更新視圖,以反映模型狀態(tài)中的變化。EditPart 是一種對象,用戶將與這種對象進(jìn)行交互。稍后將更詳細(xì)地介紹 EditPart。 
image  
GEF 提供了兩種查看器類型:圖形的和基于樹的。每種查看器都主管一種不同類型的 視圖。圖形查看器使用了在 SWT 畫布(Canvas)上繪制的 圖形(figure)。圖形是在 Draw2D 插件中定義的,該插件是 GEF 的一部分。TreeViewer 將 SWT 樹和 TreeItem 用于其視圖。

第 1 步. 選定自己的模型
GEF 對于模型一無所知。任何模型類型都可工作,只要它符合下面描述的特性。

模型中有什么?
所有東西都在模型中。模型是唯一會被持久存儲和恢復(fù)的東西。您的應(yīng)用程序應(yīng)當(dāng)將所有重要數(shù)據(jù)都存儲在模型中。在編輯、撤銷和重做的過程中,模型是唯一保持不變的。隨著時(shí)間推移,將對圖形和 EditPart 進(jìn)行垃圾收集處理并重新創(chuàng)建。

當(dāng)用戶與 EditPart 交互時(shí),EditPart 并不直接操作模型。而是創(chuàng)建一個(gè)封裝了更改的 命令(Command)。命令可用來驗(yàn)證用戶的交互,并且提供撤銷和重做支持。

嚴(yán)格地說,命令概念上也是模型一部分。它們 本身并不是模型,而是一些方法,模型是由這些方法編輯的。命令用于執(zhí)行用戶的所有可撤銷的更改。理論上,命令應(yīng)當(dāng)只了解模型。它們應(yīng)當(dāng)避免引用 EditPart 或圖形。類似地,如果可能,命令應(yīng)當(dāng)避免調(diào)用用戶界面(例如彈出式對話框)。

兩個(gè)模型的故事
一個(gè)簡單的 GEF 應(yīng)用程序就是用于繪制圖的編輯器。(這里 圖只意味著圖片,而不是類圖等)圖可以被建模成某些形狀。一個(gè)形狀可能具有位置、顏色等特性,并且可能是多個(gè)形狀構(gòu)成的一組結(jié)構(gòu)。這里沒有什么可驚訝的,并且前述需求也易于維護(hù)(請參閱圖 2)。

圖 2. 一個(gè)簡單的模型
image 
另一種常見的 GEF 應(yīng)用程序是 UML 編輯器,例如類圖編輯器。圖中的一段重要信息就是 (x, y) 位置,類就出現(xiàn)在該位置上。根據(jù)前一節(jié)的介紹,您可能會以為模型必須將一個(gè) 類描述成具有 x和 y特性。大多數(shù)開發(fā)人員都不希望由于無意義的屬性而“污染”其模型。在這類應(yīng)用程序中,術(shù)語“業(yè)務(wù)”模型可用于指代基本模型,重要語義的詳細(xì)信息存儲在基本模型中。而特定于圖的信息存儲在“視圖”模型(它指的是業(yè)務(wù)模型中某樣?xùn)|西的“視圖”;在一個(gè)圖中可多次查看某個(gè)對象)中。有時(shí)候這種劃分甚至?xí)从吃诠ぷ骺臻g中,其中不同的資源可能被分別用來持久存儲圖和業(yè)務(wù)模型。甚至可能有多個(gè)圖對應(yīng)于同一個(gè)業(yè)務(wù)模型(請參閱圖 3)。

圖 3. 劃分成業(yè)務(wù)模型和視圖模型的模型
image 
不管您的模型劃分成了兩個(gè)部分,還是劃分成了多個(gè)資源,對于 GEF 而言這都是無關(guān)緊要的。術(shù)語模型用于指代整個(gè)應(yīng)用程序模型。屏幕上的一個(gè)對象可能對應(yīng)于模型中的多個(gè)對象。GEF 旨在允許開發(fā)人員方便地處理這類映射。

通知策略
對視圖進(jìn)行更新幾乎總是由來自模型的通知而導(dǎo)致的。您的模型必須提供某種通知機(jī)制,該機(jī)制必須映射到您應(yīng)用程序中相應(yīng)的更新。而只讀模型或不能進(jìn)行通知的模型(例如文件系統(tǒng)或遠(yuǎn)程連接)可能是例外。

通知策略通常是分布式的(每對象)或集中式的(每域)。域通知器了解到對模型中任何對象的每次更改,然后將這些更改向域偵聽器廣播。如果您的應(yīng)用程序使用了這種通知模型,您可能要為每個(gè)查看器添加一個(gè)域偵聽器。當(dāng)該偵聽器接收到更改時(shí),它將查找受影響的 EditPart,然后適當(dāng)?shù)刂匦路峙稍摳?。如果您的?yīng)用程序使用了分布式通知,那么每個(gè) EditPart 通常都將把自己的偵聽器添加到任何一個(gè)影響它的模型對象。

第 2 步. 定義視圖
下一步是決定將如何使用來自 Draw2D 插件的圖形顯示您的模型。某些圖形可直接用來顯示模型的某個(gè)對象。例如,Label 圖形可用來顯示 Image 和 String。有時(shí)候,通過組合多個(gè)圖形、布局管理器和/或邊框可以獲得期望的結(jié)果。最后,您可能要編寫自己的圖形實(shí)現(xiàn),該實(shí)現(xiàn)以特定于您應(yīng)用程序的方式繪圖。

有關(guān)組合或?qū)崿F(xiàn)圖形和布局的更多信息可在 Draw2D 開發(fā)人員指南中找到,該指南包含在 GEF SDK 中。

在和 GEF 一起使用 Draw2D 時(shí),通過遵循下列方針,可以使您的項(xiàng)目更便于管理,并且可以更靈活地更改需求:

不要從頭做起。您可以組合所提供的布局管理器以呈現(xiàn)大多數(shù)東西。請考慮使用工具欄布局(在垂直或水平方向上)和邊框布局的組合來組合多個(gè)圖形。只有在萬不得已時(shí)才編寫自己的布局管理器。作為參考,請查看 GEF 中提供的調(diào)色板。該調(diào)色板是使用 Draw2D 中的許多標(biāo)準(zhǔn)圖形和布局呈現(xiàn)的。


保持 EditPart 和圖形之間“徹底”的分離。如果您的 EditPart 使用了幾個(gè)圖形、布局和/或邊框的復(fù)合結(jié)構(gòu),那么請盡量對 EditPart 隱藏詳細(xì)信息。讓 EditPart 自己構(gòu)建所有東西是可能的(但不是個(gè)好主意)。不過這樣做并不會導(dǎo)致控制器和視圖之間“徹底”分離。EditPart 非常熟悉圖形結(jié)構(gòu),因此以類似的 EditPart 重用該結(jié)構(gòu)是不可能的。此外,更改外觀或結(jié)構(gòu)可能會導(dǎo)致意想不到的錯(cuò)誤。

替代方法是,您應(yīng)當(dāng)編寫自己的 Figure 子類,該子類掩藏了圖形結(jié)構(gòu)的詳細(xì)信息。然后定義這個(gè)子類最少數(shù)量的 API,EditPart(控制器)用這些 API 來更新視圖。這種實(shí)踐(稱為 關(guān)注分離(separation of concerns))可提高重用機(jī)會并使錯(cuò)誤更少。


不要從圖形引用模型或 EditPart。圖形不應(yīng)該具有對 EditPart 或模型的訪問權(quán)。在某些情形中,EditPart 可能會將自己作為偵聽器添加到圖形,但是只會認(rèn)為它是偵聽器,而不是 EditPart。這種去耦合(de-coupling)實(shí)踐也可以產(chǎn)生更多的重用機(jī)會。


使用內(nèi)容窗格。有時(shí)候您擁有一個(gè)容器,該容器將包含其它圖形元素,但是您需要在容器四周進(jìn)行一些裝飾。例如,一個(gè) UML 類通常顯示為框,其頂部標(biāo)有類名,可能還有一些原型,而底部是為屬性和方法保留的。通過組合多個(gè)圖形可以做到這一點(diǎn)。第一個(gè)圖形是類的標(biāo)題框,而另一個(gè)圖形被指派為 內(nèi)容窗格。該圖形將最終包含表示屬性和方法的圖形。稍后在編寫 EditPart 實(shí)現(xiàn)時(shí),并不一定要表明應(yīng)該將內(nèi)容窗格用作所有子元素的父元素。
第 3 步. 編寫您的 EditPart - 控制器
接下來我們將利用控制器(即 EditPart)將模型和視圖聯(lián)接起來。該步驟在 GEF 中放置“框架”。所提供的類是抽象的,因此客戶實(shí)際上必須編寫代碼。結(jié)果證明,生成子類不僅是人們熟悉的方法,而且可能也是將模型映射到視圖最靈活和簡單的方法。

所提供的用于生成子類的基本實(shí)現(xiàn)有三種。對于出現(xiàn)在樹查看器中的 EditPart 使用 AbstractTreeEditPart 。圖形查看器中的繼承 AbstractGraphicalEditPart 和 AbstractConnectionEditPart 。本文將著重討論圖形 EditPart。相同的原理同樣適用于樹查看器。

EditPart 生命周期
在編寫您的 EditPart 之前,了解它們來自哪里,以及當(dāng)不再需要它們時(shí)怎樣處理它們,這是有幫助的。每個(gè)查看器都配置有一個(gè)用于創(chuàng)建 EditPart 的工廠(factory)。當(dāng)您設(shè)置查看器的內(nèi)容時(shí),通過提供表示該查看器輸入的模型對象,可以做到這一點(diǎn)。輸入通常是最頂部的模型對象,通過該對象可遍歷其它所有對象。然后查看器可以使用自己的工廠來構(gòu)造用于該輸入對象的 內(nèi)容 EditPart。之后,查看器中的每個(gè) EditPart 將填充和管理其自己的子 EditPart(和連接 EditPart),當(dāng)需要新的 EditPart 時(shí),將委派給 EditPart 工廠,直到填充該查看器。當(dāng)用戶添加新的模型對象時(shí),包含這些對象的 EditPart 將通過構(gòu)造相應(yīng)的 EditPart 做出響應(yīng)。請注意,視圖的構(gòu)造與 EditPart 的構(gòu)造是同時(shí)進(jìn)行的。因此,構(gòu)造每個(gè) EditPart 并將它添加到它的父 EditPart 之后,視圖(不管是圖形還是樹項(xiàng))也會發(fā)生同樣的過程。

一旦用戶除去與某些 EditPart 對應(yīng)的模型對象,就丟棄這些 EditPart。如果用戶撤銷了一個(gè)刪除操作,那么用于表示被恢復(fù)對象而重新創(chuàng)建的 EditPart 與原先的 EditPart 是不同的。這就是為什么 EditPart 不能包含長期信息,以及為什么不應(yīng)由命令引用的原因。

您的第一個(gè) EditPart:內(nèi)容 EditPart
您編寫的第一個(gè) EditPart 是對應(yīng)于圖本身的 EditPart。這個(gè) EditPart 稱為查看器的 內(nèi)容。它對應(yīng)于模型中最頂部的元素,并且其父元素為查看器的 根EditPart(請參閱圖 4)。根通過提供各種圖形層(例如連接層和句柄層等)以及可能會在查看器級別提供的視圖縮放或其它功能,為內(nèi)容打下基礎(chǔ)。請注意,根的功能不依賴于任何模型對象,GEF 為根提供了幾個(gè)現(xiàn)成的實(shí)現(xiàn)。

圖 4. 查看器中的 EditPart
image 
內(nèi)容的圖形不是很有趣,并且它通常只是一個(gè)空面板,該面板將包含圖的子圖。它的圖形應(yīng)該為不透明類型(opaque),并且應(yīng)當(dāng)利用布局管理器進(jìn)行初始化,該布局管理器將對圖的子圖進(jìn)行布局。但是,它將擁有結(jié)構(gòu)。圖的直系子圖是由返回的子模型對象列表確定的。清單 1 顯示了一個(gè)樣本內(nèi)容 EditPart,它創(chuàng)建了一個(gè)不透明類型的圖形,后者將使用 XYLayout 定位其子圖。

清單 1. 內(nèi)容 EditPart 的初始實(shí)現(xiàn)

public class DiagramContentsEditPart extends AbstractGraphicalEditPart {
protected IFigure createFigure() {
Figure f = new Figure();
f.setOpaque(true);
f.setLayoutManager(new XYLayout());
return f;
}

protected void createEditPolicies() {
...
}

protected List getModelChildren() {
return ((MyModelType)getModel()).getDiagramChildren();
}
}



要確定圖上的項(xiàng),需要實(shí)現(xiàn)方法 getModelChildren() 。該方法返回子模型對象的列表(例如圖中的節(jié)點(diǎn))。超類將使用這個(gè)模型對象列表來創(chuàng)建對應(yīng)的 EditPart。新創(chuàng)建的 EditPart 被添加到部件的子 EditPart 列表。這樣又會將每個(gè)子 EditPart 的圖形添加到示例圖。缺省情況下,將返回一個(gè)空的列表,這表明沒有子對象。

其它圖形 EditPart
其余的 EditPart(表示圖中的項(xiàng))可能擁有要以圖形方式顯示的數(shù)據(jù)。它們可能還擁有自己的結(jié)構(gòu),例如連接或自己的子 EditPart。許多 GEF 應(yīng)用程序利用由標(biāo)簽注明的圖標(biāo)之間的連接來描述這些圖標(biāo)。讓我們假定您的 EditPart 將使用 Label 作為它的圖形,并且您的模型提供了名稱、圖標(biāo)以及與標(biāo)簽之間的連接。清單 2 顯示了實(shí)現(xiàn)這種類型 EditPart 的第一次嘗試。

清單 2. “節(jié)點(diǎn)”EditPart 的初始實(shí)現(xiàn)

public class MyNodeEditPart extends AbstractGraphicalEditPart {
protected IFigure createFigure() {
return new Label();
}
protected void createEditPolicies() {
...
}
protected List getModelSourceConnections() {
MyModel node = (MyModel)getModel();
return node.getOutgoingConnections();
}
protected List getModelTargetConnections() {
MyModel node = (MyModel)getModel();
return node.getIncomingConnections();
}
protected void refreshVisuals() {
MyModel node = (MyModel)getModel();
Label label = (Label)getFigure();
label.setText(node.getName());
label.setIcon(node.getIcon());

Rectangle r = new Rectangle(node.x, node.y, -1, -1);
((GraphicalEditPart) getParent()).setLayoutConstraint(this, label, r);
}
}



這里覆蓋了一個(gè)新方法 refreshVisuals() 。當(dāng)需要利用來自模型的數(shù)據(jù)更新圖形時(shí),就調(diào)用該方法。在本案例中,模型的名稱和圖標(biāo)被反映在標(biāo)簽中。但更為重要的是,該標(biāo)簽是通過將其布局約束傳遞給父元素來定位的。在內(nèi)容 EditPart 中,我們使用了 XY 布局管理器。該布局使用 Rectangle 約束來確定在何處放置子圖形。寬和高的值為“-1”,表明應(yīng)當(dāng)為該圖提供理想的大小。

技巧 #1
決不要使用 setBounds(...) 方法來放置圖形。使用諸如 XYLayout 之類的布局管理器確保會正確地更新滾動條。另外,XYLayout 還處理將相對約束轉(zhuǎn)換成絕對位置的工作,并且可用它來將圖形自動調(diào)整為理想的大?。〒Q而言之,如果約束的寬和高為 -1)。


方法 refreshVisuals() 僅在 EditPart 初始化的過程中調(diào)用一次,并且決不會被再次調(diào)用。在響應(yīng)模型通知時(shí),應(yīng)用程序負(fù)責(zé)根據(jù)需要再次調(diào)用 refreshVisuals() 以更新圖形。要改進(jìn)性能,您可能希望將每個(gè)模型屬性的代碼分解成其自己的方法(或者是一個(gè)帶有“開關(guān)(switch)”的方法)。這樣,當(dāng)模型發(fā)出通知時(shí),可以運(yùn)行最少的代碼以便只刷新那些發(fā)生更改的內(nèi)容。

另一個(gè)有趣的區(qū)別是連接支持的代碼。與 getModelChildren() 類似, getModelSourceConnections() 和 getModelTargetConnections() 應(yīng)當(dāng)返回表示節(jié)點(diǎn)之間連接的模型對象。超類在必要時(shí)創(chuàng)建對應(yīng)的 EditPart,并將它們添加到源和目標(biāo)連接 EditPart 列表。請注意,連接是由每端的節(jié)點(diǎn)引用的,而其 EditPart 只需創(chuàng)建一次。GEF 確保只創(chuàng)建一次連接,該工作是通過首先檢查查看器中是否已經(jīng)存在連接來完成的。

建立連接
編寫連接 EditPart 實(shí)現(xiàn)沒有太大的區(qū)別。首先生成 AbstractConnectionEditPart 的子類。跟前面一樣,可以實(shí)現(xiàn) refreshVisuals() ,以將屬性從模型映射到圖形。連接可能還擁有約束,盡管這些約束與前面的約束略有不同。這里,連接路由器使用約束來使連接轉(zhuǎn)向(bend)。此外,連接 EditPart 的圖形必須是 Draw2D Connection ,它引入了另一個(gè)需求:連接錨(connection anchor)。

連接必須由 ConnectionAnchor “錨定”在兩端。因此,必須在連接 EditPart 中或在節(jié)點(diǎn)實(shí)現(xiàn)中表明使用哪些錨。缺省情況下,GEF 假定節(jié)點(diǎn) EditPart 將通過實(shí)現(xiàn) NodeEditPart 接口而提供錨。這樣假定的一個(gè)原因是,錨的選擇取決于各端上的節(jié)點(diǎn)正在使用的圖形。連接 EditPart 不應(yīng)了解節(jié)點(diǎn)正在使用的圖形的任何內(nèi)容。另一個(gè)原因是,當(dāng)用戶創(chuàng)建連接時(shí),連接 EditPart 是不存在的,因此節(jié)點(diǎn)必須能夠自己顯示反饋。作為清單 2 的延續(xù),我們在清單 3 中添加了必要的錨支持。

清單 3. 將錨支持添加到“節(jié)點(diǎn)”EditPart

public class MyNodeEditPart
extends AbstractGraphicalEditPart
implements NodeEditPart
{
...
public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) {
return new ChopboxAnchor(getFigure());
}
public ConnectionAnchor getSourceConnectionAnchor(Request request) {
return new ChopboxAnchor(getFigure());
}
public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) {
return new ChopboxAnchor(getFigure());
}
public ConnectionAnchor getTargetConnectionAnchor(Request request) {
return new ChopboxAnchor(getFigure());
}

...
}



技巧 #2
別忘記真正實(shí)現(xiàn) NodeEditPart 接口。否則您的方法將永遠(yuǎn)不會被調(diào)用。


以連接(connection)為參數(shù)的方法是對現(xiàn)有連接 EditPart 設(shè)置錨時(shí)使用的方法。其它兩個(gè)方法以請求(request)作為參數(shù)。這些方法是用戶創(chuàng)建新連接時(shí)的編輯過程中使用的。對于本示例,所有情形都將返回 chopbox 錨。chopbox 錨只查找線與節(jié)點(diǎn)圖形的邊框相交的點(diǎn)。

實(shí)現(xiàn)連接 EditPart 是比較簡單的。請注意,甚至無需創(chuàng)建圖形,因?yàn)槿笔〉?PolylineConnection 創(chuàng)建適合于大多數(shù)場合(請參閱清單 4)。

清單 4. 初始的連接 EditPart 實(shí)現(xiàn)

public class MyConnectionEditPart extends AbstractConnectionEditPart {
protected void createEditPolicies() {
...
}

protected void refreshVisuals() {
PolylineConnection figure = (PolylineConnection)getFigure();
MyConnection connx = (MyConnection)getModel();
figure.setForegroundColor(MagicHelper.getConnectionColor(connx));
figure.setRoutingConstraint(MagicHelper.getConnectionBendpoints(connx));
}
}



技巧 #3
最重要的是了解何時(shí)使用以及何時(shí)不使用 ConnectionEditPart。當(dāng)用戶可以選擇某些東西并可與之進(jìn)行交互的時(shí)候,就使用連接 EditPart。它可能與模型中的某個(gè)對象直接相關(guān),并且通??捎勺约簞h除。

如果您只是擁有一個(gè)需要繪制直線的節(jié)點(diǎn)或容器,那么只須用圖形的 paint 方法繪制直線,或者組合一個(gè)圖形,該圖形包含 Polyline 圖形。

連接始終都必須擁有源和目標(biāo)。如果您需要一個(gè)連接,該連接可以在沒有源或沒有目標(biāo)的情況下存在,那么比較好的方法是只繼承 AbstractGraphicalEditPart ,并使用連接圖形。


偵聽模型
創(chuàng)建 EditPart 之后,它應(yīng)該開始偵聽來自模型的更改通知。由于 GEF 是與模型無關(guān)的,因此所有應(yīng)用程序都必須添加自己的偵聽器,并處理產(chǎn)生的通知。接收到通知時(shí),處理程序可以調(diào)用某個(gè)提供的方法來強(qiáng)制進(jìn)行一次刷新。例如,如果刪除了一個(gè)子模型對象,那么調(diào)用 refreshChildren() 將導(dǎo)致對應(yīng)的 EditPart 及其圖形被除去。對于簡單的屬性更改,可以使用 refreshVisuals() 。正如我們前面提及的,可將該方法分解成幾個(gè)部分,從而避免沒有必要地更新每個(gè)顯示的屬性。

添加偵聽器但卻忘記除去它們是導(dǎo)致內(nèi)存泄漏的常見原因。出于這個(gè)原因,添加和除去偵聽器的地方應(yīng)該在 API 中清晰地注明。您的 EditPart 必須繼承 activate() ,以便添加稍后必須除去的任何偵聽器。通過繼承 deactivate() 可除去那些相同的偵聽器。清單 5 顯示了向節(jié)點(diǎn) EditPart 實(shí)現(xiàn)添加的模型通知內(nèi)容。

清單 5. 偵聽“節(jié)點(diǎn)”EditPart 中的模型更改

public class MyNodeEditPart
extends AbstractGraphicalEditPart
implements NodeEditPart, ModelListener
{
...

public void activate() {
super.activate();
((MyModel)getModel()).addModelListener(this);
}

public void deactivate() {
((MyModel)getModel()).removeModelListener(this);
super.deactivate();
}

public void modelChanged(ModelEvent event) {
if (event.getChange().equals("outgoingConnections"))
refreshSourceConnections();
else if (event.getChange().equals("incomingConnections"))
refreshTargetConnections();
else if (event.getChange().equals("icon")
|| event.getChange().equals("name"))
refreshVisuals();
}

...
}



編輯模型
到目前為止,我們已經(jīng)講解了如何創(chuàng)建 EditPart,它們?nèi)绾蝿?chuàng)建自己的可視圖(visual)以及當(dāng)模型發(fā)生變化時(shí)它們?nèi)绾巫晕腋?。除此之外,EditPart 也是對模型進(jìn)行更改的主要參與者。當(dāng)命令的請求被發(fā)送給 EditPart 時(shí)就會發(fā)生這種情況。請求還用來要求 EditPart 顯示諸如在鼠標(biāo)拖動期間發(fā)生的反饋。EditPart 支持、阻止或忽略給定的請求。所支持或阻止的請求類型決定了 EditPart 的行為。

到目前為止,側(cè)重點(diǎn)都是將模型的結(jié)構(gòu)和特性映射到視圖。結(jié)果表明,這基本上是您在 EditPart 類自身中所做的所有工作。其行為是由一組名為 EditPolicies 的可插入的助手類決定的。在所提供的示例中,我們忽略了方法 createEditPolicies() 。一旦您實(shí)現(xiàn)該方法,您就幾乎已經(jīng)完成了您的 EditPart。當(dāng)然,您仍需要提供編輯策略,該策略知道如何修改您應(yīng)用程序的模型。

因?yàn)榫庉嬓袨槭强刹迦氲?,所以在開發(fā)各種 EditPart 實(shí)現(xiàn)時(shí),可以根據(jù)將模型映射到視圖和處理模型更新這種任務(wù),來創(chuàng)建類層次結(jié)構(gòu)。

第 4 步. 將所有內(nèi)容組合在一起
現(xiàn)在,您已經(jīng)完成了以圖形方式顯示您的模型所需的所有部分。對于最后的組裝,我們將使用 IEditorPart 。但是,也可以在視圖、對話框或者可以放置控件的幾乎任何地方使用 GEF 的查看器。對于本步驟,您必須擁有自己的 UI 插件,它將為正在打開的資源定義編輯器和文件擴(kuò)展名??稍谕粋€(gè)插件或一個(gè)不同的插件中定義您的模型。您還需要一個(gè)預(yù)填充的模型,因?yàn)槟壳斑€沒有編輯功能。

提供樣本模型數(shù)據(jù)的方法有幾種。對于本示例而言,當(dāng)編輯器打開時(shí),我們將在代碼中創(chuàng)建模型,從而忽略了文件的實(shí)際內(nèi)容。要做到這一點(diǎn),我們假定已經(jīng)存在一個(gè)測試工廠?;蛘?,您可以創(chuàng)建一個(gè)示例向?qū)В撓驅(qū)в脭?shù)據(jù)對資源進(jìn)行預(yù)填充(普通向?qū)е粍?chuàng)建空圖)。最后,您可以利用文本編輯器以手工方式編寫文檔的內(nèi)容。

既然您有了樣本模型,那么讓我們創(chuàng)建將顯示模型的編輯器部件。有一種快速的方法,就是生成子類或復(fù)制 GEF 的 GraphicalEditor 。該類創(chuàng)建 ScrollingGraphicalViewer 的一個(gè)實(shí)例,并且構(gòu)造一個(gè)畫布來充當(dāng)編輯器的控件。它是一個(gè)很方便的類,用來幫助您開始使用 GEF;一個(gè)可以正確工作的 Eclipse 編輯器需要考慮很多其它事情,例如不利的團(tuán)隊(duì)環(huán)境(pessimistic team environment)和要刪除或移動資源等。

清單 6 顯示了一個(gè)樣本編輯器實(shí)現(xiàn)。有幾個(gè)必須實(shí)現(xiàn)的抽象方法。出于本文所討論范圍的限制,我們將忽略模型持久性和標(biāo)記。要讓您的圖出現(xiàn)在圖形查看器中,您必須做兩件事情。首先,利用自己的 EditPart 工廠配置查看器,以從第 3 步構(gòu)造 EditPart。然后,將圖模型對象傳遞給查看器。

清單 6. 實(shí)現(xiàn)您的編輯器部件(Editor Part)

public class MyEditor extends GraphicalEditor {
public MyEditor() {
setEditDomain(new DefaultEditDomain(this));
}

protected void configureGraphicalViewer() {
super.configureGraphicalViewer(); //Sets the viewers background to System "white"
getGraphicalViewer().setEditPartFactory(new MyGraphicalEditpartFactory());
}

protected void initializeGraphicalViewer() {
getGraphicalViewer().setContents(MagicHelper.constructSampleDiagram());
}
public void doSave(IProgressMonitor monitor) {
...
}
public void doSaveAs() {
...
}
public void gotoMarker(IMarker marker) {
...
}
public boolean isDirty() {
...
}
public boolean isSaveAsAllowed() {
...
}
}



接下來的步驟
我們已經(jīng)經(jīng)歷了從僅擁有一個(gè)模型到在圖形編輯器中顯示該模型的全過程。但是我們只打下了基礎(chǔ)。我們簡要提及了編輯策略。通過閱讀與 GEF SDK 一起提供的開發(fā)人員文檔,可以獲得有關(guān)編輯策略的更多信息。還可從 GEF 的主頁(請參閱文章結(jié)尾的 參考資料)獲得一個(gè)示例,該示例演示了如何使用各種編輯策略類型。

GEF 還提供了一個(gè)調(diào)色板。該調(diào)色板顯示了一組工具,用于在圖中創(chuàng)建對象。用戶可以激活這些工具,或者使用本機(jī)拖放直接從該調(diào)色板拖動項(xiàng)。它還支持讓用戶定制內(nèi)容。

在 GEF 中還可以使用幾個(gè) JFace 操作。應(yīng)用程序可以在菜單、工具欄或上下文菜單中使用諸如撤銷、對齊和刪除之類的操作。

最后,您的應(yīng)用程序應(yīng)當(dāng)支持大綱(outline)視圖和特性(properties)視圖。大綱視圖用于導(dǎo)航和有限的編輯用途。GEF 的 TreeViewer 和/或概述(overview)窗口可以在這里使用。特性表(property sheet)允許用戶查看和編輯任何當(dāng)前選定項(xiàng)的詳細(xì)特性。

為了顯示所選擇的項(xiàng)并允許用戶進(jìn)行更改,您必須將編輯策略添加到 EditPart。請參閱 GEF 主頁上的示例,并參閱與 GEF SDK 一起提供的開發(fā)人員文檔。

有關(guān) GEF 和 Eclipse 工作臺提供的其它功能的詳細(xì)信息不在本文的討論范疇之內(nèi),但是您可能有興趣對它們稍做了解:

調(diào)色板。該工具的調(diào)色板是用于在圖中創(chuàng)建新對象的 實(shí)際方法。GEF 包含了一個(gè)功能豐富的調(diào)色板,它支持拖放、多繪圖程序和布局設(shè)置,如果應(yīng)用程序希望,它甚至可支持讓用戶定制內(nèi)容。
操作欄。編輯器(Editor)和視圖(View)可以為工具欄、菜單和上下文菜單提供操作(Action)。GEF 提供了幾個(gè)可重用的操作實(shí)現(xiàn),但是將它們顯示在什么地方取決于應(yīng)用程序。
特性表。特性表可用于顯示所選項(xiàng)特性的詳細(xì)信息。GEF 允許您在 EditPart 上或在模型中添加特性表支持。
大綱。大綱視圖通常用于顯示圖的結(jié)構(gòu)化表示,但是一般來說,它可用于任何工作。GEF 的 TreeViewer 通常在大綱視圖中使用。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多