a) 模型的生成
模型的生成一般情况下由手工完成,但在有些时候也采用EMF来构造模型。
b) 模型的功能
用户可把模型理解成一个简单的可持久化的实体。但为了能让控制器知道模型的变化,应该把控制器作为事件监听者注册在模型中,当模型发生变化时,就触发相应的事件给控制器,后者负责通知各个视图进行更新。
c) 模型的实现
i. 典型模型
典型的模型对象会包含PropertyChangeSupport类型的成员变量,用来触发事件,通知监听器即控制器。一般来说,模型会实现一个基类,用来封装事件机制,主要包括添加监听器、删除监听器,以及模型属性改变触发的相应事件,代码如下:
java代码:
package com.example.model;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
public abstract class Element implements Cloneable, Serializable {
PropertyChangeSupport listeners = new PropertyChangeSupport(this);
//添加监听器
public void addPropertyChangeListener(PropertyChangeListener l) {
listeners.addPropertyChangeListener(l);
}
//触发属性改变的事件
protected void firePropertyChange(String prop, Object old, Object newValue) {
listeners.firePropertyChange(prop, old, newValue);
}
//触发结构改变的事件
protected void fireStructureChange(String prop, Object child) {
listeners.firePropertyChange(prop, null, child);
}
//删除监听器
public void removePropertyChangeListener(PropertyChangeListener l) {
listeners.removePropertyChangeListener(l);
}
}
ii. 当用户希望通过属性视图编辑模型属性时,模型要实现IPropertySource接口,该接口的方法解释如下:
rel="File-List" href="file:///C:%5CDOCUME%7E1%5CADMINI%7E1%5CLOCALS%7E1%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">
//得到在属性页中能编辑的值,可以返回this表示当前模型
public Object getEditableValue();
//得到IPropertyDescriptor类型的数组,其中每一项为属性页中能编辑的项
public IPropertyDescriptor[] getPropertyDescriptors();
//通过id值得到某个属性,在添加每一项IPropertyDescriptor时都会指定id值
public Object getPropertyValue(Object id);
public boolean isPropertySet(Object id);//表示特定属性id值是否改变
public void resetPropertyValue(Object id);//通过id重置属性
//通过id和值设置某一项属性的值
public void setPropertyValue(Object id, Object value);
iii. 代码示例:
如果模型和其它模型有关系(在视图上为连线),模型要维护这些关系,并适当的持久化,当模型的属性修改后,模型要触发相应的事件通知监听器。
1. package com.example.model;
2.
3. import java.util.ArrayList;
4. import java.util.List;
5. import org.eclipse.draw2d.geometry.Point;
6. import org.eclipse.ui.views.properties.ComboBoxPropertyDescriptor;
7. import org.eclipse.ui.views.properties.IPropertyDescriptor;
8. import org.eclipse.ui.views.properties.IPropertySource;
9. import org.eclipse.ui.views.properties.TextPropertyDescriptor;
10.
11. public class Node extends Element implements IPropertySource {
12. //定义属性的常量ID
13. final public static String PROP_LOCATION = "LOCATION";
14.
15. final public static String PROP_NAME = "NAME";
16.
17. final public static String PROP_VISIBLE = "VISIBLE";
18.
19. final public static String PROP_INPUTS = "INPUTS";
20.
21. final public static String PROP_OUTPUTS = "OUTPUTS";
22.
23. protected Point location = new Point(0, 0);
24.
25. protected String name = "Node";
26.
27. protected boolean visible = true;
28. //定义属性的编辑项
29. protected IPropertyDescriptor[] descriptors = new IPropertyDescriptor[] {
30. new TextPropertyDescriptor(PROP_NAME, "Name"),
31. new ComboBoxPropertyDescriptor(PROP_VISIBLE, "Visible", new String[] { "true", "false" }) };
32. //定义模型连线的列表
33. protected List outputs = new ArrayList(5);
34.
35. protected List inputs = new ArrayList(5);
36.
37. public void addInput(Connection connection) {
38. this.inputs.add(connection);
39. //当输入的连线改变后,触发结构改变的事件
40. fireStructureChange(PROP_INPUTS, connection);
41. }
42.
43. public void addOutput(Connection connection) {
44. this.outputs.add(connection);
45. //当输出的连线改变后,触发结构改变的事件
46. fireStructureChange(PROP_OUTPUTS, connection);
47. }
48.
49. public List getIncomingConnections() {
50. return this.inputs;
51. }
52.
53. public List getOutgoingConnections() {
54. return this.outputs;
55. }
56.
57. public void removeInput(Connection connection) {
58. this.inputs.remove(connection);
59. fireStructureChange(PROP_INPUTS, connection);
60. }
61.
62. public void removeOutput(Connection connection) {
63. this.outputs.remove(connection);
64. fireStructureChange(PROP_OUTPUTS, connection);
65. }
66.
67. public boolean isVisible() {
68. return visible;
69. }
70.
71. public void setVisible(boolean visible) {
72. if (this.visible == visible) {
73. return;
74. }
75. this.visible = visible;
76. firePropertyChange(PROP_VISIBLE, null, Boolean.valueOf(visible));
77. }
78.
79. public String getName() {
80. return name;
81. }
82.
83. public void setName(String name) {
84. if (this.name.equals(name)) {
85. return;
86. }
87. this.name = name;
88. //当模型的名字改变后,通知监听器更新名字的显示
89. firePropertyChange(PROP_NAME, null, name);
90. }
91.
92. public void setLocation(Point p) {
93. if (this.location.equals(p)) {
94. return;
95. }
96. this.location = p;
97. //当模型的位置改变后,通知监听器更新模型的位置
98. firePropertyChange(PROP_LOCATION, null, p);
99. }
100.
101. public Point getLocation() {
102. return location;
103. }
104.
105. //------------------------------------------------------------------------
106. // Abstract methods from IPropertySource
107.
108. public Object getEditableValue() {
109. return this;
110. }
111. //得到属性编辑项
112. public IPropertyDescriptor[] getPropertyDescriptors() {
113. return descriptors;
114. }
115. //得到属性编辑项的值
116. public Object getPropertyValue(Object id) {
117. if (PROP_NAME.equals(id))
118. return getName();
119. if (PROP_VISIBLE.equals(id))
120. return isVisible() ? new Integer(0) : new Integer(1);
121. return null;
122. }
123.
124. public boolean isPropertySet(Object id) {
125. return true;
126. }
127.
128. public void resetPropertyValue(Object id) {
129.
130. }
131. //设置属性的值
132. public void setPropertyValue(Object id, Object value) {
133. if (PROP_NAME.equals(id))
134. setName((String) value);
135. if (PROP_VISIBLE.equals(id))
136. setVisible(((Integer) value).intValue() == 0);
137. }
138. }