GEF七天之第二天

   上回,我们说明了GEF的实现原理,这次我们就从实际出发来说明他具体的实现.当然还是结合那个DEMO,同时我还会具体说一下,我对这个架构各部分的理解.由于是初学者,也许有理解的偏差,如有什么写错的请指正,并且欢迎交流。
    之前我还是要说,学习GEF,如果你没有学过Eclipse插件,那么最好先花时间熟悉一下Eclipse的插件体系结构,在这里我只介绍GEF的相关知识,swt以及eclipse plug-in的东西还需自己学习.(为此偶花了100大元买了IBM的eclipse 开发指南)
     从前面的介绍中我们知道,GEF采用MVC模式,所以我们就从模型开始.
      模型实现的功能主要有以下几个方面:(1)存储了所有用户可以编辑或浏览的数据,包括可视化相关的数据比如大小,坐标等
(2)提供可持久化模型的方法,当编辑器关闭时你的模型被持久化.打开后还应恢复.
(3)提供方法允许 别人监听他的变化,前面的介绍中我们知道,控制要知道模型的变化.并作出相应的相应.

根据以上三个方面我们在看DEMO的要求.三角,矩形,圆形均他们具有相同的特征,所以我们不妨将其抽象为ShapeModel类,由于模型的属性变化了,必须通知控制器,由它来刷新模型对应的视图,所以控制器必须注册为模型的侦听器。由于每个模型都有相应的控制器侦听器侦听它属性的变化,我们把这方面的功能都放在父类中,定义一个ElementModel父类(觉得这个挺好,网上的各种示例都这么干的)
    所以我们先来看看模型ElementModel父类的代码:
package hya.gef.demo.shapes.models;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;

/**
 * 基本的模型元素
 * <p>
 * 所有模型必须继承此类
 * </p>
 * <p>
 * 实现Serializable接口,持久化
 * </p>
 * 
 * 
@author hya
 
*/

