GEF七天之第三天

2023-11-22 11:40
文章标签 第三天 gef 七天

本文主要是介绍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的工作过程.

转载于:https://www.cnblogs.com/hya1109/archive/2008/07/17/1244770.html

这篇关于GEF七天之第三天的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/409881

相关文章

Java基础回顾系列-第三天-Lambda表达式

Java基础回顾系列-第三天-Lambda表达式 Lambda表达式方法引用引用静态方法引用实例化对象的方法引用特定类型的方法引用构造方法 内建函数式接口Function基础接口DoubleToIntFunction 类型转换接口Consumer消费型函数式接口Supplier供给型函数式接口Predicate断言型函数式接口 Stream API 该篇博文需重点了解:内建函数式

【JAVA】第三天

【JAVA】第三天 一、面向对象1.static2.代码块 二、继承三、权限修饰符四、方法重写五、多态1.自动类型转换2.强制类型转换 六、final七、抽象类八、接口九、内部类十、枚举十一、泛类1.泛型类2.泛型接口3.泛型方法 一、面向对象 1.static 类变量:属于类,与类一起加载一次,在内存中只有一份,会被类的所有对象共享实例变量:属于对象,每个对象中都有一份

[HZNUCTF 2023 preliminary]easyAPK-快坚持不下去的第三天

第一做安卓题,前提jadx,java环境,模拟器,我配了好久, 这段代码实现了一个简单的登录界面,用户需要输入用户名和密码。用户名和密码会与预设的硬编码值进行比较,登录成功后会启动另一个 Activity。如果密码错误或用户名不匹配,会显示错误提示。注册按钮点击后会显示不支持注册的消息。

第十四节:学习Springboot 的restful接口风格(自学Spring boot 3.x的第三天)

这节记录下自己学习restful的记录。 增(PostMapping) /*** 保存学生* @return*/@PostMappingpublic Student save(@RequestBody Student student){studentService.save(student);return student;} 注意:传参使用RequestBody 删(DeleteM

Vue笔记总结(Xmind格式):第三天

Xmind鸟瞰图: 简单文字总结: vue知识总结 响应更新:     1.v-for高效更新:         ①当v-for遍历的目标结构改变, Vue触发v-for的更新         ②数组非变更方法, 返回新数组, 就不会导致v-for更新, 可采用覆盖数组或this.$set()     2.v-for就地更新:v-for 的默认行为会尝试原地修改元素而不是移动它们

ES6笔记总结(Xmind格式):第三天

Xmind鸟瞰图: 简单文字总结: ES6知识总结: Promise的使用:     1.使用 new Promise() 构造函数来创建一个 promise 对象     2.接受两个函数作为参数:resolve 和 reject         ①resolve 函数在异步操作成功完成时调用,并将 promise 的状态从 "pending" 变为 "fulfilled",同时将操作的

React 入门第三天:深入理解Hooks的强大功能

在React学习的第三天,我将重点放在Hooks上。Hooks是React 16.8引入的一项革命性特性,使得我们能够在函数组件中使用状态和其他React特性。通过学习和实践Hooks,我进一步体会到了React的灵活性和强大之处。以下是我第三天的学习心得。 1. Hooks简介 Hooks是函数,它们允许你在函数组件中“钩入”React的特性,比如状态管理和生命周期方法。对于从类组件转向函数

linux学习--第三天

-linux特殊字符         通配符            1.  *  :匹配任意长度的字符串            2.  ?:匹配一个长度的字符串            3.  ··· :匹配指定的字符串            4.   -  :匹配指定的字符范围            5.  ^··· :匹配除该字符串外所有字符串         输出(输入)重定向

【备战蓝桥杯青少组】第三天 放苹果

题 OpenJudge - 666:放苹果 描述 把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?(用K表示)5,1,1和1,5,1 是同一种分法。 输入 第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整数M和N,以空格分开。1<=M,N<=10。 输出 对输入的每组数据M和N,用一行输出相应的K。 样例输入 17 3 样例输出