GEF原理及实现系列(二、模型)

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 ()方法里我们会把它作为监听器注册到模型中。所以,总共有四个类组成了我们的模型部分。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值