GEF七天之第三天

    在这说一下,其实GEF七天,并不是把我每天知识的总结,而是学习了GEF七天,我想通过这样一种方式将我这七天的收获和对GEF框架的理解,写出来,也算是对这一周的总结吧
   其实这一章我们介绍gef的核心控制器了,在写之前,我们先介绍一下GEF要用到的设计模式.
   在学GEF中给我感受最深的是,设计模式无处不在,除了上章中说的观察者模式外.GEF框架还运用了COMMAND(命令)模式,Policy(策略)模式.这两个模式,策略模式,貌似本团对有人介绍过了,而command模式是我现研究的(也许会单独写个随笔,谈谈心得).
  好了,我们言归正传.先说一下,GEF控制器的实现原理.
控制器是由一组EditPart对象共同组成的,每一个模型对象都对应一个EditPart对象。应用程序中需要有一个EditPartFactory对象负责根据给定模型对象创建对应的EditPart对象,这个工厂类将在创建模型时被调用。
控制器是GEF中最复杂的一部分,GEF把控制器完成的工作又分成了几个部分,包括请求和编辑策略及引申出来的命令模式,如下图:

用户的编辑操作被转换为一系列请求(Request),Eclipse中有很多种类的请求,这些种类在GEF里被成为角色(Role)。在GEF里有图形 化和非图形化这两大类角色,前者如“LayoutRole”对应和布局有关的操作,后者如“ConnectionRole”对应和连接有关的操作等。角色 这个概念是通过编辑策略(EditPolicy)来实现的,EditPolicy的主要功能是根据请求创建相应的命令(Command),而后者会直接操 作模型对象。
对每一个EditPart,用户都可以“安装”一些EditPolicy。用户对这个EditPart的特定操作会被交给已安装的对应EditPolicy处理。这样做的直接好处是可以在不同EditPart之间共享一些重复操作。
   这样说有点抽象,还是用代码说话,接着上回那个DEMO来所,该是editpart部分了.

   对于模型的每个独立部分,我们都必须定义控制器。所谓“独立”,指的是这个实体 都可以作为用户操作的对象。一个比较好的原则就是任何可以被选择,或删除的对象 都应该有它自己的编辑部件(来自于IBM)。

        所有的部件均实现了createFigure()(返回模型在视图中的图形表示), createEditPolicies()(安装相应的策略),refreshVisuals() (刷新视图), propertyChange()(接受模型改变并执行不同的操作,刷新视图) ,activate() 己加入设为监听器 和  deactivate()将自己从监听器的列表中移除)五个方法。

 所以由上回的模型,我们就可以建立控制器了,首先我们将他也抽象化:
现建基类SpecificPart

package hya.gef.demo.shapes.parts;

import hya.gef.demo.shapes.models.ElementModel;

import java.beans.PropertyChangeListener;

import org.eclipse.gef.editparts.AbstractGraphicalEditPart;


/**
 * editpart基类
 * 主要为注册自己为模型改变的监听者
 * 
@author hya
 * 
*/

public abstract class SpecificPart extends AbstractGraphicalEditPart 
implements PropertyChangeListener {
    
    
/**
     * 将自己注册为模型的属性修改事件的接收者
     
*/

    
public void activate() {
        
if (!isActive()) {
            
super.activate();
            ((ElementModel) getModel()).addPropertyChangeListener(
this);
        }

    }

    
    
/**
     * 将自己从监听器的列表中移除
     
*/

    
public void deactivate(){
        
super.deactivate();
        ((ElementModel)getModel()).removePropertyChangeListener(
this);
    }

    

}

然后是shape模型对应的part类
  
public class ShapeEditPart extends SpecificPart implements NodeEditPart {

    
//连接锚点
    private ConnectionAnchor anchor;
    
    
/**
     *@Override 
     * 建立视图
     * 
*/

    
protected IFigure createFigure() {
        IFigure f 
= createFigureByGetModel();
        f.setOpaque(
true); // non-transparent figure
        f.setBackgroundColor(ColorConstants.red);
        
return f;
    }


    
/**根据得到的模型实例,画出不同的图形*/
    
private IFigure createFigureByGetModel() {
        
if (getModel() instanceof RadioModel) {
            
return new Ellipse();//圆形
        }
 else if (getModel() instanceof RectangularModel) {
            
return new RectangleFigure();//矩形
        }
 else if (getModel() instanceof TriangleModel) {
            
return new Triangle();//三角形
        }
 else {
            
            
throw new IllegalArgumentException();
        }

    }


     
/**安置策略*/
    
protected void createEditPolicies() {
        
//安装删除策略
        installEditPolicy(EditPolicy.COMPONENT_ROLE, new ShapeComponentEditPolicy());
        
//安装建立,更改连接策略
        installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new ShapeConnectionEditPolicy());
   }

    
    
