`

GEF 应用初学

    博客分类:
  • GEF
阅读更多

目的:实现在editor上画矩形,并将矩形用线连接起来。进一步,在GEF中实现属性视图、大纲视图。

创建例程

利用模板创建一个Hello RCP插件例程,运行该例程(这个例程是用了eclipse的平台的启动入口)。

添加GEF依赖插件

在该例程的plugin.xml的插件依赖项中,目前只有org.eclipse.uiorg.eclipse.core.runtime两个插件依赖项,现在将org.eclipse.gef插件添加进来。

扩展editor

打开“扩展”选项卡,对org.eclipse.ui.editors扩展,

<extension

         point="org.eclipse.ui.editors">

      <editor

            class="gef.chenq.editor.GEFEditor"

            contributorClass="gef.chenq.actions.DiagramActionBarContributor"

            default="true"

            extensions="chenq"

            icon="icons/alt_window_16.gif"

            id="gef.chenq.gefEditor"

            name="gef Editor">

      </editor>

   </extension>

说明:class 指明了我们GEF Editor,可以理解为画布。

contributorClass:使我们对于键盘、菜单等进行动作的绑定而设定。

extensions:是我们定义的文件的后缀名,当文件的后缀是”chenq”,双击该文件就能打开GEF编辑器。

定义了class就要实现它,因为我们要使这个editor有一个调色板,所有让GEFEditor继承GraphicalEditorWithPalette类。这个类就是我们编辑器类。

对于contributorClass,也要实现它,暂时让它继承gef中的ActionBarContributor。在buildActions()以及contributeToToolBar()方法中添加redo/undodelete的动作(参考其他)。

定义模型

根据要求我们要创建3个模型,一个是画布Diagram,一个是代表矩形的Node,一个是代表连线的Connection。因此,在models包下建立这三个模型。GEF告诉我们模型要与控制器EditPart打交道(EditPart是模型和视图之间交互的唯一桥梁)。模型的变化如何通知EditPart呢?我们让EditPart(每一个模型对应一个控制器EditPart)实现propertyChangeListener接口,然后将控制器作为监听器注册到模型上,当模型变化时,控制器EditPart就收到通知。为了同一监听器注册机制,我们令这三个模型继承Element这个抽象类,这个类负责注册监听器和删除监听器。并且当模型变化时,负责通知所有的监听器。

Node

这个类表现在编辑器中时,有名字,有位置,还作为连接源和目的。因此它有4个属性,namelocationinConnectionsoutConnections。各个属性的setaddremove方法内一定含有调用通知editpart的语句。

Diagram

这个模型表现在界面上是一片空白,它有子图形NodeConnection不算),因此,Diagram只有一个Node属性的列表。

Connection

这个类表现为一条直线,因此它有源Node和目的Node两个属性。它的属性变化就不需要通知editPart,它构造时就应该有了sourcetarget两个Node

创建EditPart控制器

上面说了,每一个模型都对应一个控制器,因此在这里创建三个editPartNodePartDiatramPartConnectionPart。这些控制器都直接或间接继承AbstractGraphicalEditPart类(参考相关代码)。别忘了上面说的,让editPart实现PropertyChangeListener接口。

DiagramPart

在创建代表模型的图形方法createFigure()中我们返回一个GEF自带的图形FreeformLayer,让后给这个figure设置一个layoutManager。我们就不用构造一个figure了。

createEditPolicies()方法中,安装到EditPart中的每一个Policy都对应一个ROLE,因为Diagram有子元素,一般地都会安装EditPolicy.LAYOUT_ROLE,我们安装Diagram的编辑策略。

installEditPolicy(EditPolicy.LAYOUT_ROLE, new DiagramLayoutEditPolicy());

因为Diagram含有子元素,我们需要覆盖方法getModelChilden(),返回Diagram内的子模型。

Diagram内可以增加和删除子元素,因此在propertyChange()方法中,要处理子元素增加和删除时的响应,refreshChilden();

每个EditPart内都有activate()deactivate()方法,因此,当editpart激活时我们将editPart作为监听器注册到model上,当不活动时,移除editpart。因此当model改变时,editPart能监听器事件。

ConnectionPart

ConnectionPart需要继承AbstractConnectionPart,作为连线的控制器,在createFigure()方法中,我们可以使用gef内的PolylineConnection类,而不必自己构造一个figure

createEditPolicies()方法中,对于连接类型,一般要安装EditPolicy.CONNECTION_ENDPOINTS_ROLE角色的编辑策略。

installEditPolicy(EditPolicy.COMPONENT_ROLE, new DeleteConnectionPolicy());

installEditPolicy(EditPolicy.CONNECTION_ENDPOINTS_ROLE, new ConnectionEndpointEditPolicy());

我们可以删除连线,因此安装删除策略;我们可以在两个图形之间画线,因此安装ConnectionEndpointEditPolicy

NodePart

我们自己构造一个NodeFigure(实现一个NodeFigure继承RectangleFigure),在createFigure()方法中,返回一个NodeFigure的实例。

createEditPolicy()中安装node的删除策略,安装一个NodeGraphicalNodeEditPolicy,该策略是为了让连接可以添加到node上来(实现4个方法)。

installEditPolicy(EditPolicy.COMPONENT_ROLE, new DeleteNodePolicy());

        installEditPolicy(EditPolicy.GRAPHICAL_NODE_ROLE, new NodeGraphicalNodeEditPolicy());

propertyChange()方法中,需要监听node位置改变,名称改变,连接进入和连接输出等属性的变化。

位置等变化时需要在refreshVisuals()刷新Node的显示位置和名称。

同样的,需要在activatedeactivate方法中注册和删除监听器EditPart

为了让NodePart能用线连接,作为连接的源和目的,nodePart还要实现NodeEditPart接口,在4getXXXAnchor()中返回chopboxAnchor(getFigure())

要显示连线,NodePart还需要覆盖方法getModelSourceConnectionsgetModelTargetConnections方法,要不然,我们的连线,在创建的时候看见,一旦放开鼠标,连纤就看不见了。因为界面要不断的刷新连接的起点和终点。getModelSourceConnectionsgetModelTargetConnections方法暗地里在refreshSourceConnectionsrefreshTargetConnections方法内调用。

创建编辑策略

在上面各个editpart中的createEditPolicies()中,我们需要安装编辑策略,Role-EditPolicy——command的这种模式主要是为了尽量重用代码,同一个editPart中可以安装不同的policy,同一个command中可以被不同的policy重用。

DiagramLayoutEditPolicy

该类继承XYLayoutEditPolicy是一个表示XY布局的编辑策略,需要实现方法getCreateCommand(),在这方法中返回创建Node的命令CreateNodeCommand实例。

为了拖动Node节点在编辑器中移动,还要覆盖createChangeConstraintCommand()方法,在该方法中创建移动Node的命令MoveNodeCommand

NodeGraphicalNodeEditPolicy

创建了node节点,下面就要创建连线,所以该类继承自GraphicalNodeEditPolicy类,实现4个方法,在创建连接命令和连接创建完成命令两个方法中需要对创建连接命令CreateConnectionCommand构造和处理。

DeleteNodeEditPolicy

这个类很明显是创建一个删除Node节点命令的编辑策略。继承自ComponentEditPolicy,需要覆盖createDeleteCommand().方法需要返回一个删除节点的命令。

DeleteConnectionPolicy

功能同上。

创建命令

在编辑策略中,我们返回了一系列的创建、删除等命令,这些命令直接操作模型。这些命令一般都继承自gef.commands.Command类。

CreateNodeCommand

创建Node节点,该类具有Node属性、diagram属性、以及nodelocation属性。所谓创建节点,就是在该类的execute()方法中向Diagram模型中添加node.并指定node显示位置的location

GEF中都有redo/undo的操作,因此我们让这些命令类都覆盖Command中的redo/undo方法。

DeleteNodeCommandMoveNodeCommand

同上。

CreateConnectionCommand

创建连接命令。查看DiagramLayoutEditPolicy中,我们知道Node节点模型在创建“创建节点命令”之前的createRequest参数中就能够取得。而这个Connection模型不需要添加到diagram中,在CreateConnectionRequest参数中没有Connection模型,因此在execute()中创建connection模型。在鼠标移动并进入Node节点之上时,NodeGraphicalNodeEditPolicy中的getCreateConnectionCommand()和getCreateConnectionCommand()方法都会调用,创建了大量的Command,这些命令最终是不是入栈,需要看该条命令是不是被执行了。在上面两个方法中,需要给CreateConnectionCommand命令设置源端和目的端。因为鼠标的滑动可能创建大量的command,这就要求在CreateConnectionCommandcanExecute()方法中做一定的判断。

DeleteConnectionCommand

同上。

创建图形Figure

figure在编辑器中代表一个模型,用于可视化。上面提到了Diagram的图形,使用gef中的freeformLayerConnection的图形使用PolylineConnection。而nodeNodeFigure需要我们自己创建。

NodeFigure

我们用一个矩形框框来代笔一个Node,继承RectangleFigure,在该类内部定义一个Label(是一个Figure)作用是显示Node的名字。该类用名字属性,需要将名字设置给label。还要覆盖setBounds()方法,并设置label的参数设置给label

创建编辑器

在扩展扩展点时,我们声明了一个GEFEditor类,下面要填写代码实现之。该类中最重要的两个方法是configureGraphicalViewer()和initializeGraphicalViewer(),用来定制和初始化editPartViewer,在GraphicalEditor中先后调用者两个方法,不过中间加了一个将editor注册作为selectionProvidersite的方法hookGraphicalViewer()。我们需要在这两个方法中配置rootEditPartEditPartFactoryContents

RootEditPart和模型没有关系,是一种特殊的EditPart,可以认为是contents的容器。

EditPartFactory负责给定模型对象创建对应的EditPart对象(以显示),该类被Editor使用。比如在拖拽创建节点时,当Node模型生成了,并添加到Diagram模型后,DiagramPart收到结构改变的属性变化就去刷新childen,这时候就要去通过这个EditPartFactory创建这个nodeEditPart

Content指的就是Diagram这个模型。

setInput()Editor设置input,如果我们再GEFEditor中的总模型对象Diagram没有初始化,就要在这里初始化了。要不然报空指针了。

GEFEditor带有一个调色板,需要实现getPaletteRoot()方法创建调色板并组织调色板内的组件内容。通过一个工具类PaletteFactory来创建。创建几个PaletteContainer类分类调色板内的工具,对于选择图形工具、连接图形工具,采用gef中的SelectionToolEntry以及ConnectionCreateToolEntry实现。而node节点工具通过CombindTemplateCreateENtry生成。

GEFEditor支持拖动,因此需要在initializeGraphicalViewer()方法中添加拖动释放目标监听器,该监听器DiagramTemplateTransferDropTargetListener需要我们自己实现,并覆盖getFactory()方法,返回一个工厂类ElementFactory,(我们可以不必自己创建而采用SimpleFactory),ElementFactory负责创建各种模型。另外,我们还要对调色板添加拖动源监听器(gef.TemplateTransferDragSourceListener)。

实现键盘监听和菜单绑定

参考《动作重定向RetargetAction.doc》资料。

上面已经完成了基本GEF的实现,可以创建图形和连线。但是按delete键,却不能删除图形和连接,ctrl+Zctrl+y也不能实现redo/undo,这是因为我们没有将全局键绑定到GEFEditor中。在扩展editor扩展点时,有一项ContributorClass,就是来做这个事情的。redo/undo,delete动作GEF内部已经定义好了,我们需要在DiagramActionBarContributor中的buildActions()方法中使用addRetargetActionnew UndoRetargetAction())。如果还想将这几个动作绑定到toolBar上,还需要覆盖contributeToToolBar()方法,使用toolBarManager.add(getAction(ActionFactory.UNDO.getId()));……

 

如果只是一些常用的动作redo/undo,我们可以不用再buildActions()方法中再去创建,而是可以直接在declareGlobalActionKeys()方法通过调用addGlobalActionKey()来绑定。这里面隐含的是redo/undo操作都已经创建了,其实这些操作是在GEF编辑器的createActions()方法中创建的(通过super.createActions())。

 

如果我们不想通过定义一个actionBarContributor的类来重定向动作。那么我们可以在GEFEditor初始化的时候添加action重定向代码来完成,比如,在initializeGraphicalViewer()方法中通过getEditorSite().getActionBars()得到actionBars,并通过getActionRegistry()方法得到actionRegistry

//准备从ActionRegistry中找actionId对应的处理动作

        ActionRegistry registry = getActionRegistry();

        //actionBar上按钮的重定向

        IActionBars bars = this.getEditorSite().getActionBars();

        IToolBarManager toolBarManager = bars.getToolBarManager();

        //actionid

        String id = ActionFactory.UNDO.getId();

        bars.setGlobalActionHandler(id, registry.getAction(id));

        //动作绑定到工具栏上

        toolBarManager.add(registry.getAction(id));

 

实现Figure的直接编辑

实现Node的重命名的直接编辑。

实现直接编辑的原理:当用户发出修改请求时,就在文字所在的位置覆盖一个文本框等组件作为编辑器,编辑结束后,在将编辑器中的内容应用到模型中。

GEF中这个弹出的编辑器由DirectEditManager类负责管理,在NodePart类里,通过覆盖performRequest()方法响应用户的DirectEdit请求,在这个方法内构造一个DirectEditManager类的实例。其参数有editpPart控制器,有弹出的编辑器的类型(TextCellEditor.class)以及cellEditor的位置cellEditorLocator实例,然后让manager显示(show)。

根据以上要求,首先要实现一个DirectEditManagerNodeDirectEditManager,这该类内主要实现initCellEditor()方法,为编辑器中的text设置初始值、字体、颜色、选中全部文字等操作。

然后要实现一个CellEditorLocatorNodeCellEditorLocator,该类的方法relocate()使得当编辑器内容改变时,让编辑器始终处于正确的位置,为此,在方法内取得cellEditorText的最优size以及nodeFigure的文本的边界,计算后设置给text

修改NodeFigure,添加一个方法getTextBounds()并在内返回NodeFigurelabel的文本的边框label.getTextBounds().如果返回的是label.getBounds(),那么弹出的编辑器的文本框将会在NodeFigure左上角(因为labelboundfigurebound大小一样)。

准备工作完成了,下面还是老生常谈,建立直接编辑的Editpolicy安装到NodePart中,建立DirectNodeEditCommand添加到NodeDirectEditPolicy中。其中有showCurrentEditValue()方法,作用是在编辑时,始终保持figure中的文本和编辑器中的文本一致,不至于出现盖不住的情况。

实现属性视图

比如要在属性视图中显示Node的基本属性需要修改几处,1首先要将属性视图所在的插件添加到依赖项(org.eclipse.ui.views)2 node实现IPropertySource接口,实现方法getPropertyDescriptors()需要返回变量对应的描述。3 实现getPropertyValue(),4 实现setPropertyValue()。

实现大纲视图

eclipse中当编辑器Editor被激活时,大纲视图自动通过这个编辑器的getAdapter()方法寻找他提供的大纲(大纲实现IContentOutlinePage接口)。GEF提供了ContentOutlinePage类(是一个page)用来实现大纲视图(PageBookView)。我们要做的就是重点实现它的createPartControl()方法。大纲视图(PageBookView)有一个PageBook,包含很多的page,并且可以在他们之间切换。切换的依据就是当前活动的editor,因此我们在createPartControl()中就是要构造这个pagepage中的createPartControl()如下:

publicvoid createControl(Composite parent)

        {

            // getViewer()返回的是在构造函数中的TreeVieweroutline就是一个Tree

            outline = getViewer().createControl(parent);

            // TreeViewer添加到同步器中,从而让用户不论在大港或是编辑区内选择editPart

            // 另一方都能自动做出同样的选择

            getSelectionSynchronizer().addViewer(getViewer());

 

            // 保存命令的栈,与GEFEditor中的EditDemain是一个,这样能在大纲视图中和GEFEditor中都能响应redo/undo动作

            getViewer().setEditDomain(getEditDomain());

            // 要有一个editpartfactory负责给定模型对象创建对应的editPart对象

            getViewer().setEditPartFactory(new TreePartFactory());

            // 将模型(内容)和视图联系起来

            getViewer().setContents(diagram);

        }

同时,在GEFgetAdapter()方法中当传入的参数时IContentOutlinePage.class时返回创建的outlinePage对象。

我们大纲视图的实现也是采用MVC的模式,所以给TreeViewer(也就是getViewer())设置一个模型到控制器的创建工厂TreePartFactory。在我们实现的TreePartFactory中,我们新建了两个在大纲视图中应用的EditPartDiagramTreeEditpartNodeTreeEditPart)。

这基本完成大纲视图的实现,操作发现,当大纲视图处于激活状态时,toolBar上的redo/undo不可用,这是因为对于大纲视图,没有进行action的重新绑定,因此,在outlinePage类的init()方法中添加action重绑定的代码。

分享到:
评论

相关推荐

    界面设计GEF应用实例

    【标题】"界面设计GEF应用实例"涉及的是在软件开发中使用图形编辑框架(Graphical Editing Framework,简称GEF)进行用户界面设计的具体实践。GEF是Eclipse平台下的一个开源组件,它为创建可定制的、交互式的图形...

    GEF初学者开发样例

    **GEF初学者开发样例详解** ...总的来说,GEF为图形编辑器的开发提供了一种标准和灵活的框架,通过"gefpractice"这样的实践项目,初学者可以逐步掌握其核心概念和实际应用,从而提升在图形界面开发领域的技能。

    gef版本的helloworld

    2. GEF的基本结构:GEF应用程序通常包括三个核心组件——模型(Model)、控制器(Controller)和视图(View)。文档中介绍了如何在Eclipse的plugin.xml文件中设置依赖,以便加入GEF库。接着,重点在于创建Editor,...

    GEF入门必读 GEF入门系列 GEF-whole-upload

    10. **调试与测试**:提供调试GEF应用程序的方法和技巧,以及如何进行单元测试和集成测试。 通过深入学习这些内容,开发者能够具备创建专业级图形编辑器的能力,适用于软件建模、流程设计、电路图等多种场景。对于...

    Eclipse的GEF学习

    ### Eclipse的GEF框架深入解析 #### 一、GEF框架概述 GEF,全称为Graphical Editor Framework,是Eclipse平台下...无论是初学者还是经验丰富的开发者,掌握GEF都将为他们在图形编辑领域的工作带来巨大的帮助和便利。

    GEF教程

    即便是最基础的GEF应用程序,也会涉及到多个包和数十个类,涵盖从模型到视图再到控制器的完整链路。这种结构化的设计,虽然在初始阶段可能会让人感到困惑,但一旦理解其设计理念,就能体会到其在扩展性和灵活性上的...

    GEF学习资料

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

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

    2. "GEF入门系列(一、Draw2D).doc" 可能是一个逐步的教学系列,从基础的Draw2D开始,逐步引入GEF的概念和应用。 3. "如何在Eclipse3.3.1.1中安装VE,emf,GEF插件.doc" 提供了在特定版本的Eclipse中安装相关插件的步骤...

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

    ### GEF简易教程知识点详解 #### 一、GEF简介与环境配置 **GEF**,全称为**Graphical Editing Framework**,是Eclipse平台上用于...继续探索GEF的高级特性,将有助于你开发出更加复杂且功能丰富的图形化应用程序。

    GEF入门学习例子

    这个入门学习例子旨在帮助初学者理解GEF的基本用法和核心概念,通过实例展示如何利用GEF实现工具栏、菜单栏、属性栏以及图形的交互功能,如移动、删除、撤销、连线等,并涵盖了大纲视图和鹰眼功能的实现。...

    GEF-ALL-3.2.zip_GEF-ALL-3.6.2 pudn_gef_gef 3.2 download_gef java

    **gef-runtime** 标签指的是运行时环境,这部分通常包括了运行GEF应用所需的库和依赖。开发者在自己的项目中集成GEF时,需要确保正确配置这些运行时依赖。 在压缩包内的`www.pudn.com.txt`可能是下载链接的来源记录...

    GEF 入门版中文教程 源码

    总结来说,"GEF入门版中文教程 源码"是一个面向初学者的宝贵资源,它涵盖了GEF的主要概念和技术,结合源码实践,可以帮助开发者快速掌握图形化编辑器的开发技术,并为后续的RCP应用开发打下坚实基础。无论你是希望...

    GEF开发指南---插件开发

    该书深入浅出地讲解了如何利用GEF(Graphical Editing Framework)进行插件开发,特别适合初学者阅读。GEF是Eclipse平台上的一个框架,用于构建高级的图形编辑器。 #### 二、GEF基本概念 - **GEF**:GEF全称为...

    GEF开发指南

    GEF(Graphical Editing Framework)图形...它不仅对初学者有着很强的入门指导性,对于有经验的开发者而言,也是一份很好的参考手册,有助于更深入地了解和掌握GEF框架的高级特性,提高图形编辑应用的开发效率和质量。

    GEF中文教程+代码

    **GEF(Graphical Editing Framework)** 是一个强大的开源框架,用于构建图形化编辑器,主要在Java平台上运行,由...无论你是初学者还是有经验的开发者,这个教程都会对你在图形界面开发领域的能力提升有所帮助。

    GEF 入门教程 中文版

    本教程的初衷是解决作者们在开发GEF应用时遇到的诸多问题。在互联网上以及相关书籍(如IBM Redbook)中找到的主要文档更多地集中在GEF的理论概念上,而非具体如何使用GEF类的实际应用案例。因此,本教程旨在通过实际...

    GEF入门系列 pdf 格式资料

    本资料集合包含了一系列关于GEF的入门教程,旨在帮助初学者快速掌握GEF的基本概念、架构和应用。 **1. GEF的核心概念** - **模型-视图-控制器(MVC)**:GEF基于MVC设计模式,将图形元素的逻辑(模型)、显示(视图...

    GEF入门实例代码2《Eclipse插件开发》中实例

    这个实例代码2是《Eclipse插件开发》教程中的一部分,旨在帮助初学者理解如何利用GEF来创建自定义的图形编辑器。在Eclipse插件开发中,GEF提供了一套强大的框架,使得开发者可以方便地构建出功能丰富的图形用户界面...

    gef小例子(含文档)

    这个压缩包“gef小例子(含文档)”似乎包含了一些示例代码和相关文档,旨在帮助用户更好地理解和应用Gef。 在Eclipse插件开发中,GEF(Generic Editor Framework)是一种用于构建图形化编辑器的框架,它允许开发者...

Global site tag (gtag.js) - Google Analytics