GEF 学习系列之四:使用GEF构建应用程序的步骤

来源:互联网 发布:三角函数计算器软件 编辑:程序博客网 时间:2024/05/22 03:10

使用GEF构建应用程序

     使用GEF构建应用程序虽然比较复杂,但确是一个思路非常清晰的过程,它可以帮助我们更好的理解MVC的工作原理:

1.        构建自己的模型

GEF给予了模型构建极大的灵活性,因为在EditPart中对模型的引用都是Object类型的,这也符合GEF的设计原则,可以让我们任意的构建模型,在构建模型时需要注意如下几个方面:

1)       如果模型是序列化保存,需要实现Serializable接口;

2)       模型必须是一个事件源,因为一旦模型更改的话需要通知视图进行刷新,可以将模型的更改定义为Javabean中的属性事件,在模型中保持一个PropertyChangeSupport 的引用,这样就可以实现这种事件通知机制(当然也可以采用其他的方式);

3)       如果需要在Eclipse Properties中显示图元的属性的话,需要实现接口IpropertySource,如果在属性视图中对属性值进行了修改的话,也需要触发相应的事件;

4)       需要在模型中定义图元的显示坐标,也可以将模型划分为业务模型和视图模型,这样程序结构更加清晰;

5)       如果模型之间是有关系的(在视图上表现为图元之间是可连接的),需要在模型中表明这种关系,具体方式为:定义一个出口连接列表和一个进口连接列表;如果连接的关系发生改变的话,需要触发某个事件;

通知策略:

对视图进行更新几乎总是由来自模型的通知而导致的。您的模型必须提供某种通知机制,该机制必须映射到您应用程序中相应的更新。而只读模型或不能进行通知的模型(例如文件系统或远程连接)可能是例外。

通知策略通常是分布式的(每对象)或集中式的(每域)。域通知器了解到对模型中任何对象的每次更改,然后将这些更改向域侦听器广播。如果您的应用程序使用了这种通知模型,您可能要为每个查看器添加一个域侦听器。当该侦听器接收到更改时,它将查找受影响的 EditPart,然后适当地重新分派该更改。如果您的应用程序使用了分布式通知,那么每个 EditPart 通常都将把自己的侦听器添加到任何一个影响它的模型对象。

 

2.        定义自己的视图

下一步是决定将如何使用来自 Draw2D 插件的图形显示您的模型。某些图形可直接用来显示模型的某个对象。例如,Label图形可用来显示 Image String。有时候,通过组合多个图形、布局管理器和/或边框可以获得期望的结果。最后,您可能要编写自己的图形实现,该实现以特定于您应用程序的方式绘图。

在和 GEF 一起使用 Draw2D 时,通过遵循下列方针,可以使您的项目更便于管理,并且可以更灵活地更改需求:

1)       不要从头做起。您可以组合所提供的布局管理器以呈现大多数东西。请考虑使用工具栏布局(在垂直或水平方向上)和边框布局的组合来组合多个图形。只有在万不得已时才编写自己的布局管理器。作为参考,请查看 GEF 中提供的调色板。该调色板是使用 Draw2D 中的许多标准图形和布局呈现的。

2)       保持 EditPart 和图形之间“彻底”的分离。如果您的 EditPart 使用了几个图形、布局和/或边框的复合结构,那么请尽量对 EditPart隐藏详细信息。让EditPart 自己构建所有东西是可能的(但不是个好主意)。不过这样做并不会导致控制器和视图之间“彻底”分离。EditPart 非常熟悉图形结构,因此以类似的 EditPart 重用该结构是不可能的。此外,更改外观或结构可能会导致意想不到的错误。

3)       不要从图形引用模型或 EditPart图形不应该具有对 EditPart 或模型的访问权。在某些情形中,EditPart 可能会将自己作为侦听器添加到图形,但是只会认为它是侦听器,而不是EditPart。这种去耦合(de-coupling)实践也可以产生更多的重用机会。

4)       使用内容窗格。有时候您拥有一个容器,该容器将包含其它图形元素,但是您需要在容器四周进行一些装饰。例如,一个 UML 类通常显示为框,其顶部标有类名,可能还有一些原型,而底部是为属性和方法保留的。通过组合多个图形可以做到这一点。第一个图形是类的标题框,而另一个图形被指派为内容窗格。该图形将最终包含表示属性和方法的图形。稍后在编写EditPart 实现时,并不一定要表明应该将内容窗格用作所有子元素的父元素。

3.  定义自己的控制器

接下来进行的工作就是将模型和视图连接起来,这是整个GEF中比较关键的一步,EditPart负责了模型和视图的交互,我们只需要继承相应的类即可。

