最后轮到GEF中最重要的Controller——控制器了。它们是model和view之间的桥梁。我们先从直观上来分析这种连接作用。
1 Connection <-->ConnectionEditPart <-->PolylineConnection
2 EllipticalShape <-->ShapeEditPart <-->Ellipse
3 RectangularShape <-->ShapeEditPart <-->RectangleFigure
4 ShapeDiagram <-->DiagramEditPart <-->FreeformLayer
再看一个图:
先分析一下ShapeEditPart类。
class ShapeEditPart extends AbstractGraphicalEditPart
implements PropertyChangeListener, NodeEditPart
它继承自AbstractGrahpicalEditPart,同时实现了PropertyChangeListener和NodeEditPart。
AbstractGrahpicalEditPart 是一个非常重要的类,是GEF中控制器的核心。既然它是模型和视图的桥梁。那么猜想一下它一定知道模型是什么、视图在哪里。看一下它的成员变量:
1 figure:IFigure 视图表现,在createFigure()中初始化;
2 model:Object 模型,由EditPartFactory传递给EditPart;
3 parent:EditPart 父亲EditPart,EditPart的父子关系由model决定;
4 children:List 子EditPart
5 sourceConnections:List 源连接模型对应的EditPart
6 targetConnections:List 目的连接模型对应的EditPart
7 policies:Object[] 策略,稍后再议。
这里就很明了,在EditPartFactory中,根据模型来产生EditPart,然后在EditPart中的createFigure()创建图形,再通过一系列的方法刷新显示(refreshVisuals()、refreshChildren()等)。
先看看EditPartFactory的实现——ShapesEditPartFactory.java:
核心就是getPartForElement()方法了,也就是根据模型创建EditPart(控制器)了。
它实现了PropertyChangeListener,这个接口只有一个方法,propertyChange()。上面我们在讲Connection.java的时候,说
有行代码:
它将线条样式这个属性的变更通知给属性监听器,要求它做一些处理。这里ShapeEditPart就是一个属性监听器,它接收到传递过来的属性变更信息,然后做出一些处理,见:
至此ShapeEditPart将模型与视图关联到了一起,模型的改动将带来视图的改动,这个过程是自动的。
在ShapeEditPart的初始化过程中,有几个方法比较重要:
1 activate():EditPart被激活的操作,包括激活所有子EditParta以及给对应的模型添加属性监听器;
同时请注意在deactivate()中进行的remove操作。
2 createEditPolicies():安装编辑策略,这与图形编辑器是否提供可视化的操作相关,比如拖拽、创建、删除;
3 createFigure():创建视图图形元素。
<!-- /* Font Definitions */ @font-face {font-family:Wingdings; panose-1:5 0 0 0 0 0 0 0 0 0; mso-font-charset:2; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:0 268435456 0 0 -2147483648 0;} @font-face {font-family:宋体; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:SimSun; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"Cambria Math"; panose-1:2 4 5 3 5 4 6 3 2 4; mso-font-charset:1; mso-generic-font-family:roman; mso-font-format:other; mso-font-pitch:variable; mso-font-signature:0 0 0 0 0 0;} @font-face {font-family:Calibri; panose-1:2 15 5 2 2 2 4 3 2 4; mso-font-charset:0; mso-generic-font-family:swiss; mso-font-pitch:variable; mso-font-signature:-1610611985 1073750139 0 0 159 0;} @font-face {font-family:"/@宋体"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-unhide:no; mso-style-qformat:yes; mso-style-parent:""; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-font-kerning:1.0pt;} p.MsoListParagraph, li.MsoListParagraph, div.MsoListParagraph {mso-style-priority:34; mso-style-unhide:no; mso-style-qformat:yes; margin:0cm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; text-indent:21.0pt; mso-char-indent-count:2.0; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:11.0pt; font-family:"Calibri","sans-serif"; mso-ascii-font-family:Calibri; mso-ascii-theme-font:minor-latin; mso-fareast-font-family:宋体; mso-fareast-theme-font:minor-fareast; mso-hansi-font-family:Calibri; mso-hansi-theme-font:minor-latin; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi; mso-font-kerning:1.0pt;} .MsoChpDefault {mso-style-type:export-only; mso-default-props:yes; mso-bidi-font-family:"Times New Roman"; mso-bidi-theme-font:minor-bidi;} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:612.0pt 792.0pt; margin:72.0pt 90.0pt 72.0pt 90.0pt; mso-header-margin:36.0pt; mso-footer-margin:36.0pt; mso-paper-source:0;} div.Section1 {page:Section1;} /* List Definitions */ @list l0 {mso-list-id:1664896968; mso-list-type:hybrid; mso-list-template-ids:1525981020 67698713 67698691 67698693 67698689 67698691 67698693 67698689 67698691 67698693;} @list l0:level1 {mso-level-number-format:alpha-lower; mso-level-text:"%1/)"; mso-level-tab-stop:none; mso-level-number-position:left; margin-left:42.0pt; text-indent:-21.0pt;} ol {margin-bottom:0cm;} ul {margin-bottom:0cm;} -->
还有一些其他比较重要的方法,如下:
a) getModelSourceConnections() :与连接有关,返回对应模型的源连接;
b) getModelTargetConnections() :与连接有关,返回对应模型的目的连接;
c) getSourceConnectionAnchor(ConnectionEditPart connection) :获取源连接的锚点,也就是连接与图形的焦点位置,详细见后面 ConnectionEditPart 的讲解;
d) getSourceConnectionAnchor(Request request) :获取源连接的锚点,这个锚点与 Request 相关,详细见后面 Policy 的讲解部分;
e) getTargetConnectionAnchor(ConnectionEditPart connection) :获取目的连接的锚点,也就是连接与图形的焦点位置,详细见后面 ConnectionEditPart 的讲解;
f) getTargetConnectionAnchor(Request request) : 获取目的连接的锚点,这个锚点与 Request 相关,详细见后面 Policy 的讲解部分;
在org.eclipse.gef.examples.shapes.parts下还有一部分是AbstractTreeEditPart的继承类,这些类用于在Outline 视图中显示大纲的。它们同样由EditPartFactory控制: