`
yiliner
  • 浏览: 214540 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

在GEF中如何使用DirectedGraph来对图中的对象进行位置的排放

    博客分类:
  • GEF
阅读更多

在使用GEF进行开发的时候,对于需要绘制的图形的节点,往往除了模型对象本身之外,还需要有一个相应的“图”对象来保存图中这个节点的位置,以及大小等图相关,但是与业务模型无关的一个对象。而在一开始希望显示一个初始模型文件的时候,再对应保存图信息的文件不存在的情况下,如何能够很好的显示这个图,是一个比较麻烦的问题,涉及到对布局算法的一些分析与实现。这片文章就是介绍,如何使用GEF内的DirectedGraph这个类以及其相应的布局算法类DirectedGraphLayout,来解决这个问题。
基本思想是:为
GEFEditPart模型生成一个DirectedGraph,然后使用DirectedGraphLayout来计算布局,最后将布局的结果通过GEF显示出来。

 

在参考了GEFflow example之后,对其代码作了部分重构,写了这片文章,希望对遇到同样问题的同志能够有一定的帮助。

 

首先引入一个接口:

public interface GraphBuilder {

       public void contributeNodesToGraph(DirectedGraph graph, Map map);

       public void contributeEdgesToGraph(DirectedGraph graph, Map map);

       public void applyGraphResults(DirectedGraph graph, Map map);

}

这个接口中定义了几个方法,其含义从其方法名中可以猜出:

contributeNodesToGraph:将当前对象作为节点(Node)添加到DirectedGraph中。

contributeEdgesToGraph:将当前对象所对应的连线作为边(Edge)添加到DirectedGraph中。

applyGraphResults:将图中生成的布局信息取出,对本对象进行重新布局。

接口中的graph参数就是保存的图的信息,map参数维持一个对象到节点/边的映射,使得每个对象能够方便的找到其对应的图中的节点或者边。这个接口的使用,在后面会有涉及。下面先看看显示图的容器是如何构建的。

 

图的容器定义为GraphDiagramEditPart,这个EditPart对应于要显示的有向图的容器。它实现了GraphBuider接口,这也是我们主要需要关注的接口:

public class GraphDiagramEditPart extends AbstractGraphicalEditPart implements

              GraphBuilder.

 

contributeNodesToGraph方法将自身作为节点添加到图中,但是因为GraphDiagramEditPart对应的是容器,因此它不需要向图中添加信息,只是调用其子EditPart,将其添加到图中。

       public void contributeNodesToGraph(DirectedGraph graph, Map map) {

              for (int i = 0; i < getChildren().size(); i++) {

                     NodeEditPart activity = (NodeEditPart)getChildren().get(i);

                     activity.contributeNodesToGraph(graph, map);

              }

       }

 

contributeEdgesToGraph方法将这个EditPart的所有子EditPart取出,调用其contributeEdgesToGraph方法,通过这个方法,就可以将所有的边添加到图中了:

       public void contributeEdgesToGraph(DirectedGraph graph, Map map) {

              for (int i = 0; i < getChildren().size(); i++) {

                     NodeEditPart child = (NodeEditPart)children.get(i);

                     child.contributeEdgesToGraph(graph, map);

              }

       }

 

applyGraphResults方法将所有取出所有的子EditPart,并调用其applyGraphResults,使得图中所生成的布局信息能够被应用到显示上。

       public void applyGraphResults(DirectedGraph graph, Map map) {

              applyChildrenResults(graph, map);

       }

       protected void applyChildrenResults(DirectedGraph graph, Map map) {

              for (int i = 0; i < getChildren().size(); i++) {

                     GraphBuilder part = (GraphBuilder) getChildren().get(i);

                     part.applyGraphResults(graph, map);

              }

       }

 

下面要介绍的是NodeEditPart,它作图中所有节点所对应的EditPart的抽象父类,也实现了GraphBuilder接口。每一个要做为节点添加到图中的EditPart,应该继承这个类。

public abstract class NodeEditPart extends AbstractGraphicalEditPart implements

              GraphBuilder{

 

       public void contributeNodesToGraph(DirectedGraph graph,

                     Map map) {

              Node n = new Node(this);

              n.outgoingOffset = 7;

              n.incomingOffset = 7;

              n.width = getFigure().getPreferredSize().width;

              n.height = getFigure().getPreferredSize().height;

              n.setPadding(new Insets(10,8,10,12));

              map.put(this, n);

              graph.nodes.add(n);

       }

 

       public void contributeEdgesToGraph(DirectedGraph graph, Map map) {

              List outgoing = getSourceConnections();

              for (int i = 0; i < outgoing.size(); i++) {

                     EdgeEditPart part = (EdgeEditPart)getSourceConnections().get(i);

                     part.contributeEdgesToGraph(graph, map);

              }

       }

 

       public void applyGraphResults(DirectedGraph graph, Map map) {

              Node n = (Node)map.get(this);

              getFigure().setBounds(new Rectangle(n.x, n.y, n.width, n.height));

              for (int i = 0; i < getSourceConnections().size(); i++) {

                     EdgeEditPart trans = (EdgeEditPart) getSourceConnections().get(i);

                     trans.applyGraphResults(graph, map);

              }

       }

}

 

再就是边所对应EditPart的抽象类EdgeEditPart。每一个要作为边添加到图中的EditPart,需要继承这个类。在上面NodeEditPart中对其所对应的Figure其实并没有什么要求,但是对EdgeEditPart所对应的Figure,要求其Figure必须由一个BendpointConnectionRouter,作为其ConnectionRoutersetConnectionRouter(new BendpointConnectionRouter())。这样图的边的路径信息才能够被显示出来。

public abstract class EdgeEditPart extends AbstractConnectionEditPart implements

              GraphBuilder {

 

       public void contributeEdgesToGraph(DirectedGraph graph, Map map) {

              Node source = (Node)map.get(getSource());

              Node target = (Node)map.get(getTarget());

              Edge e = new Edge(this, source, target);

              e.weight = 2;

              graph.edges.add(e);

              map.put(this, e);

       }

 

       public void applyGraphResults(DirectedGraph graph, Map map) {

              Edge e = (Edge)map.get(this);

              NodeList nodes = e.vNodes;

              PolylineConnection conn = (PolylineConnection)getConnectionFigure();

              conn.setTargetDecoration(new PolygonDecoration());

              if (nodes != null) {

                     List bends = new ArrayList();

                     for (int i = 0; i < nodes.size(); i++) {

                            Node vn = nodes.getNode(i);

                            int x = vn.x;

                            int y = vn.y;

                            if (e.isFeedback) {

                                   bends.add(new AbsoluteBendpoint(x, y + vn.height));

                                   bends.add(new AbsoluteBendpoint(x, y));

 

                            } else {

                                   bends.add(new AbsoluteBendpoint(x, y));

                                   bends.add(new AbsoluteBendpoint(x, y + vn.height));

                            }

                     }

                     conn.setRoutingConstraint(bends);

              } else {

                     conn.setRoutingConstraint(Collections.EMPTY_LIST);

              }

       }

}

 

最后的就是一个LayoutManager来初始化图的创建,以及对图的信息进行解释了,生成最终布局了。这个GraphLayoutManager作为GraphDiagramEditPart所对应的GraphDiagramLayoutManager,来显示图的内容。

public class GraphLayoutManager extends AbstractLayout {

       private GraphBuilder diagram;

 

       GraphLayoutManager(GraphBuilder diagram) {

              this.diagram = diagram;

       }

 

       protected Dimension calculatePreferredSize(IFigure container, int wHint,

                     int hHint) {

              container.validate();

              List children = container.getChildren();

              Rectangle result = new Rectangle().setLocation(container

                            .getClientArea().getLocation());

              for (int i = 0; i < children.size(); i++)

                     result.union(((IFigure) children.get(i)).getBounds());

              result.resize(container.getInsets().getWidth(), container.getInsets()

                            .getHeight());

              return result.getSize();

       }

 

       public void layout(IFigure container) {

              DirectedGraph graph = new DirectedGraph();

              Map partsToNodes = new HashMap();

              diagram.contributeNodesToGraph(graph, partsToNodes);

              diagram.contributeEdgesToGraph(graph, partsToNodes);

              new DirectedGraphLayout().visit(graph);

              diagram.applyGraphResults(graph, partsToNodes);

       }

}

可以看到在layout方法中,首先生成了一个DirectedGraph,并调用了contributeNodesToGraph以及contributeEdgesToGraph方法,将节点和边的信息添加到这个生成的DirectedGraphGraph中,然后使用布局算法DirectedGraphLayout().visit(graph)来计算生成图的信息(这里使用了visitor模式)最后调用applyGraphResults将图的信息应用到图形的显示上。

 

至此,所有框架的工作做完了,如果要将模型作为一个有向图显示的话,只需要将模型的容器对象对应于GraphDiagramEditPart(在EditPartFactory中进行映射),为每一个需要表示为节点的对象,对应到一个继承于NodeEditPartEditPart,为每一个需要表示为边的模型对象,对应到一个继承于EdgeEditPartEditPart。这样,就能够将图的布局算法,应用到GEF框架中了。

 

这里写的比较简单,使用起来也会有一些具体的约束。例如在有向图中,是不能够有孤立的节点的。如果使用CompoundDirectedGraph,就不会有这样的问题,CompoundDirectedGraph可以包括子图,可以支持更为复杂的图形。在Flow Example中使用的就是CompoundDirectedGraph。在后面,我或许会将这个框架进行改写,以使其支持CompoundDirectedGraph来进行布局算法。下面的图是一个生成的例子,大家可以看一下效果:



这是从OWL文件中读取内容之后生成的一个图的表示。可以看到,OWL的节点通过自动图的自动布局之后,已经有了较好的视觉效果。如果没有这样的布局的话,因为单纯的OWL文件中并不会包含节点的图的信息,图显示出来会变得非常的乱,所有的节点都会堆在一起。

  • 大小: 51.4 KB
分享到:
评论

相关推荐

    Eclipse开发使用GEF和EMF(IBM 红皮书)中英文对照版

    《Eclipse开发使用GEF和EMF》是IBM红皮书系列中的一部经典著作,主要探讨了如何在Eclipse环境中利用GEF(图形编辑框架)和EMF( Eclipse模型框架)进行图形化应用程序的开发。这两项技术是Eclipse平台上的核心组件,...

    自己下的GEF资源打包

    用户可以通过阅读这个教程来了解如何在Eclipse环境中搭建GEF项目,并进行基本的图形编辑功能开发。 "GEF教程.pdf"可能更加深入,除了基础内容外,可能会涉及到更高级的主题,如自定义手势识别、动态模型更新、图层...

    GEF 入门版中文教程 源码

    在GEF中,模型通常由EMF(Eclipse Modeling Framework)来定义和管理,可以将业务逻辑和视图分离。 2. **视图(View)**:视图是模型的可视化表示,它将模型数据呈现为用户界面。GEF提供了基础框架来实现这一转换,...

    GEF中文教程+代码

    在本教程中,我们将深入探讨GEF的基本概念、设计原则以及如何使用它来开发自己的图形编辑器。 **1. GEF简介** GEF的设计目标是将图形编辑器的实现细节抽象化,让开发者能够专注于业务逻辑和模型设计,而不是底层的...

    gef 转折线的相关方法实现和 GEF的API chm 格式

    在gef中,转折线的实现涉及到PathFigure和Segment类的使用。PathFigure用于定义一个图形的轮廓,而Segment则代表了轮廓中的一段线段。通过添加和调整Segment实例,我们可以构建出具有转折点的线条。 实现gef转折线...

    GEF入门学习例子

    在GEF中,模型通常由`EObject`和`EObjectImpl`实现,可以使用EMF(Eclipse Modeling Framework)来生成。 2. **视图(View)**: 视图是模型的可视化表示,将模型数据呈现给用户。GEF中的视图由`GraphicalViewer`类...

    GEF_Demo_Code20170307

    这个项目旨在演示如何利用GEF进行图形界面开发,并且特别关注了通过适配器(Adapter)扩展点来实现属性页配置以及在非Editor的ViewPart中使用GEF。 GEF是Eclipse平台下的一个开源库,专门用于构建可自定义的、图形...

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

    **GEF(Graphical Editing Framework)** 是一个用于构建图形化编辑器的开源框架,它在Eclipse平台上广泛使用,特别是在开发复杂的图形用户界面和工具时。本资料集旨在为初学者提供一个全面的入门指南,帮助理解GEF...

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

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

    GEF中文帮助实例

    GEF支持图形的缩放操作,可以使用鼠标滚轮或预定义的快捷键来改变视图的比例。这有助于用户在不同层次上查看和编辑图形内容。 **七、大纲视图** 大纲视图提供了图形元素的树状结构,便于用户浏览和选择模型中的元素...

    GEF的动态变化二

    在GEF中,动画通常涉及图元的帧序列,通过改变其位置、大小或其他属性来创造动态效果。可能包含关键帧动画、时间线控制、事件驱动的更新或者其他动画技术。 在GraphAnimation.java中,我们可能会看到以下知识点: 1...

    GEF锚点鼠标定位

    在GEF中,锚点的定位直接影响到连接线的形状和行为,特别是当用户通过鼠标进行交互时。"GEF锚点鼠标定位"这个主题主要探讨的是如何使锚点跟随鼠标移动,从而提供更加灵活和直观的用户操作体验。 1. **GEF框架基础**...

    GEF理解系列三

    在GEF(Graphical Editing Framework)中,理解其工作流程对于开发图形编辑工具至关重要。GEF主要用于构建基于SWT和JFace的图形用户界面,它提供了丰富的功能来处理图形元素的绘制、操作和交互。本篇文章将深入探讨...

    GEF教程及demo源码GEF_RCP_DEMO.zip

    GEF使用命令模式来处理用户的编辑操作,每个编辑操作对应一个Command对象。当用户执行操作时,Command执行其doExecute()方法;如果需要撤销,调用undo()方法。 6. **适配器模式与EditPolicy** EditPolicy是GEF中...

    GEF典型实现例子

    在描述中提到的“博文链接”,我们可以推断这可能是一个关于如何使用GEF的教程或技术分享。 源码标签表明内容可能包含了实际的代码示例,这对于学习和理解GEF的工作原理和如何在实际项目中应用非常有帮助。工具标签...

    GEF 入门教程 中文版

    在互联网上以及相关书籍(如IBM Redbook)中找到的主要文档更多地集中在GEF的理论概念上,而非具体如何使用GEF类的实际应用案例。因此,本教程旨在通过实际操作指导读者逐步掌握GEF的核心技术和实践技巧。 #### 二...

    GEF-II电场仪使用手册.pdf

    附录A则提供了一些Linux常用指令,方便操作者在Linux环境下进行操作。 特别提醒: - 在上电前应检查仪器,若运输过程中可能导致内部连接件松散,应先大动作摇晃几下主机检查是否有异响,有则需开盖检查连接固定后再...

    GEF快速入门教程和EMF教程

    - 添加依赖后,项目的构建路径将包含GEF库,从而可以在项目中使用GEF功能。 ### 创建Editor 接下来,我们将创建一个Editor,这是GEF应用中最核心的部分之一。通常情况下,GEF会集成到Editor中而非View中,这是...

    GEF实现拷贝粘贴

    标题“GEF实现拷贝粘贴”涉及到的是在软件开发中使用Graphical Editing Framework(GEF)进行图形界面编辑时,如何实现复制和粘贴功能的技术。GEF是Eclipse平台下用于构建图形化编辑器的框架,它提供了一套完整的...

Global site tag (gtag.js) - Google Analytics