提供的用于生成子类的基本实现有三种。对于出现在树查看器中的 EditPart 使用 AbstractTreeEditPart 。图形查看器中的继承 AbstractGraphicalEditPart AbstractConnectionEditPart 。本文将着重讨论图形 EditPart。相同的原理同样适用于树查看器。

1)     EditPart的生命周期;

每个查看器都有一个用于创建EditPart的工厂类(需要自己实现,从EditPartFactory继承而来),该工厂类需要在配置时与查看器关联,当您设置查看器的内容时,通过提供表示该查看器输入的模型对象,可以做到这一点。输入通常是最顶部的模型对象,通过该对象可遍历其它所有对象。然后查看器可以使用自己的工厂来构造用于该输入对象的 内容EditPart。之后,查看器中的每个EditPart 将填充和管理其自己的子EditPart(和连接EditPart),当需要新的EditPart 时,将委派给EditPart 工厂,直到填充该查看器。当用户添加新的模型对象时,包含这些对象的EditPart 将通过构造相应的EditPart 做出响应。请注意,视图的构造与EditPart 的构造是同时进行的。因此,构造每个EditPart 并将它添加到它的父EditPart 之后,视图(不管是图形还是树项)也会发生同样的过程。

一旦用户除去与某些EditPart 对应的模型对象,就丢弃这些EditPart。如果用户撤销了一个删除操作,那么用于表示被恢复对象而重新创建的EditPart 与原先的EditPart 是不同的。这就是为什么EditPart 不能包含长期信息,以及为什么不应由命令引用的原因。

2)      查看器的内容

我们需要编写的第一个EditPart对应于图本身的EditPart(即画布),这个EditPart称为查看器的内容,他对应于模型中最顶部的元素,并且其父元素为查看器的根EditPart。根通过提供各种图形层(例如连接层和句柄层等)以及可能会在查看器级别提供的视图缩放或其它功能,为内容打下基础。请注意,根的功能不依赖于任何模型对象,GEF为根提供了几个现成的实现。

 

内容的图形不是很有趣,并且它通常只是一个空面板,该面板将包含图的子图。它的图形应该为不透明类型(opaque),并且应当利用布局管理器进行初始化,该布局管理器将对图的子图进行布局。但是,它将拥有结构。图的直系子图是由返回的子模型对象列表确定的。

3)      覆盖方法createEditPolicies()。此方法的作用是为EditPart安装相应的编辑策略,只有安装了相应的编辑策略后,才能将Request转化为相应的Command,所以要想在内容视图上添加图元的话,需要为其控制器添加如下编辑器策略:

installEditPolicy(EditPolicy.LAYOUT_ROLE, 

newShapesXYLayoutEditPolicy());

4)      添加和移除监听器;前面说过,EditPart需要监听模型的改变,具体实现方式如下:

activate()中监听:

((ModelElement)getModel()).addPropertyChangeListener(this);

deactivate()中移除监听:

((ModelElement)getModel())

.removePropertyChangeListener(this);

5)      覆盖方法refreshVisuals();

当需要用到模型的数据更新视图时,应调用此方法。方法refreshVisuals()仅在EditPart初始化的过程中调用了一次,并且绝不会被再次调用。在相应模型通知时,应用程序应该根据需要再次调用refreshVisuals()以更新图形。

6)      使EditPart支持连接;

    编写连接EditPart 实现没有太大的区别。首先生成AbstractConnectionEditPart 的子类。跟前面一样,可以实现 refreshVisuals() ,以将属性从模型映射到图形。连接可能还拥有约束,尽管这些约束与前面的约束略有不同。这里,连接路由器使用约束来使连接转向(bend)。此外,连接EditPart 的图形必须是Draw2D Connection ,它引入了另一个需求:连接锚(connection anchor)。

 

连接必须由ConnectionAnchor “锚定”在两端。因此,必须在连接EditPart 中或在节点实现中表明使用哪些锚。缺省情况下,GEF假定节点EditPart 将通过实现NodeEditPart 接口而提供锚。这样假定的一个原因是,锚的选择取决于各端上的节点正在使用的图形。连接EditPart 不应了解节点正在使用的图形的任何内容。另一个原因是,当用户创建连接时,连接EditPart 是不存在的,因此节点必须能够自己显示反馈。

此时需要注意的一点是,节点的控制器必须要实现接口NodeEditPart,然后在相应的方法中返回锚点对象即可。

4.  将所有对象组合到一起

    对于最后的组装,我们将使用IEditorPart 。但是,也可以在视图、对话框或者可以放置控件的几乎任何地方使用GEF 的查看器。