日期:2014-05-20 浏览次数:21140 次
在GMP:了解GMF引擎功能(Graphical Modeling Framework) 中的架构组件中介绍了GMF依赖于GEF,本篇介绍一下GEF。GEF( Graphical Editing Framework ) 建立标准的 MVC 构架,代码利用 Draw2D 作为自己的 View 部分,主要代码实现复杂的树状 ( 于 Model 分别对应 ) 的控制器。实现的框架具有很高的可复用等特性,例如:将图形部件功能分解为多个 EditPolicy ,这样使用者可以通过 installEditPolicy 接口来定制,以及扩充自己的某一功能特征。
Draw2D 通过被称为LightweightSystem (以下简称LWS )的部件与SWT中的某一个Canvas实例相连,这个Canvas 在 Draw2D应用程序里一般是应用程序的Shell,在GEF应用程序里更多是某个Editor的 Control(createPartControl()方法中的参数),在界面上我们虽然看不到LWS的存在,但其他所有能看到的图形都是放在它里面 的,这些图形按父子包含关系形成一个树状的层次结构。LWS是Draw2D的核心部件,它包含三个主要组成部分:RootFigure 是LWS中所有图形的根,也就是说其他图形都是直接或间接放在RootFigure里的;EventDispatcher 把Canvas上的各种事件分派给RootFigure,这些事件最终会被分派给适当的图形,请注意这个RootFigure和你应用程序中最顶层的IFigure 不是同一个对象,前者是看不见的被LWS内部使用的,而后者通常会是一个可见的画布,它是直接放在前者中的;UpdateManager 用来重绘图形,当Canvas被要求重绘时,LWS会调用它的performUpdate()方法。
GEF的controller负责更新视图,并把UI事件转换为命令来操作底层的模型。
? 初步了解了GEF的MVC实现方式,让我们看看典型的GEF应用程序是什么样子的。大部分GEF应用程序都实现为Eclipse的Editor,也就是 说整个编辑区域是放置在一个Editor里的。所以典型的GEF应用程序具有一个图形编辑区域包含在一个Editor(例如 GraphicalEditorWithPalette)里,可能有一个大纲视图和一个属性页,一个用于创建EditPart实例的 EditPartFactory,一些表示业务的模型对象,与模型对象对应的一些EditPart,每个EditPart对应一个IFigure的子类对 象显示给用户,一些EditPolicy对象,以及一些Command对象。 GEF应用程序的工作方式如下: EditPartViewer接受用户的操作,例如节点的选择、新增或删除等等,每个节点都对应一个EditPart对象,这个对象有一组按操作Role 分开的EditPolicy,每个EditPolicy会对应一些Command对象,Command最终对模型进行直接修改。用户的操作转换为 Request分配给适当的EditPolicy,由后者创建适当的Command来修改模型,这些Command会保留在EditDomain (专门用于维护EditPartViewer、Command等信息的对象,一般每个Editor对应唯一一个该对象)的命令堆栈里,用于实现撤消/重做功能。
- 模型
GEF的模型只与控制器打交道,而不知道任何与视图有关的东西。为了能让控制器知道模型的变化,应该把控制器作为事件监听者注册在模型中,当模型发生变化时,就触发相应的事件给控制器,后者负责通知各个视图进行更新。
典 型的模型对象会包含PropertyChangeSupport类型的成员变量,用来维护监听器成员即控制器;对于与其他对象具有连接关系的模型,要维护 连入/连出的连接列表;如果模型对应的节点具有大小和位置信息,还要维护它们。这些变量并不是模型本身必须的信息,维护它们使模型变得不够清晰,但你可以 通过构造一些抽象模型类(例如让所有具有连接的模型对象继承Node 类)来维持它们的可读性。
- 控制器
我们知道,在MVC结构里控制器是模型与视图之间的桥梁,也是整个GEF的核心。它不仅要 监听模型的变化,当用户编辑视图时,还要把编辑结果反映到模型上。举个例子来说,用户在数据库结构图上删除一个表时,控制器应该从模型中删除这个表对象、 表中的字段对象、以及与这些对象有关的所有连接。GEF中的控制器是所谓的EditPart 对象,更确切的说应该是一组EditPart对象共同组成了GEF的控制器这部分,每一个模型对象都对应一个EditPart对象。你的应用程序中需要有一个EditPartFactory 对象负责根据给定模型对象创建对应的EditPart对象,这个工厂类将被视图利用。
RootEditPart 是一种特殊的EditPart,它和你的模型没有任何关系,它的作用是把EditPartViewer 和contents(应用程序的最上层EditPart,一般代表一块画布)联系起来,可以把它想成是contents的容器。Editpart的生命周期由EditPartViewer 负责。EditPartViewer有一个方法setRootEditPart()专门用来指定视图对应的RooEditPart。
用户的编辑操作被转换为一系列请求(Request),有很多种类的请求,这些种类在GEF里被称为角色(Role) ,GEF里有图形化和非图形化这两大类角色,前者比如Layout Role对应和布局有关的的操作,后者比如Connection Role对应和连接有关的操作等等。角色这个概念是通过编辑策略(EditPolicy )来实现的,EditPolicy的主要功能是根据请求创建相应的命令(Command),而后者会直接操作模型对象。
EditParts包含一套EditPolicy 类。 EditPolicy 提供行为来操作大部分实际的模型编辑。对每一个EditPart,你都可以"安装"一些EditPolicy,用户对这个EditPart的特定操作会被交给已安装的对应EditPolicy处理。这样做的直接好处是可以在不同EditPart之间共享一些重复操作。
在GEF SDK提供的帮助文档(GEF开发指南)里有一份详细的EditPolicy、Role和Request类型列表。
- 视图
前面说过,GEF的视图可以有很多种,GEF目前提供了图形(GraphicalViewer) 和树状(TreeViewer) 这两种,前者利用Draw2D图形(IFigure)作为表现方式,多用于编辑区域,后者则多用于实现大纲展示。视图的任务同样繁重,除了模型的显示功能以外,还要提供编辑功能、回显(Feedback)、工具提示(ToolTip)等等
GEF使用EditPartViewer作为视图 , 它的作用和JFace中的Viewer十分类似,而EditPart就相当于是它的ContentProvider和LabelProvider,通过 setContents()方法来指定。我们经常使用的Editor是一个GraphicalEditorWithPalette(GEF提供的 Editor,是EditorPart的子类,具有图形化编辑区域和一个工具条),这个Editor使用GraphicalEditViewer和 PaletteViewer这两个视图类,PaletteViewer也是GraphicalEditViewer的子类。开发人员要在 configureGraphicalViewer()和initializeGraphicalViewer()这两个方法里对 EditPartViewer进行定制,包括指定它的contents和EditPartFactory等等。
EditPartViewer 同时也是ISelectionProvider,这样当用户在编辑区域做选择操作时,注册的SelectionChangeListener就可以收到选 择事件。EditPartViewer会维护各个EditPart的选中状态,如果没有被选中的EditPart,则缺省选中的是作为contents的 EditPart。
?
?
推荐:你可能需要的在线电子书
?