/**
     *     @Override
     * 刷新视图
     * 
*/

    
protected void refreshVisuals() {
        Rectangle bounds 
= new Rectangle(((ShapeModel) getModel()).getLocation(),
                ((ShapeModel) getModel()).getSize());
        ((GraphicalEditPart) getParent()).setLayoutConstraint(
this, getFigure(), bounds);
    }


    
/**
     *接受修改事件,刷新视图 
     * 
*/

    
public void propertyChange(PropertyChangeEvent arg0) {
        String p 
= arg0.getPropertyName();
        
if (ShapeModel.SIZE_PROP.equals(p) || ShapeModel.LOCATION_PROP.equals(p)) {
            refreshVisuals();
        }
else if (ShapeModel.SOURCE_CONNECTIONS_PROP.equals(p)) {
            refreshSourceConnections();
        }
 else if (ShapeModel.TARGET_CONNECTIONS_PROP.equals(p)) {
            refreshTargetConnections();
        }
 

    }

    
    
//------------------------------------------------------------------------ 
    
//---
    
//连接设置
    
    
//得到相应图形的锚点
    protected ConnectionAnchor getConnectionAnchor() {
        
if (anchor == null{
            
if (getModel() instanceof RadioModel)
                anchor 
= new EllipseAnchor(getFigure());
            
else if (getModel() instanceof RectangularModel)
                anchor 
= new ChopboxAnchor(getFigure());
            
else if(getModel()instanceof TriangleModel)
                anchor 
= new ChopboxAnchor(getFigure());    
            
else
                
throw new IllegalArgumentException("unexpected");
        }

        
return anchor;
    }


    
//得到以模型作为源的连接列表 
    protected List getModelSourceConnections() {
        
return  ((ShapeModel) getModel()).getSourceConnections();
    }


    
//得到以模型作为目标的连接列表
    protected List getModelTargetConnections() {
        
return ((ShapeModel) getModel()).getTargetConnections();
    }


    
//当需要画连接的时候,获取连接的源锚点
    public ConnectionAnchor getSourceConnectionAnchor(ConnectionEditPart connection) {
        
return getConnectionAnchor();
    }

    
    
//准备创建连接的时候,通过Request来获取新连接的源锚点
    public ConnectionAnchor getSourceConnectionAnchor(Request request) {
        
return getConnectionAnchor();
    }

    
   
//获取连接的目标锚点
    public ConnectionAnchor getTargetConnectionAnchor(ConnectionEditPart connection) {
        
return getConnectionAnchor();
    }


     
public ConnectionAnchor getTargetConnectionAnchor(Request request) {
        
return getConnectionAnchor();
    }


    
}


   由于图形之间是可以连接的所以我们还同时让其实NodeEditPart接口。通过实现这个接口,编辑部件可以定义源锚点和目标锚点,锚点就是图形和连接接触的连接点 。重写了getModelSourceConnections方法和getModelTargetConnections方法。这两个方法的任务就是要通知GEF有关该图形的源连接和目标连接

       createFigure()方法,根据返回的对象不同,返回 不同的图形实例(矩形,三角形和圆形)。主要通过方法createFigureByGetModel()来判断。

       createEditPolicies()安装了两个策略,ShapeComponentEditPolicy提供命 令将一个 图形从图删除。第二个策略处理图形间连接的创建和转移,它的索引字是 GRAPHICAL_NODE_ROLE。

  其他的两个模型对应的part也差不多
DiagamEditPart

package hya.gef.demo.shapes.parts;

import hya.gef.demo.shapes.models.DiagramModel;
import hya.gef.demo.shapes.parts.policy.ShapesXYEditPolicy;

import java.beans.PropertyChangeEvent;
import java.util.List;

import org.eclipse.draw2d.ConnectionLayer;
import org.eclipse.draw2d.Figure;
import org.eclipse.draw2d.FreeformLayer;
import org.eclipse.draw2d.FreeformLayout;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.MarginBorder;
import org.eclipse.draw2d.ShortestPathConnectionRouter;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.LayerConstants;
import org.eclipse.gef.editpolicies.RootComponentEditPolicy;


