#
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等等。