public abstract class ElementModel implements Serializable {

    
// 表明类的不同版本间的兼容性,序列化
    private static final long serialVersionUID = 1;

    
/** 构造一个 PropertyChangeSupport 对象,绑定this类,非序列化 */
    
private transient PropertyChangeSupport pcsDelegate = new PropertyChangeSupport(
            
this);

    
/** 注册监听器 */
    
public synchronized void addPropertyChangeListener(PropertyChangeListener l) {
        
if (l == null{
            
throw new IllegalArgumentException();
        }

        pcsDelegate.addPropertyChangeListener(l);
    }


    
/** 发生改变通知监听器 */
    
protected void firePropertyChange(String property, Object oldValue,
            Object newValue) 
{
        
if (pcsDelegate.hasListeners(property)) {
            pcsDelegate.firePropertyChange(property, oldValue, newValue);
        }

    }


    
//序列化
    private void readObject(ObjectInputStream in) throws IOException,
            ClassNotFoundException 
{
        in.defaultReadObject();
        pcsDelegate 
= new PropertyChangeSupport(this);
    }


    
//撤销监听
    public synchronized void removePropertyChangeListener(
            PropertyChangeListener l) 
{
        
if (l != null{
            pcsDelegate.removePropertyChangeListener(l);
        }

    }


}


从中可以看到为了持久化,我们让其实现了java.io.Serializable接口以及readObject方法.同时我为了提供监听机制,我们引入了PropertyChangeSupport对象,同时添加addPropertyChangeListeneraddPropertyChangeListener两个方法来提供监听器的注册和移除.同时提供firePropertyChange(String property, Object oldValue,Object newValue) 方法来同志监听器模型属性发生了变化.
然后我们在来看我们的抽象图形类,取名为ShapeModel
/**
 * 图形的公共基类
 * <UL>
 * <LI>所有图形继承此类<LI>
 * <LI>抽象了图形的公共属性位置,大小,以及连线<LI>
 * </UL>
 * 
@author hya
 * 
*/

public abstract class ShapeModel extends ElementModel {
    
    
/**坐标改变的ID, 用于通知监听器图形坐标放生改变 */
    
public static final String LOCATION_PROP = "Model.Location";
    
private static final long serialVersionUID = 1;
    
/** 大小改变的ID,通知监听器图形大小放生改变 */
    
public static final String SIZE_PROP = "Model.Size";
    
    
/**以下连个为连接ID,用于通知监听器图形的连接发生改变  */
    
public static final String SOURCE_CONNECTIONS_PROP = "Model.SourceConn";
    
public static final String TARGET_CONNECTIONS_PROP = "Model.TargetConn";


    
/** 图形坐标 */
    
private Point location = new Point(00);
    
/** 图形大小 */
    
private Dimension size = new Dimension(5050);
    
/** 图形作为连接源点的列表 */
    
private List sourceConnections = new ArrayList();
    
/** 图形作为连接终点的列表*/
    
private List targetConnections = new ArrayList();

    
/**
     * 图形增加连接
     
*/

    
void addConnection(Connection conn) {
        
if (conn == null || conn.getSource() == conn.getTarget()) {
            
throw new IllegalArgumentException();
        }

        
if (conn.getSource() == this{
            sourceConnections.add(conn);
            firePropertyChange(SOURCE_CONNECTIONS_PROP, 
null, conn);
        }
 else if (conn.getTarget() == this{
            targetConnections.add(conn);
            firePropertyChange(TARGET_CONNECTIONS_PROP, 
null, conn);
        }

    }


    
/**
     * 根据路径得到图标
     * 相对于类Activator
     * 
*/

    
protected static Image createImage(String name) {
        InputStream stream 
= Activator.class.getResourceAsStream(name);
        Image image 
= new Image(null, stream);
        
try {
            stream.close();
        }
 catch (IOException ioe) {
        }

        
return image;
    }

    
/**
     *定义元素模型图标
     *子类应实现它
     
*/

    
public abstract Image getIcon();

    
/**
     * 得到图形坐标
     
*/

    
public Point getLocation() {
        
return location.getCopy();
    }




    
/**
     * 得到图形大小
     
*/

    
public Dimension getSize() {
        
return size.getCopy();
    }



    
public List getSourceConnections() {
        
return new ArrayList(sourceConnections);
    }


    
public List getTargetConnections() {
        
return new ArrayList(targetConnections);
    }


    
/**
     *移出连接
     
*/

    
public void removeConnection(Connection conn) {
        
if (conn == null{
            
throw new IllegalArgumentException();
        }

        
if (conn.getSource() == this{
            sourceConnections.remove(conn);
            firePropertyChange(SOURCE_CONNECTIONS_PROP, 
null, conn);
        }
 else if (conn.getTarget() == this{
            targetConnections.remove(conn);
            firePropertyChange(TARGET_CONNECTIONS_PROP, 
null, conn);
        }

    }


    
/**
     * 改变图形坐标
     
*/

    
public void setLocation(Point newLocation) {
        
if (newLocation == null{
            
throw new IllegalArgumentException();
        }

        location.setLocation(newLocation);
        firePropertyChange(LOCATION_PROP, 
null, location);
    }




    
/**
     *改变图形大小
     
*/

    
public void setSize(Dimension newSize) {
        
if (newSize != null{
            size.setSize(newSize);
            firePropertyChange(SIZE_PROP, 
null, size);
        }

    }

    }

由于图形之间要有连线,这个连线通常是有方向的所以我们提供了两个List来分别存储源连接和目标连接。源连接是指那些以当前图形作为源的连接,目标连接是指以当前图形作为目标的连接。同时的还有两个对象属性location,size 来表示图形的坐标和大小。同时提供了各自的方法来维护这些属性,我们应该注意到每次模型发生改变时都会调用firePropertyChange();来通知监视器模型有改变,他维护了三个参数第一个为属性表示,是我们自己定义的用来告诉监视器那个属性有变化
以及变化的值。(看到这里你是不是会想到什么,对就是观察者模式,属性监听机制就是用了观察者模式)。
三个图形的只是对它的扩展

    
/**
     *三角型
     * 
@author hya 
     * 
*/

    
public class TriangleModel extends ShapeModel {

        
private static final Image RECTANGLE_ICON = createImage("icons/triangle.gif");

        
private static final long serialVersionUID = 1;

        
public Image getIcon() {
            
return RECTANGLE_ICON;
        }


        
public String toString() {
            
return "Triangle " + hashCode();
        }

    }

它的两个方法提供了了在outline中要显示的图标和名称,以后我们会涉及到
是不是忘了什么,对就是连接线模型
/**
 *连接线模型
 * 
@author hya
 
*/

public class Connection extends ElementModel {



//表明类的不同版本间的兼容性,序列化
private static final long serialVersionUID = 1;

private boolean isConnected;
/**源点 */
private ShapeModel source;
/**目的节点*/
private ShapeModel target;


/**
 * 初始化类时建立一个连接
 
*/

public Connection(ShapeModel source, ShapeModel target) {
    reconnect(source, target);
}


/** 
 * 删除连接
 
*/

public void disconnect() {
    
if (isConnected) {
        source.removeConnection(
this);
        target.removeConnection(
this);
        isConnected 
= false;
    }

}




/**
 * 得到连接的源点
 
*/

public ShapeModel getSource() {
    
return source;
}


/**
 *得到连接的目的点
 
*/

public ShapeModel getTarget() {
    
return target;
}


/**重新建立连接*/  
public void reconnect() {
    
if (!isConnected) {
        source.addConnection(
this);
        target.addConnection(
this);
        isConnected 
= true;
    }

}


/**建立连接*/
public void reconnect(ShapeModel newSource, ShapeModel newTarget) {
    
if (newSource == null || newTarget == null || newSource == newTarget) {
        
throw new IllegalArgumentException();
    }

    disconnect();
    
this.source = newSource;
    
this.target = newTarget;
    reconnect();
}




}

原理和上面一样,在下一天中我们会来讨论GEF的核心控制器。
posted @ 2008-07-14 23:18    阅读(932)  评论(4编辑  收藏  举报