一、创建Editor
图一:Editor类层次图
从图上被选中的那一层起就是GEF中的Editor类层级关系。GraphicalEditor是根类。我们的Editor可以直接实现这个类;如果想带有调色板(palette),则至少需要继承GraphicalEditorWithPalette;如果还想调色板(palette)可收缩,则可继承GraphicalEditorWithFlyoutPalette。在下面的过程中,我们就假设我们实现的都是带调色板(palette)的Editor。
二、添加EditDomain
图二
在步骤一中,我们已经有了一个可运行的Editor了。但是如果此时打开这个Editor,会得到一个异常。可以看到异常是发生在getCommandStack方法里的。如果查看GEF的源码就可以发现,这个空指针异常是由getEditDomain()返回的是一个空而造成的。
在每个GEF的Editor里,都需要有一个EditDomain的存在。EditDomain是一个很重要的对象,它维护着GEF中的命令栈(所谓的命令栈就是一个用来存放命令的堆栈。GEF中的所有操作都是通过命令来完成的,这个命令栈就存储所有的这些操作命令。这也能方便的实现redo、undo操作)、负责事件通知等等。所以我们要给我们的Editor设置一个这样的EditDomain。
一般说来我们直接在构造方法里使用一个DefaultEditDomain对象即可,例如:setEditDomain(new DefaultEditDomain(this));当然有可能你也需要实现自己的EditDomain,这超出了本文的讲解范围。
现在我们就有了一个可打开的Editor了,只是现在还没有内容而已。
三、MVC三部曲
我们已经有了一个可运行的Editor了,暂时我们先不管这个Editor,我们来看另外一部分:GEF的MVC结构。
GEF全称“图形编辑框架”。简单来说就是一个用来编辑图形的框架,也是一个典型的MVC结构框架。因此要实现一个GEF的应用,主要就是要实现MVC框架中的:模型、视图和控制。
首先:模型
实现模型很简单,通常这部分是根据自己的应用需求来实现的。当然了你也可以用Eclipse里的EMF框架生成的一个应用模型。这里我们定义一个简单的应用模型:HelloWorld,它有一个text属性,有两个方法用来设置和取得这个text属性的值。如下:
图3
其次:控制器
GEF中的控件器都需要实现某个EditPart类。一般来说普通的模型结点需要实现AbstractGraphicalEditPart;连接线需要实现AbstractConnectionEditPart等等。我们可以看一下类图:
图四
看我们的HelloWorld(红色圈住的)就继承了AbstractGraphicalEditPart类。需要实现至少两个方法:createFigure()(对应的显示部分)和createEditPolicies()(对应的操作部分)。这里暂时先不讲。
最后:视图
GEF中的视图部分是由控制器(Editpart)负责创建的。看上面控制器部分,最后我们说到的需要实现的两个方法中,其中:createFigure()方法就是用来创建视图的。GEF的视图部分是由Draw2D负责完成的。可以到网上去找一些Draw2D的简单教程看看。例如我们的实现:
@Override
protected IFigure createFigure() {
Label label = new Label();
label.setBorder(new LineBorder(ColorConstants.red));
HelloWorldModel helloworld = (HelloWorldModel) getModel();
label.setText(helloworld.getText());
label.setOpaque(true);
label.setBackgroundColor(ColorConstants.yellow);
return label;
}
三者之间的关系
应该来说MVC结构中,模型不应该知道任何有关图形的信息,也不应该包含图形的任何信息,模型和视图之间是通过控制器来打交道的。不过在GEF中,有时为了记住视图的一些状态,我们却不得不在模型中保存一些图形相关的信息,例如:图形大小、图形位置等等。这样当我们下次打开图形时,还可以保持它最后关闭时的状态。这点可能不是太好。在GMF中,这种状态终于有所改变了。GMF中每种模型都有一个view去专门处理图形的信息,而且保存的时候也可以把模型信息与图形信息进行分开保存。
说上面的话,其实我只是想说下面的内容:在HelloWorld中添加一个属性用于保存图形的大小。所以现在我们的HelloWorld模型就变成了:
import org.eclipse.draw2d.geometry.Rectangle;
public class HelloWorldModel{
private String text = "<unname>";
private Rectangle constraints = new Rectangle(0,0,100,20);
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public Rectangle getConstraints() {
return constraints;
}
public void setConstraints(Rectangle constraints) {
this.constraints = constraints;
}
}
将三者联结
最后就是将三者联结起来,这里用到了EditPartFactory类,例如:
public class DiagramEditPartFactory implements EditPartFactory {
public EditPart createEditPart(EditPart context, Object model) {
if(model instanceof HelloWorldModel){
HelloWorldEditPart editPart = new HelloWorldEditPart();
editPart.setModel(model);
return editPart;
}
return null;
}
}
这样我们就完成了一个模型对象的MVC结构。 假如可以运行的话,我们看到此时运行的效果应该是:
呵呵,现在什么都还没有。
如果我们还要再创建一个模型,就基本上是做重复运动了。这个在GEF是比较烦的一件事。所以在后面的才会出现GMF。只要给出一个能生成模型的东西,比如说XML schema、java annotaion、UML图等,它就自动帮你生成了一个Editor。那几乎是不要几分钟的事情。不过现在我们还得继续我们的事件。。。。