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

使用 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, 

new ShapesXYLayoutEditPolicy());

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 的查看器。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值