《gef理解系列三》由会员分享,可在线阅读,更多相关《gef理解系列三(7页珍藏版)》请在金锄头文库上搜索。
1、GEF 理解系列三关键字: gef 理解系列 经过以上步骤,我们已经有办法显示多个图形了。还是重提一下:Editor 的初始状态由 initializeGraphicalViewer()方法决定。不过在我们已经完成的过程,我们会发现,初始状态,也是最终状态,我们甚至不能移动任何一个图,当然了也不能增加和删除。下面我们要逐一的实现这些功能。在继续之前,我们先了解一下 GEF 执行操作的过程,看下图:图一 从上图可以看到。GEF 把 SWT 事件包装成一个个的 request 发送到Controller(EditPart)上,通过 Controller(EditPart)来操作、修改模型和视图。但
2、是 Controller(EditPart)并不直接进行操作。而是由安装在Controller(EditPart)上的一个个 Policy 来完成的。每个Controller(EditPart)上会安若干个 Policies。当然了 Policy 其实也不直接完成操作,而只是返回一个对应的 Command,由 Command 去实现真正的操作。 图二 在 GEF 中,实现任何操作,都是同样的路子:安装对应的 Policy返回某个Command执行(由框架调) 我们应该还记得在之前的篇段里,我们一直没讲到 EditPart 的一个方法:createEditPolicies()。下面,就要开始用到
3、这个方法了。 一、图形的移动与缩放首先需要明白的一点就是:对子图形的改变大小、变换位置的操作都是由父模型来负责完成的,因为子图形是附着在父图形上来显示。如果要实现对子模型的改变大小、变换位置的操作,我们需要在父模型的 editpart 上安装一个policy。可能初学的一个难点就是要找到一个直接对应的 Policy。在 EditPolicy 里已经定义了一些 Policy 的 Key 常量。每个常量对应的 Policy 的名字通常和常量的名字相同。例如:常量名 类名 CONNECTION_ROLE ConnectionEditPolicy GRAPHICAL_NODE_ROLE Graphic
4、alNodeEditPolicy COMPONENT_ROLE ComponentEditPolicy CONTAINER_ROLE ContainerEditPolicy DIRECT_EDIT_ROLE DirectEditPolicy 。 。表一所以如果我们选择了某个常量,就能知道应该选择哪个对应的 EditPolicy;另外Policy 名字有时也就决定了它的作用,所以要找到一个正确的 Policy 也不是太难。我个人觉得如果真的不知道应该选择哪个 Policy,那就把觉得可能的一个一个的试,因为每个 EditPolicy 继承时都会有一些要求实现的方法,例如GraphicalNode
5、EditPolicy 需要实现的方法有: protected Command getConnectionCompleteCommand(CreateConnectionRequest request) ; protected Command getConnectionCreateCommand(CreateConnectionRequest request) ; protected Command getReconnectSourceCommand(ReconnectRequest request) ; protected Command getReconnectTargetCommand(R
6、econnectRequest request) ;很显然,如果是要实现创建连接和重连的话,应该安装这个 Policy,所以对应的安装就应该是: installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new *GraphicalNodeEditPolicy(); 好了,废话少说。继续我们的事情。 要实现图形的移动和缩放,需要安装的 Policy 是 LayoutEditPolicy,所以我们需要实现一个 LayoutEditPolicy 的子类,不过这里,我们要注意的是,我们应该继承的类为:XYLayoutEditPolicy。这是 LayoutE
7、ditPolicy 的一个子类。在实现之前,我们先想一下,要实现移动或者是缩放,我们需要哪些东西。很显示,我们要有一个需要将要移动或缩放的结点对象吧,对吧?另外,我们得知道移动或缩放后的位置大小吧,对吧?所以我们的 command 如果想完成这个任务,那么它至少需要知道这两个东西。所以我们的 Policy 可以如下实现了:public class DiagramLayoutPolicy extends XYLayoutEditPolicy Overrideprotected Command createChangeConstraintCommand(EditPart child,Object
8、constraint) ResizeHelloWorldCommand command = new ResizeHelloWorldCommand(HelloWorldModel) child.getModel(), (Rectangle) constraint);return command; Overrideprotected Command getCreateCommand(CreateRequest request) return null; 然后完成 createChangeConstraintCommand(EditPart child, Object constraint) 方法
9、,返回一个 Command 即可。如上我们已经返回了一个 Command。下面我们就要实现这个 Command。实现 Command 本身是很简单的。就是把模型设置为当前的大小。如下: public class ResizeHelloWorldCommand extends Command private HelloWorldModel model;private Rectangle constraints;private Rectangle old;public ResizeHelloWorldCommand(HelloWorldModel model, Rectangle constrai
10、nts) super();this.model = model;this.constraints = constraints;Overridepublic void execute() old = model.getConstraints();model.setConstraints(constraints);Overridepublic void undo() constraints = model.getConstraints(); model.setConstraints(old); 这里我们加了一个对象:old。这是为了实现重做与撤消用的。 现在我们试一下效果: 图三 图形已经可以缩放
11、和拖动了。但是当我们把鼠标松开时,模型又回到了原处,变回了原来的大小了;打印一下可以知道:在模型中,图形的位置确实变了。这是怎么回事呢? 二、增加通知机制 如上,模型是发生了变化。但是图形并不知道模型的变化。所以图形不发生改变。要让图形发生变化。我们就需要有一个通知机制了。 一般来说,对模型有改变,都需要通过一种机制去通知视图进行刷新。在 GEF中,通常这是通过属性改变监听机制来完成的。例如,当模型的 constraint 改变时,我们可以加一个监听。这里的一个标准模式是: 1模型做为事件源,由模型添加事件和发出事件 2模型对应的 EditPart 作为事件处理者(因为模型不知道视图的存在)
12、通常我们可以用一个抽象类来专门处理属性改变,让所以模型继承这个类,例如: public abstract class AbstractModel private PropertyChangeSupport support = new PropertyChangeSupport(this); public void firePropertyChange(String propertyName, Object oldValue, Object newValue) support.firePropertyChange(propertyName, oldValue, newValue); public
13、 void addPropertyChangeListener(PropertyChangeListener listener) support.addPropertyChangeListener(listener); public void removePropertyChangeListener(PropertyChangeListener listener) support.removePropertyChangeListener(listener); 添加监听和删除监听的地方在对应的 editpart 里,此时 editpart 本身要实现监听接口 PropertyChangeList
14、ener,然后让模型的监听对象设为模型对应的 EditPart。在 EditPart 里重写 active()和 deactive()方法,分别加上监听和移除监听;然后实现 propertyChange 方法,例如: Override public void activate() super.activate(); (HelloWorldModel)getModel().addPropertyChangeListener(this); Override public void deactivate() (HelloWorldModel)getModel().removePropertyChan
15、geListener(this); super.deactivate(); public void propertyChange(PropertyChangeEvent evt) if(evt.getPropertyName().equals(HelloWorldModel.P_CONSTRAINT) refreshVisuals(); 这里的 active()方法是当 EditPart 激活时调用,deactive()方法当 EditPart 钝化时调用。上面说的有点乱,实际上那就是一个固定的样子,理解后就很好写了。 好,为了实现更改大小和位置,我们首先要修改我们的模型,我们按照上面的样子写
16、一个 AbstractModel,然后让所有的模型继承这个类。 现在,我们有了一套通过机制了。下一步就是在我们所有修改了模型属性的方法里,利用这套机制,生成事件,例如 HelloWorldModel 更改大小事件: public static final String P_CONSTRAINT = p_constraint;public void setConstraints(Rectangle constraints) Rectangle old = getConstraints();this.constraints = constraints;firePropertyChange(P_CONSTRAINT, old, constraints); 修改 HelloWorldEditPart: 1.首先让它实现接口:PropertyChan