您的位置:首页 > 其它

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

2010-04-27 12:50 363 查看
使用

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
的查看器。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: