GEF理解系列一

这两天又重新看了一下GEF。现在理解起来感觉比以前要容易的多了。这里就把一些心得整理一下,写了一个系列,以期与大家共同探讨。

一、创建Editor

      一般来说GEF都是用来实现一个Editor的。因此这里我也以Editor为例来说明。首先要做的一点就是实现一个Editor的扩展。具体怎么实现这里就不讨论,不明白的可以去找一个关于Eclipse插件开发方面的文章看看就知道了。
      可以有两种运行方式:一个种是插件方式;一种是RCP方式。具体到Editor本身来说,在这两种实现方式上运行的效果都是一样的。因此在后面的过程中,我们就忽略具体的运行方式,根据自己的喜好选择。
      要实现为一个GEF的Editor,我们扩展的Editor就需要继承自GEF的某个Editor实现。我们可以看一下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。那几乎是不要几分钟的事情。不过现在我们还得继续我们的事件。。。。

你可能感兴趣的:(eclipse,mvc,框架,UML)