`

GEF简介与事件机制

阅读更多
一、GEF简介
GEF(Graphical Editing Framework)是一个图形化编辑框架,它允许开发人员以图形化的方式展示和编辑模型,从而提升用户体验。
GEF的优势是提供了标准的MVC(Model-View-Control)结构,开发人员可以利用GEF来完成以上这些功能,而不需要自己重新设计。与其他一些MVC编辑框架相比,GEF的一个主要设计目标是尽量减少模型和视图之间的依赖,好处是可以根据需要选择任意模型和视图的组合,而不必受开发框架的局限(实际上视图基本是Draw2D的实现)。

二、GEF各项目的关系图:


图2.1


1、 Draw2D:建立了二维的图形库(树状图形部件Figure),负责显示二维的图形展示。

2、GEF:(Graphical Editing Framework)建立MVC构架,代码利用Draw2D作为自己的View部分,主要代码实现复杂的树状(于Model分别对应)的控制器。实现的框架具有很高的可复用等特性,例如:将图形部件功能分解为多个EditPolicy,这样使用者可以通过installEditPolicy接口来定制,以及扩充自己的某一功能特征。

3、EMF:(Eclipse Modeling Framework)首先在一个轻量级项目以及项目初期开发,Model常常采用拥有Property的Java对象来简单明了表示【即 Plain Old Java Objects (POJOs)】。EMF定义了一套Ecore元模型,使得Model具有易于维护、易于扩充、易于数据交换等特性的Model Framwork。因此、在实际中大型的项目中往往会采用Draw2D+GEF+EMF的方式来实现整体的MVC模式。例如:ROSE的最新版本 IBM.Rational.Software.Architect就是采用了这种构架。

4、GMF:(Graphical Modeling Framework )使用了GEF和EMF,建立了两个之间的桥梁框架,同时实现了一些领域上的典范应用,如UML图,甘特图,脑图等。(项目正在进行中这些功能还未完备。可以用来参考以实现自己的一个标准的GEF+EMF的应用)。

5、各项目依赖关系:

 
图2.2


如上图:使用者可以有以下几种用法:
EMF: Model管理层
Draw2D: 二维图形展现
Draw2D + GEF: 二维图形的简单编辑模块
Draw2D + GEF + EMF: 二维图形的编辑模块
Draw2D + GEF + EMF + GMF:基于GMF提供的图形编辑功能之上扩展

三、Draw2D技术
1、Draw2D是什么?
轻量级框架:轻量级框架,使用LightweightSystem类把SWT和Draw2D 连接起来,它把鼠标事件和画图事件从SWT 转发给Draw2D的图形上。它是Draw2D的核心类。
Draw2d中的Graphics和GC的对比:
Graphics类的很多方法和GC的完全一样,尤其是绘制线和几何图形、显示图片以及字体等方面。但Graphics还提供了一个不同于GC的功能:它的对象可以在LightweightSystem中移动。这意味着当你想要改变一个图形组件的位置时,Draw2d提供了它自己的拖拽机制来将一个Figure移动到合适的位置。
2、 LightweightSystem 主要包含三个组成部件:
LightweightSystem不依赖于特定操作系统,这意味着你失去了SWT/Jface重量级组件的优势,比如快速的响应和本地外观风格,但你得到的,是对自己的组件的外观与行为的完全控制。
1).根图形【IFigure】: 根图形是RootFigure类的实例,应用程序的根图形必须建立在它之上。它继承了一些SWT Canvas的图形环境,如颜色,字体等。
2).事件转发器【EventDispatcher】: 事件转发器把SWT事件转换成相应Draw2D事件。它可以跟踪那个图形被聚焦,那个图形是被鼠标点击的目标图形。它还控制tooltip的激活。它为想捕捉鼠标的图形提供支持。
3).更新管理器【UpdateManager】:更新管理器是负责画和更新Draw2D图形。当一个画的请求被事件转发器从SWT canvas发送到LightweightSystem上时,LightweightSystem调用更新管理器performUpdate()方法。一般管理器维持着一个List列表,该列表包含无效的或需要重画的图形。
3、Figure类
Draw2D的界面中看到的都是图形,即Figure类的实例。它在一个重量级的窗口中模拟一个重量级图形系统。在不消耗太多系统资源情况下,他们允许你创建一个复杂的图形展示。图形都应该建立在根图形之上。
Figure的绘制过程:
1).paintfigure() 图形绘制本身
2).paintclientarea() 绘制该图形的子图形
3).paintborder() 绘制该图形的修饰边框
验证:当图形的大小或位置需要被计算时(如图形的位置发生变化时),Draw2D将使用验证。
1).validate( ) 要求图形的布局管理器重新布局它的子图形。
2).revalidate( ) 首先调用invalidate( )方法(该方法会使该图形及其父链上的图形无效),其次,添加该图形及其父链到更新管理器的无效List上。

四、GEF的MVC
1、GEF的优势是提供了标准的MVC(Model-View-Control)结构。与其他的一些MVC框架相比,GEF的一个主要设计目标是尽量减少模型和视图之间的依赖,好处是可以根据需要选择任意模型和视图的组合,而不必受开发框架的限制。

2、 GEF中MVC框架的实现


图4.1 MVC的示例图




图4.2 GEF的MVC实现




图4.3 GEF通过EditPart来管理Model和Figure


通过第二章的内容,结合图4.2中我们可以得到一个结论:
View部分:GEF利用Draw2D的Figuer作为自己的View。
Model部分:往往内部包含了千差万别、不可预知的商业信息。因此GEF框架应该尽量减少约束。
Controller部分: EditPart中建立了与其对应的Draw2D的Figure和用户自定义的Model结点建立一一关联的关系。
Controller(EditPart)也是树形的层级,这样的话更能容易的对具体具有树形结构的Model,进行特殊化UI和相关的行为处理方式,更容易进行功能分解。
因此在设计Controller(EditPart)时,只需处理自身逻辑、管理子Controller、通知父Controller。

3、 如何使用GEF来创建Model/Figure/EditPart



图4.4 GEF创建MVC相关类


1).从上图可以看出在GEF是通过EditPartFactory根据以存在的Model 来创建并设置不同的EditPart。
EditPartFactory的接口如下:
EditPart createEditPart(EditPart context, Object model);

2).其中model是Object类型,因此可以看出在GEF对model没什么过多的约束,context是于要创建的EditPart有关联的EditPart,例如是将要创建EditPart的Parent。
参考时序图:GEF创建Editor时序图

五、EditPart
1、EditPolicy

六、GEF的事件转义与事件传递:Tool
1、用户输入(系统UI事件)与UI业务语义
在界面操作过程中,我们希望面对的是边框调整事件,图形移动事件,或者是编辑文本事件,而不是原始的鼠标和键盘事件?


术语定义:
系统UI事件:一般由某些计算机人机交互硬件发出信号,并且经操作系统理解后产生的事件,例如:原始的鼠标的移动、点击和键盘的敲击事件等。
UI业务语义事件: 由系统UI事件和其它UI业务语义事件触发,由UI业务代码理解后产生的事件(操作系统不可理解,同时无任何领域的业务语义),如2D图形的尺寸调整,2D图形的点击,2D图形的移动。(其实不仅限于事件的转义,包括UI的改变,也需要由系统UI语义转换到UI业务语义来使用)
UI业务语义事件在Controller控制中的优点是易于理解、维护和扩充,具体的主要有以下方面:
a.减少系统UI事件判断逻辑部分代码的重复。比如在Controller部分代码无需分步着大量逻辑重复的代码,当鼠标移动时去判断究竟是一个2D图形的尺寸改变,还是一个2D图形的移动,还是一组2D图形的移动,还是2D图形DragAndDrop的动作。
b.Controller部分的代码语义明确。在Controller内部处理代码和接口中直接面对的是UI业务语义,如图形的移动,图形的尺寸改变,这样、代码易于理解、调试等。
b.Controller部分代码无需为系统UI事件保存状态。如2D图形的移动中,如果这些事件直接在Controller中处理,从开始MouseDown,到MouseMove,到MouseUp过程中,在Controller中要集中保留这样众多状态,极易造成Controller代码具体多头职责的症状,从而患上严重的精神分裂:)。

2、GEF给出的解决方案



图6.1 GEF给出的解决方案


GEF通过Tools(根interface是Tool),当然在视图上的Menu和Toolbar是通过Action发出,这个是eclipse的Workbench机制,在此就不讨论了。


图6.2 Tool的类继承树


从Tool继承的这些类均处理一个或者一类UI业务语义事件,其中需要保留中间状态的子类均以XXXTracker形式出现。
首先这些Tool的实现类通过Tool的接口(上图右边),接收界面来的事件,然后调用内部方法,例如键盘按下事件(AbstractTool. handleButtonDown())之类的handle***()的方法;这样通过AbstractTool的具体实现类中的内部函数getTargetRequest()[createTargetRequest()]和getSourceRequest()[createSourceRequest()],把系统UI事件转换为UI业务语义事件叫Request(如图6.3)。至此Tool会通过调用相关联的EditPart的接口将UI业务语义事件通知到EditPart中。于是在Controller(EditPart)中仅仅需要理解处理Request对象。


图6.3 Request的类继承树


Tool这些事件接口,如何从Viewer传递过来的呢?

图6.4 从SWT的系统UI Input到GEF的Tool


注意以下两方面
1)、创建这些关键事件处理链的过程(注意图上的粗体文字);
2)、消息从SWT中Canvas实例传递到Tool过程(图D中注释标签的顺序)

学习了Tool产生Request的机制,可以帮助我们调试GEF,同时如果在大家自己的程序中需要有新的UI交互类型,也可以试着建立自己的Tool类产生新的Request,这样在自己的EditPart产生对应的Command,这样就可以处理实现新的UI交互类型。

自定义Request
从本章的内容,理解了SWT的UI输入如何传到GEF的Tool中,并知道Too是用来对系统UI输入进行转义并转换成EditPart能理解的Request,而最终会由EditPart的EditPolicy来处理Tool产生的Request。
那么我们就可以针对GEF的机制来制定我们自用的Request来实现我们特定的功能。

假设我们需要有一个功能,当通过Tool,左键画布上选中的节点,并改变节点的颜色。

1)、修改Node,增加用于反映颜色的变量
模型里节点(Node)类里没有反映颜色的成员变量,所以先要在Node类里添加一个color属性,以及相应的 getter/setter方法,注意这个setter方法里要和其他成员变量的setter方法一样传递模型改变的消息。仿照其他成员变量,还应该有一个静态字符串变量,用来区分消息对应哪个属性。
final public static String PROP_COLOR = "COLOR";

protected RGB color = new RGB(255, 255, 255);

public RGB getColor() {
    return color;
}

public void setColor(RGB color) {
    if (this.color.equals(color)) {
        return;
    }
    this.color = color;
    firePropertyChange(PROP_COLOR, null, color);
}

2)、修改NodePart支持当Node的color属性的值改变时进行视图的刷新
修改NodePart里的propertyChanged()和 refreshVisuals()方法,在前者里增加对color属性的响应,在后者里将NodeFigure的背景颜色设置为Node的color属性对应的颜色。
public void propertyChange(PropertyChangeEvent evt) {
    if (evt.getPropertyName().equals(Node.PROP_COLOR))//Response to color change
        refreshVisuals();
}
}

protected void refreshVisuals() {
((NodeFigure) this.getFigure()).setBackgroundColor(new Color(null, node.getColor()));
}

3)、自定义一个Request
因为目的是改变颜色,所以不妨叫做ChangeColorRequest。它应当继承自org.eclipse.gef.Request,我们需要ChangeColorRequest上带有两样信息:1.需要改变颜色的节点;2.目标颜色。因此它应该有这两个成员变量。
public class ChangeColorRequest extends Request{
    final static public String REQ_CHANGE_COLOR="REQ_CHANGE_COLOR";
    private Node node;
    private RGB color;

    public ChangeColorRequest(Node node, RGB color) {
        super();
        this.color = color;
        this.node = node;
        setType(REQ_CHANGE_COLOR);
    }

    public RGB getColor() {
        return color;
    }

    public Node getNode() {
        return node;
    }

    public void setNode(Node node) {
        this.node = node;
    }

    public void setColor(RGB color) {
        this.color = color;
    }
}
ChangeColorRequest看起来和一个JavaBean差不多,的确如此,因为Request的作用就是传递翻译后的鼠标事件。如果你看一下org.eclipse.gef.Request的代码,你会发现Request还有一个type属性,这个属性一般是一个字符串(在gef的RequestConstants里预定义了一些,如RequestConstants.REQ_SELECTION_HOVER), EditPolicy可以根据它决定是否处理这个Request。在我们的例子里,顺便定义了这样一个常量字符串REQ_CHANGE_COLOR,在后面的 ChangeColorEditPolicy里会用到它。

4)、需要覆盖SelectionTool的handleButtonDown
(PS:尽量做到复用,GEF中已经提供了很多很好用的Tool的实现类,我们通过对GEF中Tool的类继承树中具体实现类的理解来选择比较符合我们当前需要实现功能的Tool实现类,并覆盖其中方法来达到代码复用,也能更快的实现功能。)

我们理解了对节点上色这个需求后,发现“上色工具”的用法和“选择工具”基本上差不多。显然,我们需要覆盖的是handleButtonDown()方法,用来告诉gef如果用户当前选择了这个工具,在画布区域按下鼠标会发生什么事情。
代码如下:
public class ChangeColorTool extends SelectionTool {.
private RGB color;

   public ChangeColorTool(RGB color) {
        super();
        this.color = color;
    }

   @Override
    protected boolean handleButtonDown(int button) {
        //Get selected editpart
        EditPart editPart = this.getTargetEditPart();
       
        if (editPart instanceof NodePart) {
            NodePart nodePart = (NodePart) editPart;
            Node node = (Node) nodePart.getModel();
           
            //Create an instance of ChangeColorRequest
            ChangeColorRequest request = new ChangeColorRequest(node, color);
           
            //Get command from the editpart
            Command command = editPart.getCommand(request);
           
            //Execute the command
            this.getDomain().getCommandStack().execute(command);
           
            return true;
        }
        return false;
    }
}

5)、实现改变颜色的Command
GEF里任何对模型的修改都是通过command完成的,因此一个ChangeColorCommand肯定是需要的。
public class ChangeColorCommand extends Command{
    private RGB oldColor;

    @Override
    public void execute() {
        oldColor = node.getColor();
        node.setColor(color);
    }
   
    @Override
    public void undo() {
        node.setColor(oldColor);
    }
}

6)、增加Policy来处理ChangeColorRequest
EditPolicy负责接收所有的Request,所以还要创建一个ChangeColorEditPolicy。
public class ChangeColorEditPolicy extends AbstractEditPolicy {
    final static public String CHANGE_COLOR_ROLE = "CHANGE_COLOR_ROLE";

    @Override
    public Command getCommand(Request request) {
        //Judge whether this request is intersting by its type
        if (request.getType() == ChangeColorRequest.REQ_CHANGE_COLOR) {
            ChangeColorRequest theRequest = (ChangeColorRequest) request;
           
            //Get information from request
            Node node = theRequest.getNode();
            RGB color = theRequest.getColor();
           
            //Create corresponding command and return it
            ChangeColorCommand command = new ChangeColorCommand(node, color);
            return command;
        }
        return null;
    }
}

7)、在NodePart中增加ChangeColorEditPolicy
protected void createEditPolicies() {
   //Add change color editpolicy
installEditPolicy(ChangeColorEditPolicy.CHANGE_COLOR_ROLE,new ChangeColorEditPolicy());
}
  • 大小: 10.3 KB
  • 大小: 6.3 KB
  • 大小: 3.8 KB
  • 大小: 9.3 KB
  • 大小: 8.2 KB
  • 大小: 18.8 KB
  • 大小: 16.6 KB
  • 大小: 56.6 KB
  • 大小: 29.7 KB
  • 大小: 16.6 KB
分享到:
评论

相关推荐

    GEF简易教程-学习GEF的入门教程

    #### 一、GEF简介与环境配置 **GEF**,全称为**Graphical Editing Framework**,是Eclipse平台上用于创建复杂图形编辑器的框架。它提供了一套完整的工具集,使开发者能够构建具有图形化用户界面的应用程序,特别...

    GEF 3.10 eclipse 插件

    **一、GEF简介** GEF(Graphical Editing Framework)是Eclipse平台中的一个图形编辑框架,用于构建图形化用户界面和图形编辑工具。它为开发者提供了创建可定制的、基于模型的图形编辑器所需的各种组件和服务。GEF自...

    GEF锚点鼠标定位

    在图形编辑框架(GEF,Graphical Editing Framework)中,锚点(Anchor)是一个关键概念,它是连接模型元素之间的连接线在元素上的固定点。在GEF中,锚点的定位直接影响到连接线的形状和行为,特别是当用户通过鼠标...

    GEF Example Source Code

    这些示例涵盖了GEF的基本用法和高级特性,包括图元的创建、拖放操作、撤销/重做机制、以及事件处理等。 通过深入研究这两个压缩包,开发者可以学习如何结合使用GEF和Zest来创建强大的图形编辑器。这可能涉及到以下...

    GEF中文教程+代码

    - **Step 6-7**:介绍交互功能,如选择、拖动和约束处理,以及事件处理机制。 - **Step 8-9**:讲解命令模式的应用,实现可撤销/重做功能,并讨论如何处理模型变化的传播。 - **Step 10-11**:高级特性,如自定义...

    GEF理解系列三

    首先,GEF的核心在于其事件处理机制。当用户在图形视图上执行操作(如点击、拖动等)时,SWT事件会被转换为请求(request),这些请求随后被发送到Controller(通常是EditPart)上。Controller并不直接处理操作,...

    GEF教程和demo源码

    5. **事件监听**:源码可能会添加事件监听器,以便当用户与图形元素交互时,能够响应并更新模型。 6. **运行与调试**:最后,源码会教你如何在Eclipse环境中运行和测试这个简单的GEF应用。 通过这个教程和示例,你...

    GEF-ALL-3.7+GEF-ALL-3.8+GEF_Draw2d学习资料

    同时,Draw2D还提供了事件处理机制,使得图形可以响应用户的交互操作。 该资源包中的文档包括: 1. "GEF.doc" 和 "Draw2D.doc" 可能是关于这两个框架的基本介绍和使用指南。 2. "GEF入门系列(一、Draw2D).doc" ...

    Eclipse的GEF学习

    通过将复杂的编辑操作抽象为请求(Request)、角色(Role)、策略(EditPolicy)和命令(Command),GEF提供了一套灵活且强大的机制,让开发者可以专注于业务逻辑,而不必担心图形界面的具体实现细节。 #### 五、GEF在实际...

    GEF框架入门学习

    这是我自己在学习GEF的时候做的一些总结。 1、GEF中的概念比如Command,Tool,Request等等。 2、GEF中使用到的几种设计模式。 3、GEF中对鼠标键盘事件处理的机制、流程。

    GEF实例教程PDF

    #### 一、GEF简介与环境配置 - **GEF (Graphical Editing Framework)**:GEF是Eclipse平台提供的一个用于构建图形编辑器的框架,能够帮助开发者快速构建功能丰富的图形用户界面。适用于创建各种类型的图形编辑器,如...

    GEF入门学习例子

    6. **适配器(Adapter)**: 适配器机制使得不同组件之间能够互相通信,即使它们的接口不兼容。在GEF中,适配器通常用于将模型对象转换为视图对象。 7. **手势(Gesture)**: 手势是用户与图形元素交互的方式,如鼠标...

    GEF 入门版中文教程 源码

    GEF提供了一套机制来创建和管理编辑器。 4. **命令(Command)**:GEF中的命令模式用于封装对模型的修改操作,使得撤销/重做功能得以实现。命令对象记录了更改前后的状态,便于执行回滚或重复操作。 5. **图元...

    GEF 进阶+源码.rar

    9. **事件处理(Event Handling)**:DRAW2D和GEF都提供了丰富的事件处理机制,允许监听和响应用户操作,如鼠标点击、键盘输入等。 10. **样例代码(Sample Code)**:`samplecode.rar`很可能包含了实际的编程示例...

    GEF连接线Node之间连接

    总的来说,理解和实现“GEF连接线Node之间连接”需要掌握`GEF`框架的基本结构、事件处理、模型与视图的分离、以及图形元素的布局和约束。这不仅可以帮助你构建出强大的图形编辑工具,也能提升你在图形界面开发领域的...

    GEF学习资料

    在这个教程中,可能会通过一个实际的GEF应用示例来讲解如何创建和操作图形元素,如何处理用户的交互事件,以及如何利用GEF的事件驱动机制来更新图形视图。此外,"dudu"可能还会涉及图形布局算法,这是图形界面设计中...

    GEF 入门教程 中文版

    #### 一、简介 GEF(Graphical Editing Framework),即图形编辑框架,是一种基于Java的技术,它作为Eclipse框架的一部分,由IBM开发。GEF为开发者提供了一整套解决方案,用于Java对象模型的图形化建模。它可以与...

    GEF-SDK-3.6.2 jar

    4. **连接器和容器**:GEF提供了处理图形元素之间连接以及包含关系的机制,如树形结构、网格布局等。 5. **自动生成代码**:通过GEF,开发者可以定义图形化的编辑域,然后自动生成对应的Java代码,减少了手动编码的...

    GEF教程

    #### GEF入门挑战与策略 面对GEF框架的学习门槛,正确的学习策略至关重要。作者在“八进制”Blog中分享的经验指出,结合具体实例进行学习是一种高效的方法。通过边看代码边对照文档,再辅以实际动手实践,能够逐步...

Global site tag (gtag.js) - Google Analytics