#
http://dev.eclipse.org/mhonarc/lists/gef-dev/msg00183.html
Ask:
How to add a double click event or Request on a figure?when double click on a figure, a dialog pop up and do some actions.for example when double click on
a UML class figure, a dialog pop up, user can Add a method to the class.
Answer:
This is already done in GEF. Your editpart will receive a performRequest(req) with the type RequestConstants.REQ_OPEN.
See SelectEditPartTRacker#performOpen()
-randy
就是在figure對應的editpart中重載方法performRequest(Request req),并判斷req的type是否為RequestConstants.REQ_OPEN,如果是,則處理這個雙擊事件.
這個方法是個回調方法,在SelectEditPartTRacker#performOpen() 中調用的.
在GEF中一個容器圖形,其中可以盛放其他圖形,但我在實現是總是在坐標計算上出問題,就是其子圖形的坐標并不是相對于此容器的坐標,而是畫布的坐標,后來參考了Logical的例子,發現它在org.eclipse.gef.examples.logicdesigner.figures.CircuitFigure類中重載了useLocalCoordinates方法,返回了true(默認是false),在我的容器圖形(繼承于org.eclipse.draw2d.Figure)也重載這個函數,子圖形的坐標問題就解決了.
摘要: http://dev2dev.bea.com.cn/bbs/thread.jspa?forumID=125&threadID=27195
Design Pattern Practice 1.序 本文從一個簡單的多列排序的例子入手,由淺入深地講解Design Pattern(設計模式)的目的、分析和實踐。 文中的例子用到Compositor Pattern和Decora...
閱讀全文
上文提到的GEF工作過程中還有一些不太詳細的地方,這里做些補充。
再GEF中UI的操作交互都是通過構建Request,并調用EditPart中的API來完成相應的操作,這些API可以分為四類:
1。??EditPart getTargetEditPart(Request)
???boolean understandsRequest(Request)
再我們進行交互操作時,首先要確定激活的是那個EditPart,經常是一個當前被選中的viewer和通過單擊選擇的EditPart的復合體。這個被選擇的部件通過詢問每個被選擇的EditPart是否處理這個request(通過understandsRequest方法)。那個在鼠標單擊確定的EditPart是通過viewer的幫助和getTargetEditPart方法來找到的。并不是所有的交互都有target。
2。
void showSourceFeedback(Request)
void eraseSourceFeedback(Request)
void showTargetFeedback(Request)
void eraseTargetFeedback(Request)
在我們的交互操作特別是托拽圖形時,就需要EditPart來回顯(Feedback),托拽源被認為是起作用的那個editpart,目的部件被認為是鼠標的目的地。showXXXFeedback可能是在鼠標移到目的地,但未作用于目的part時調用,eraseXXXFeedback則可能是在鼠標作用于目的part后調用的。
3。Command getCommand(Request)
這個方法用于獲得可執行的命令列表,命令可以對模型進行操作,Editpart通過request詢問Editpolicy來獲得相應的command列表。同時command也可以判斷這個交互操作是否時可能的。如果沒有command或者command不能執行,則ui會指出這個操作是不能執行的(鼠標變成禁止操作的樣子)。如果一個editpart返回null作為command則它不會阻止這個交互操作,除非沒有一個command被提供。為了指示某個操作是不能執行的則EditPart需要返回一個不能執行的command。
4。void performRequest(Request)
還有一種API,它讓EditPart去do something,可能是一些并不會立即就改變model的改變,比如打開對話框或者激活直接編輯模式。
??????? EditPart并不直接進行編輯,它將操作委托給EditPolicy,每個EditPolicy專著于一種編輯任務或者一組相關的操作。當上面的API被調用后(除了performRequest方法),EditPart便委托給它的EditPolicy來處理這個request。對于不同的方法,EditPart可能是在第一個能處理request的policy處就停止調用了或者每個policy都有機會執行這個request。GEF提供了幾個默認的policy,不過還是需要實現其中的一些特定方法。
???????? 這里再廢話一點,在注冊相應的EditPolicy時,需要指定Role,這是一個字符串,用來標示這個EditPolicy,相同的Role對應的EditPolicy會被替換,例如子類可以通過Role這個Key來覆蓋其父類所安裝的EditPolicy。EditPolicy(Role)分成兩種類型,一種是圖形的,一種是非圖形的,上文中有提到,這里詳細的描述一下:
Non-Graphical Roles:
1) COMPONENT_ROLE: 一個Component存在于一個parent中,并且可以從parent中刪除。更為一般的,它可以使任何只涉及到這個EditPart,而與View無關的東西。(More generally, it is anything that involves only this EditPart.)
2) CONNECTION_ROLE 這是ConnectionEditParts應該有的一個基本角色。Connections同Components有一點不同,刪除Connections時通常還需要其從其source和target節點中刪除,而不是從其parent中刪除。
3) CONTAINER_ROLE 大部分擁有children的EditParts都應該具有這個角色。一個Container會涉及到adds/orphans以及creates/deletes等操作。
4) NODE_ROLE 如果一個EditParts用戶Connection,則其應該具有這個角色,它可以用來創建,刪除,重新連接一個Connection。
Graphical Roles:
1) PRIMARY_DRAG_ROLE: 用來允許用戶拖動這個EditPart。用戶可以通過點擊這個EditPart然后拖動,或者點擊這個EditPart所創建的一個Handle來進行拖動。
2) LAYOUT_ROLE: Layout角色用來放在一個Container的EditPart上,這個EditPart擁有一個graphical layout。如果這個layout有constraints,則它需要通過計算來得到這個constraints。
3) GRAPHICAL_NODE_ROLE: A node supports connections to terminals. When creating and manipulating connections, EditPolicies with this role might analyze a Request's data to perform "hit testing" on the graphical view and determine the semantics of the connection. 用于支持連接到重點的node,當創建、操作連接時,包含這個Role的Editpolicy會分析request的數據,來在圖形view上做“hit testing”,并且判斷這個connection的語義。
4) CONNECTION_ENDPOINTS_ROLE: 這個Role允許用戶拖動一個ConnectionEditPart的端點。
5) CONNECTION_BENDPOINTS_ROLE: 這個Role允許用戶能夠在一個Connection中間拖動和創建bendpoints。
6) SELECTION_FEEDBACK_ROLE: 這個角色只是用來顯示feedback。當鼠標進入或者在一個EditPart上暫停時,Selection Tool會發送兩個類型的request給EditPart。安裝了這個角色的EditPart能夠在此時接受這些請求來改變view的樣子,或者彈出tip,label等。
7) TREE_CONTAINER_ROLE: SWT Tree的Layout Role。 本地SWT Tree的Layout Role的等價物。這個EditPolicy應該在樹上顯示反饋并計算索引,就像在file explorer里拖拽一樣。
over。
??????? GEF中的起到關鍵作用的是EditPart,而EditPart中起到關鍵作用的是EditPolicy,現在來描述一下GEF是如何創建一個圖形并顯示顯示出來的。
??????? 首先通過單擊調色板,會調用一個實現org.eclipse.gef.requests.CreationFactory接口的工廠類,這個是我們在注冊相應的ToolEntry時聲明的,通過傳入的參數這個工廠類就知道應該創建一個什么類型的model元素。(注意,這時候因為我們只是純創建了一個模型元素,對于它的父元素,位置信息等等都還不清楚,所以一般我們在設置模型元素的構造函數時需要有個無參數的構造方法(或者有默認參數的構造函數)。)
??????? 當單擊畫布上的某個位置后,相應的信息比如 模型的父元素,位置信息等等都已經可以確定,將這些信息以及新創建的模型元素本身包裝成request傳給相應的EditPart(就是鼠標單擊處所在的圖形元素對應的EditPart)。
??????? 這個EditPart會將這個request傳給相應的EditPolicy(至于怎么傳遞,還不清楚,估計是這樣的,EditPart會傳給注冊在其上的所有EditPolicy,而每個EditPolicy都有個getCommand方法,通過request的type交給相應的getXXXCommand方法。查看了一下源代碼,發現在AbastractEditPart中有個getCommand方法正是將每個EditPolicy中的getCommand方法都調用了一遍)。
???????然后EditPolicy處理相應的request,具體的就是調用getXXXCommad方法得到處理相應request的Command,Command是可以改變模型。上面提到的這種EditPolicy屬于NonGraphical類型,GEF中還包括了一種稱為Graphical類型的EditPolicy,這種EditPolicy不對模型進行處理,只是用來修改圖形顯示(似乎這種說法不正確,它可以更改視圖元素的位置,在業務模型和視圖模型統一的情況下,這種圖形EditPolicy也會更改模型);而NonGraphical的EditPolicy則是不清楚圖形元素的,但它可以對模型進行更改,因此這種EditPolicy在不同view之間是可以通用的。
?????? 當模型發生改變后,注冊再其上的EditPart將會得到相應的通知,此時,通過通知中的property信息,EditPart會refreshVisual或者refreshChildren,從而使視圖發生改變。
最近在用javasvn做一個svn的管理程序,用rcp實現,在實現過程中發現,如果只是單純的用java程序實現目錄列表的時候,一切正常,但使用rcp后始終出錯,認證錯誤,觀察javasvn源代碼后發現,在定義認證manager的時候javasvn會檢測是否在使用eclipse,如果是,則定義一個eclipseAuth××manger,后來修改了相應的代碼,不調用那個檢測是否為eclipse的方法后就ok了,估計是在eclipse中使用javasvn會有特殊性,故加了此段代碼,不過簡單的rcp是不需要的。
Draw2D學習
Draw2D is a lightweight system.輕量級系統,指這個繪圖系統全部建立在一個重量級的控件上。對于Draw2D他是建立在SWT的Canvas上的。
Draw2D的幾個部分
1.figures
主要功能:
1。給一個figure注冊和去注冊監聽器。這個figure會通知在這個figure中的鼠標時間給監聽器。
2。結構化的事件。比如figure層次的結構化變化,figure的移動和大小調整。
3。當光標從figure上移過時,光標的改變和顯示。
4。在figure的層次中操作figure的位置,包括添加移除訪問子節點,或者訪問他們的父節點。
5。存取:figure的layout manager;figure的size和location;還有tooltips。
6。設置獲得焦點。
7。設置figure的透明度和可視性。
8。進行坐標變換,figure的交疊和碰撞檢測。
9。繪制。
10。確認。
figure有很多subclass,提供了很多附加的功能。比如
1。shape,它包含了非矩形的figure,可以知道如何填充,并提供了對邊界的寬和類型的配置,并提供了異或的繪制方法。比如有橢圓,幾何線,多邊形,矩形,圓角矩形和三角形。
2。widget,draw2d包含的figure允許你創建輕量級(lightweight)的部件(widget),從而在你的draw2d應用程序中需要輸入控制時提供支持。這包含大量的按鈕,選擇框和文本圖形,標簽。
3。layer and pane,這些使用來作為子類的容器,他們提供了縮放,滾動和講figure放置在不同layer上的能力。
圖形上下文(the graphics context)
當一個figuer需要被繪制的時候輕量系統會調用fiuger的一個paint方法。每一個figure都會得到一個graphical context,他是Graphics的一個實例。作為參數傳給paint方法。這個繪圖上下文支持圖形操作包括繪制,填充圖形繪制它的文字。它也提供了圖形的狀態,這些可以影響圖形操作。這些狀態包括當前字體,背景前景顏色等等。
2.LightweightSystem
LightweightSystem時draw2d的核心。它提供了SWT Canvas控件和在其上建立的draw2d系統之間的映射。包含三個方面:
1。the root figure.這個是LightweightSystem$RootFigure類的一個實例。這個是用戶的root figure的父類。它繼承了一些基于SWT Canvas的圖形環境,比如字體,前景背景顏色。
2。the event dispatcher:SWTEventDispatcher類將SWT事件傳給Draw2D的root figure中相應的部件。
3。the update manager.它負責繪制并更新Draw2dfigure。當一個繪制請求從下層的SWTcanvas傳來時,LightWeightSystem將會調用updatemanager中的performUpdate方法。update manager將會維護一個非法的或者需要重畫的figure的worklist。upate manager會設法盡量連續的它的work list,這樣可以盡量的提高效率。默認的update manager:DaferredUpdateManager允許通過再Display上的用戶線程來使工作隊列異步的更新。
對于一個figure的生存周期中,繪制(painting)和確認(validating)是主要的處理過程。draw2d會要求一個figure,調用繪制方法來遞歸的繪制自己。paint()方法會調用多個繪制方法:
1。paintFigure():figure遞歸的繪制自己
2。paintclientarea(): figure遞歸的繪制子圖
3。paintborder():figure繪制邊界。
當一個figure的size或者location需要重新計算時,將會調用確認。
1。validate():要求figure的layout manager去重新布局它的子圖
2。revalidate():調用invalidate;添加一個圖形和它的祖先去更新update manager的invalid list。
現在來討論一下emf所生成的幾個plugin。一般通過ecore模型可以生成三個插件分別是emf模型,emf.edit和emf.editor。
讓我們現在看模型插件
對于所有的EPackage,都會生成兩個或三個java package,本別是base package(*),implemention package(*.impl),tool package(*.util)。其中,第三個包是可選的,這取決于生成屬性的設置,默認是生成。包名(*)也是在生成屬性中設置的。
對于所有EClass,在base package中生成相應的interface,而其java實現則在impl包中,如果一個EClass繼承于另一個EClass,那么生成的interface和implemention都繼承于相應的超類的interface和implemention。如果這個類有多個超類,那么在eSuperTypes中的第一個class將作為主超類(primary supertype)。對于這個子類的實現它將繼承主超類的實現,并且實現其他超類接口中的方法。
對于Feature,getter和setter方法在類和接口中被定義。如果一個一個feature(成員變量)不是volatile,那么它的值會被存儲在一個量值(field)中。如果一個feature是只讀的,那么只生成它對應的getter方法。對于多值屬性一般使用EList表示,而單值就用那個屬性的類型表示。EList的類型取決于模型的約束,例如,一個non-containment reference將會使用EObjectWithInverseResolvingEList,對于一個containment reference將會使用EObjectContainmentWithInverseEList表示。
對于Operation,在包含類(containing class)的接口中生成一個公共方法標簽,在對應的實現中生成實現骨架。
對于DataType,其中EEnum產生于一個繼承了org.eclipse.common.util.AbstractEnumerator的實現。對于其他的EDataType,是沒有接口和實現生成的,它們的實例化類就是直接使用了EAttribute的類型。
再來看看edit插件:
對于edit插件provider package中的所有類都有相應的ItemProviders類生成。更進一步,對于整個插件有一個EMFPluginClass生成。ItemProvider類繼承于org.eclipse.emf.edit.provider.ItemProviderAdaptor,用于適配模型中相應的EObject(所有emf類的基類)。當模型對象由于fireNotifyChanged()改變,ItemProvider會傳送相應的通知,并過濾其他的。當你生成插件時,你可以控制哪些通知被過濾。
ItemProvider也管理屬性描述(property descriptors)對于所有的featur of the class,通過getImage和getText方法來管理類的icon和descrition。
對于所有的ItemProvider都有一個ItemProviderAdaptorFactory。
最后時editor插件:
對于所有的模型都會再presentation package中生成三個類。
一個多頁編輯器,它給模型創建幾個不同的jface viewer,包含一個TreeViewer,使用edit插件中的ItemProvider作為這個treeviewer的content和label的provider。這個editor還創建outline和property來顯示在viewer中選中對象的屬性。
一個ActionBarContributor,它被用于對編輯器視圖中選中的item所創建的context menu添加選項。
最后是一個向導,允許你創建一個包含模型對象的一個實例的資源(resource)。
EMF中的三個部分:元數據meta-data,代碼生成code generation,默認序列化default serialization.
EMF is part of the Model Driver Architecture(MDA).MDA是將整個應用軟件生存周期的開發管理都集中于模型上。這種模型是用元模型(meta-model)定義的。然后,使用映射,模型被用于生成software artefacts, 這就實現了整個系統。
EMF所能做的:emf能夠用于描述和構建模型。所實現的模型可以被用于任何java應用程序的開發。
對于ecore模型我們有幾點需要注意:
1。在ecore文件的xmi描述中沒有各個元素之間的聯系,我們使用EReference來表示各個元素之間的聯系。
對于兩個方向上的聯系,通過兩個成對的EReference來表示,每個聯系的類,都有一個eOpposite來保存它自己在所聯系類中的名字(引用)。
對于單方向上的聯系,使用一個單獨的EReference,并且這個reference沒有eOpposite(因為對方并沒有對自己的引用)。
連接的多重性通過upperBound和lowerBound來表示。多個用-1。
2。使用EPackage可以像java中的package一樣用。
3。兩種模型,一種是業務模型,一種是視圖模型。一般將兩種模型放在不同的package中。兩種方法將兩種模型聯系起來:
一是構建一個新package,構建一個多重繼承的新package來將兩個package聯系起來。
二是將兩種模型分開存儲,添加從視圖模型到業務模型的引用。這種方法兩個模型是松耦合的。這種單方向的引用也不會破壞(污染)業務模型。注意,由于這種引用是兩個package之間的,所以在移用的eType類型中需要指明包名。
除此之外,ecore還提供了一種遞歸的定義方法。就是使用eSubPackage來分別包含業務模型和視圖模型,并且在這兩個subPackage間建立reference(對于package來說是自己引用自己)。
4。我們可以有多種方法來生成ecore模型。通過注釋的java接口(annotated java interface),通過rantional rose創建模型,通過XML Schema等等。