public class DiagamEditPart extends SpecificPart {

    
/**
     *@Override 
     * 建立视图
     * 建立容器,设置布局管理器
     * 
*/

    
protected IFigure createFigure() {
        Figure f 
= new FreeformLayer();
        f.setBorder(
new MarginBorder(3));
        
//FreeformLayout布局管理器,这是一种XY型的布局管理器
        f.setLayoutManager(new FreeformLayout());

        
// Create the static router for the connection layer
    ConnectionLayer connLayer = (ConnectionLayer)getLayer(LayerConstants.CONNECTION_LAYER);
        connLayer.setConnectionRouter(
new ShortestPathConnectionRouter(f));
    
        
return f;
    }


    
    
/**
     * 得到子对象列表
     * 
*/

    
protected List getModelChildren() {
        
return ((DiagramModel) getModel()).getChildren(); // return a list of shapes
    }



    
protected void createEditPolicies() {
        
//阻止模型的根被删除,它重写了createDeleteCommand方法,并返回一个不能被执行的命令
        installEditPolicy(EditPolicy.COMPONENT_ROLE, new RootComponentEditPolicy());
        
//安装添加和更改元素策略
        installEditPolicy(EditPolicy.LAYOUT_ROLE,  new ShapesXYEditPolicy());

    }


    
/**模型改变时,刷新视图*/
    
public void propertyChange(PropertyChangeEvent arg0) {
        String p 
= arg0.getPropertyName();
        
if (DiagramModel.CHILD_ADDED_PROP.equals(p)
                
|| DiagramModel.CHILD_REMOVED_PROP.equals(p)) {
            refreshChildren();
        }


    }


}

ConnectionEditPart

package hya.gef.demo.shapes.parts;

import hya.gef.demo.shapes.commands.ConnectionDeleteCommand;
import hya.gef.demo.shapes.models.Connection;


import org.eclipse.draw2d.BendpointConnectionRouter;
import org.eclipse.draw2d.IFigure;
import org.eclipse.draw2d.PolygonDecoration;
import org.eclipse.draw2d.PolylineConnection;
import org.eclipse.gef.EditPolicy;
import org.eclipse.gef.commands.Command;
import org.eclipse.gef.editparts.AbstractConnectionEditPart;
import org.eclipse.gef.editpolicies.ConnectionEditPolicy;
import org.eclipse.gef.editpolicies.ConnectionEndpointEditPolicy;
import org.eclipse.gef.requests.GroupRequest;

class ConnectionEditPart extends AbstractConnectionEditPart  {



protected void createEditPolicies() {
    
//安装与连接有关的策略
    installEditPolicy(EditPolicy.CONNECTION_ENDPOINTS_ROLE,
            
new ConnectionEndpointEditPolicy());
    
    installEditPolicy(EditPolicy.CONNECTION_ROLE, 
new ConnectionEditPolicy() {
        
protected Command getDeleteCommand(GroupRequest request) {
            
return new ConnectionDeleteCommand(getCastedModel());
        }

    }
);
}



protected IFigure createFigure() {
    PolylineConnection conn 
= new PolylineConnection();
    conn.setTargetDecoration(
new PolygonDecoration());
    conn.setConnectionRouter(
new BendpointConnectionRouter());
    
return conn;
}




private Connection getCastedModel() {
    
return (Connection) getModel();
}



}

   连接编辑部件,它继承自AbstractConnectionEditPart类。createFigure()方法返回了一个带箭头的连接线。

      他安装了两个策略第一个是ConnectionComponentPolicy,它提供删除命令给Delete菜单项 所需要的action。第二个策略提供了一种视觉上的选择反馈,即当一个连接被拖动时,GEF 没有办法获取连接两端的标识.
      那么GEF是怎么知道模型与PART之间的对应关系的呢,所以应该建立模型与part之间的映射,这个我们用到了工厂模式
建立part工厂:ShapesEditPartFactory


package hya.gef.demo.shapes.parts;

import hya.gef.demo.shapes.models.Connection;
import hya.gef.demo.shapes.models.DiagramModel;
import hya.gef.demo.shapes.models.ShapeModel;

import org.eclipse.gef.EditPart;
import org.eclipse.gef.EditPartFactory;



/**
 * 控制器工厂
 * 
@author hya
 * 
*/

public class ShapesEditPartFactory implements EditPartFactory {


public EditPart createEditPart(EditPart context, Object modelElement) {
    EditPart part 
= getPartForElement(modelElement);
part.setModel(modelElement);
    
return part;
}


/**建立模型与EditPart的映射*/
private EditPart getPartForElement(Object modelElement) {
    
if (modelElement instanceof DiagramModel) {
        
return new DiagamEditPart();
    }

    
if (modelElement instanceof ShapeModel) {
        
return new ShapeEditPart();
    }

if (modelElement instanceof Connection) {
        
return new ConnectionEditPart();
    }

    
throw new RuntimeException(
            
"Can't create part for model element: "
            
+ ((modelElement != null? modelElement.getClass().getName() : "null"));
}


}

    这是,核心的part就建立完了.我们可以看到他们当中的方几乎一样,狭义回我们将加入策略和命令部分,并更加详细的通过代码来说明GEF的工作过程.

posted @ 2008-07-17 00:23    阅读(1382)  评论(5编辑  收藏  举报