接触GEF 已经一年多了,最近有点空,刚好整理一下。
其他的不说了,我主要用到的就是GEF和Draw2D,其他的EMF、GMF都还没有用过(看是看过),这些就不多言了。
先看一个GEF 官方自带的示例——org.eclipse.gef.examples.shapes,这应该是一个最基本的demo示例,但也还有几十个类和文件,GEF的入门的确有点麻烦。
项目的基本结构:
下面开始对源码的分析:
1 org.eclipse.gef.examples.shapes —— 插件工程相关的文件,还有就是图形编辑器相关的类,以及一个新建向导扩展(针对新建.shapes文件)。
2 org.eclipse.gef.examples.shapes.icons ——工程用到的一些图片文件
3 org.eclipse.gef.examples.shapes.model —— GEF中的模型
4 org.eclipse.gef.examples.shapes.model.commands —— GEF中的命令(Command)
5 org.eclipse.gef.examples.shapes.parts —— GEF中的控制器(Controller)
GEF拥有明显的三层架构——MVC:
1 M:Model,模型,在上面的工程中对应org.eclipse.gef.examples.shapes.model 类包;
2 V:View,视图,它对应什么不好一概而论,在界面上看,它与图形编辑器(GrahpicalEditor)和相关的图形元素(Figure)相关;
3 C:Controller,控制器,就是M和V之间的桥梁,主要为一些EditPart,个人觉得GEF 的精妙之处就在于此。它完美的实现了模型和视图的分离,但是通过控制器,任何一方的改动都将传递给另一方,这就使得图形化的编辑和保存得以实现。
下面是一张GEF 的工作示意图,主要看看它的右边,模型和视图通过控制器连接起来。
接着看源码,首先了解一下模型的实现,也就是org.eclipse.gef.examples.shapes.model 类包下的文件。
所有模型都继承自ModelElement,看看ModelElement 的实现:
上面这几行截自ModelElement.java。可以发现它实现了IPropertySource 接口(另一个Serializable 接口是负责序列化的,此处暂不议)。
IPropertySource的主要作用为提供属性支持,我们知道在Eclipse中有属性视图(PropertySheet),实现了这个接口的类将拥有属性视图。赘述一下,IPropertyDescriptor 对应的就是属性视图里的一行,属性视图中的值的存取与getPropertyValue()和setPropertyValue()相关。在这里ModelElement自然也拥有了属性视图查看的功能,但是它更重要的是实现与控制器的交互——通过PropertyChangeSupport。它的方法见下图:
添加删除监听器和出发监听器都由它完成。
在ModelElement中最重要的三个方法为addPropertyChangeListener()、firePropertyChange()、removePropertyChangeListener(),它们为控制器连接模型和视图提供了功能接口。
接下来看看Connection.java。它为连接模型的封装类,理所当然与连接相关。在GEF中连接有几个元素:源端点、目的端点、线条、箭头。它继承自ModelElement,说明它是一个属性源。在Connection中需要注意的有以下几个方法:
1 reconnect()/disconnection():实现Connection的连接和断开
2 setLineStyle():设置Connection的线条样式,尤其注意它里面有行代码:
它将线条样式这个属性的变更通知给属性监听器,要求它做一些处理。至于什么处理,稍后再讲。
接下来看看Shape.java。这个类为形状的基类,稍微大一些。作为在图形编辑器中出现的图形元素,有几个必备的属性(当然也可以叫做特征):
1 位置:注意是org.eclipse.draw2d.geometry.Point类型,而不是SWT的Point;
2 大小:注意是org.eclipse.draw2d.geometry.Dimension类型;
3 源连接:当图形具有连接功能时,需要提供源连接,也就是以此图形为源端点的连接;
4 目的连接:当图形具有连接功能时,需要提供目的连接,也就是以此图形为目的端点的连接;
这个类的其他方法很简单,也就是对以上属性进行操作。在进行set或者change的同时,注意通知相关监听器属性的变更。
最后就是ShapeDiagram.java,这个类是所有图形元素的根(Root)图形。根据GEF的图形放置特点,所有的图形都放在RootFigure上。而一般的,这个根图形为一个Layer(在View中详述)。ShapeDiagram具有children,它与Shape在逻辑上构成父子关系,请注意这种关系,在很多情况下,父子关系在GEF的View和Contraoller中都有巨大的作用。