GEF的模型只与控制器打交道,而不知道任何与视图有关的东西。
1.模型的功能
在GEF框架中,模型(Model)是非常简单的一部分,用户可把模型理解成一个简单的可持久化的实体。但为了能让控制器知道模型的变化,应该把控制器作为事件监听者注册在模型中,当模型发生变化时,就触发相应的事件给控制器,后者负责通知各个视图进行更新。
2.模型的实现
典型的模型对象会包含PropertyChangeSupport类型的成员变量,用来触发事件,通知监听器即控制器。一般来说,模型会实现一个基类,用来封装事件机制,主要包括添加监听器、删除监听器,以及模型属性改变触发的相应事件,代码如下:
java 代码
1.package com.example.model;
2.
3.import java.beans.PropertyChangeListener;
4.import java.beans.PropertyChangeSupport;
5.import java.io.Serializable;
6.
7.public abstract class Element implements Cloneable, Serializable {
8.
9. PropertyChangeSupport listeners = new PropertyChangeSupport(this);
10. //添加监听器
11. public void addPropertyChangeListener(PropertyChangeListener l) {
12. listeners.addPropertyChangeListener(l);
13. }
14. //触发属性改变的事件
15. protected void firePropertyChange(String prop, Object old, Object newValue) {
16. listeners.firePropertyChange(prop, old, newValue);
17. }
18. //触发结构改变的事件
19. protected void fireStructureChange(String prop, Object child) {
20. listeners.firePropertyChange(prop, null, child);
21. }
22.
23.// private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
24.// in.defaultReadObject();
25.// listeners = new PropertyChangeSupport(this);
26.// }
27. //删除监听器
28. public void removePropertyChangeListener(PropertyChangeListener l) {
29. listeners.removePropertyChangeListener(l);
30. }
31.
32.}
另外,当用户希望通过属性视图编辑模型属性时,模型要实现IPropertySource接口,该接口的方法解释如下:
package org.eclipse.ui.views.properties;
public interface IPropertySource {
public Object getEditableValue();//得到在属性页中能编辑的值,可以返回this表示当前模型
public IPropertyDescriptor[] getPropertyDescriptors();//得到IPropertyDescriptor类型的数组,其中每一项为属性页中能编辑的项
public Object getPropertyValue(Object id);//通过id值得到某个属性,在添加每一项IPropertyDescriptor时都会指定id值
public boolean isPropertySet(Object id);//表示特定属性id值是否改变
public void resetPropertyValue(Object id);//通过id重置属性
public void setPropertyValue(Object id, Object value);//通过id和值设置某一项属性的值
}
如果模型和其它模型有关系(在视图上为连线),模型要维护这些关系,并适当的持久化,当模型的属性修改后,模型要触发相应的事件通知监听器。
java 代码
1.package com.example.model;
2.
3.import java.util.ArrayList;
4.import java.util.List;
5.
6.import org.eclipse.draw2d.geometry.Point;
7.import org.eclipse.ui.views.properties.ComboBoxPropertyDescriptor;
8.import org.eclipse.ui.views.properties.IPropertyDescriptor;
9.import org.eclipse.ui.views.properties.IPropertySource;
10.import org.eclipse.ui.views.properties.TextPropertyDescriptor;
11.
12.public class Node extends Element implements IPropertySource {
13. //定义属性的常量ID
14. final public static String PROP_LOCATION = "LOCATION";
15.
16. final public static String PROP_NAME = "NAME";
17.
18. final public static String PROP_VISIBLE = "VISIBLE";
19.
20. final public static String PROP_INPUTS = "INPUTS";
21.
22. final public static String PROP_OUTPUTS = "OUTPUTS";
23.
24. protected Point location = new Point(0, 0);
25.
26. protected String name = "Node";
27.
28. protected boolean visible = true;
29. //定义属性的编辑项
30. protected IPropertyDescriptor[] descriptors = new IPropertyDescriptor[] {
31. new TextPropertyDescriptor(PROP_NAME, "Name"),
32. new ComboBoxPropertyDescriptor(PROP_VISIBLE, "Visible", new String[] { "true", "false" }) };
33. //定义模型连线的列表
34. protected List outputs = new ArrayList(5);
35.
36. protected List inputs = new ArrayList(5);
37.
38. public void addInput(Connection connection) {
39. this.inputs.add(connection);
40. //当输入的连线改变后,触发结构改变的事件
41. fireStructureChange(PROP_INPUTS, connection);
42. }
43.
44. public void addOutput(Connection connection) {
45. this.outputs.add(connection);
46. //当输出的连线改变后,触发结构改变的事件
47. fireStructureChange(PROP_OUTPUTS, connection);
48. }
49.
50. public List getIncomingConnections() {
51. return this.inputs;
52. }
53.
54. public List getOutgoingConnections() {
55. return this.outputs;
56. }
57.
58. public void removeInput(Connection connection) {
59. this.inputs.remove(connection);
60. fireStructureChange(PROP_INPUTS, connection);
61. }
62.
63. public void removeOutput(Connection connection) {
64. this.outputs.remove(connection);
65. fireStructureChange(PROP_OUTPUTS, connection);
66. }
67.
68. public boolean isVisible() {
69. return visible;
70. }
71.
72. public void setVisible(boolean visible) {
73. if (this.visible == visible) {
74. return;
75. }
76. this.visible = visible;
77. firePropertyChange(PROP_VISIBLE, null, Boolean.valueOf(visible));
78. }
79.
80. public String getName() {
81. return name;
82. }
83.
84. public void setName(String name) {
85. if (this.name.equals(name)) {
86. return;
87. }
88. this.name = name;
89. //当模型的名字改变后,通知监听器更新名字的显示
90. firePropertyChange(PROP_NAME, null, name);
91. }
92.
93. public void setLocation(Point p) {
94. if (this.location.equals(p)) {
95. return;
96. }
97. this.location = p;
98. //当模型的位置改变后,通知监听器更新模型的位置
99. firePropertyChange(PROP_LOCATION, null, p);
100. }
101.
102. public Point getLocation() {
103. return location;
104. }
105.
106. //------------------------------------------------------------------------
107. // Abstract methods from IPropertySource
108.
109. public Object getEditableValue() {
110. return this;
111. }
112. //得到属性编辑项
113. public IPropertyDescriptor[] getPropertyDescriptors() {
114. return descriptors;
115. }
116. //得到属性编辑项的值
117. public Object getPropertyValue(Object id) {
118. if (PROP_NAME.equals(id))
119. return getName();
120. if (PROP_VISIBLE.equals(id))
121. return isVisible() ? new Integer(0) : new Integer(1);
122. return null;
123. }
124.
125. public boolean isPropertySet(Object id) {
126. return true;
127. }
128.
129. public void resetPropertyValue(Object id) {
130.
131. }
132. //设置属性的值
133. public void setPropertyValue(Object id, Object value) {
134. if (PROP_NAME.equals(id))
135. setName((String) value);
136. if (PROP_VISIBLE.equals(id))
137. setVisible(((Integer) value).intValue() == 0);
138. }
139.}
上例中实现了模型对应的属性视图,当属性被修改后,模型将会调用“fire...”方法触发相应的模型改变事件。
你可以参考着代码来看接下来的内容了,让我们从模型开始说起。模型是根据应用需求来设计的,所以我们的模型包括代表整个图的Diagram、代表节 点的Node和代表连接的Connection这些对象。我们知道,模型是要负责把自己的改变通知给EditPart的,为了把这个功能分离出来,我们使 用名为Element的抽象类专门来实现通知机制,然后让其他模型类继承它。Element类里包括一个PropertyChangeSupport类型 的成员变量,并提供了addPropertyChangeListener()、removePropertyChangeListener()和 fireXXX()方法分别用来注册监听器和通知监听器模型改变事件。在GEF里,模型的监听器就是EditPart,在EditPart的active ()方法里我们会把它作为监听器注册到模型中。所以,总共有四个类组成了我们的模型部分。