GEF常见问题5:自动布局

简介: 利用自动布局功能,我们可以把本来不包含图形信息的文件以图形化的方式展示出来,典型的例子比如将一组Java接口反向工程为类图,那么图中每个图元的坐标应该必须都是自动生成的。GEF里提供了DirectedGraphLayout类用来实现自动布局功能,下面介绍一下怎样在程序里使用它。

利用自动布局功能,我们可以把本来不包含图形信息的文件以图形化的方式展示出来,典型的例子比如将一组Java接口反向工程为类图,那么图中每个图元的坐标应该必须都是自动生成的。GEF里提供了DirectedGraphLayout类用来实现自动布局功能,下面介绍一下怎样在程序里使用它。

DirectedGraphLayout提供的visit()方法接受一个org.eclipse.draw2d.graph.DirectedGraph实例,它遍历这个有向图的所有节点和边,并按照它自己的算法计算出每个节点布局后的新位置。所以在使用它布局画布上的图元分为两个步骤:1、构造有向图,2、将布局信息应用到图元。

还是以gefpractice为基础,我们在主工具条上增加了一个自动布局按钮,当用户按下它时自动布局编辑器里的图形,再次按下时恢复以前的布局。为了完成步骤1,我们要在DiagramPart里添加以下两个方法:

/**
 * 将图元(NodePart)转换为节点(Node)到有向图
 * 
@param  graph
 * 
@param  map
 
*/
public   void  contributeNodesToGraph(DirectedGraph graph, Map map) {
    
for  ( int  i  =   0 ; i  <  getChildren().size(); i ++ ) {
        NodePart node 
=  (NodePart)getChildren().get(i);
        org.eclipse.draw2d.graph.Node n 
=   new  org.eclipse.draw2d.graph.Node(node);
        n.width 
=  node.getFigure().getPreferredSize().width;
        n.height 
=  node.getFigure().getPreferredSize().height;
        n.setPadding(
new  Insets( 10 , 8 , 10 , 12 ));
        map.put(node, n);
        graph.nodes.add(n);
    }
}

/**
 * 将连接(ConnectionPart)转换为边(Edge)添加到有向图
 * 
@param  graph
 * 
@param  map
 
*/
public   void  contributeEdgesToGraph(DirectedGraph graph, Map map) {
    
for  ( int  i  =   0 ; i  <  getChildren().size(); i ++ ) {
        NodePart node 
=  (NodePart)children.get(i);
        List outgoing 
=  node.getSourceConnections();
        
for  ( int  j  =   0 ; j  <  outgoing.size(); j ++ ) {
            ConnectionPart conn 
=  (ConnectionPart)outgoing.get(j);
            Node source 
=  (Node)map.get(conn.getSource());
            Node target 
=  (Node)map.get(conn.getTarget());
            Edge e 
=   new  Edge(conn, source, target);
            e.weight 
=   2 ;
            graph.edges.add(e);
            map.put(conn, e);
        }
    }
}

要实现步骤2,在DiagramPart里添加下面这个方法:

/**
 * 利用布局后的有向图里节点的位置信息重新定位画布上的图元
 * 
@param  graph
 * 
@param  map
 
*/
protected   void  applyGraphResults(DirectedGraph graph, Map map) {
    
for  ( int  i  =   0 ; i  <  getChildren().size(); i ++ ) {
        NodePart node 
=  (NodePart)getChildren().get(i);
        Node n 
=  (Node)map.get(node);
        node.getFigure().setBounds(
new  Rectangle(n.x, n.y, n.width, n.height));
    }
}

为了以最少的代码说明问题,上面的方法里只是简单的移动了图形,而没有改变模型里Node的属性值,在大多情况下这里使用一个CompoundCommand对模型进行修改更为合适,这样用户不仅可以撤消(Undo)这个自动布局操作,还可以在重新打开文件时看到关闭前的样子。注意,DirectedGraphLayout是不保证每次布局都得到完全相同的结果的。

因为Draw2D里是用LayoutManager管理布局的,而DirectedGraphLayout只是对布局算法的一个包装,所以我们还要创建一个布局类。GraphLayoutManager调用我们在上面已经添加的那几个方法生成有向图(partsToNodes变量维护了编辑器图元到有向图图元的映射),利用DirectedGraphLayout对这个有向图布局,再把结果应用到编辑器里图元。如下所示:

class  GraphLayoutManager  extends  AbstractLayout {

    
private  DiagramPart diagram;

    GraphLayoutManager(DiagramPart 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);
    }

}

当用户按下自动布局按钮时,只要设置DiagramPart对应的图形的布局管理器为GraphLayoutManager就可以实现自动布局了,布局的结果如图所示。


自动布局的结果

点此下载工程,此工程修改自GEF应用实例中的GefPractice,目标文件的扩展名改为.gefpracticeal。最后有几点需要说明:

1、DirectedGraphLayout只能对连通的有向图进行布局,否则会产生异常“graph is not fully connected”,参考Eclipse.org文章Building a Database Schema Diagram Editor中使用的NodeJoiningDirectedGraphLayout可以解决这个问题;

2、如果要对具有嵌套关系的有向图自动布局,应使用SubGraph和CompoundDirectedGraphLayout;

3、这个版本的gefpractice在自动布局后,没有对连接线进行处理,所以可能会出现连接线穿过图元的情况,这个问题和上一个问题都可以参考GEF提供的flow例子解决。

Update(2007/4/9):如果diagram是放在ScrollPane里的,则要修改一下applyGraphResults()方法,增加container作为参数以使整个diagram能正确滚动。

protected   void  applyGraphResults(DirectedGraph graph, Map map, IFigure container) {
    
for  (Iterator iterator  =   this .nodeParts.iterator(); iterator.hasNext();) {
        NodePart element 
=  (NodePart) iterator.next();
        Node n 
=  (Node) map.get(element);
        Rectangle containerBounds
= container.getBounds();
        Rectangle elementBounds
= new  Rectangle(n.x, n.y, n.width, n.height);
        element.getFigure().setBounds(elementBounds.translate(containerBounds.getLocation()));
    }
}
本文转自博客园八进制的博客,原文链接:GEF常见问题5:自动布局,如需转载请自行联系原博主。


相关文章
|
测试技术
解决duilib使用zip换肤卡顿的问题(附将资源集成到程序中的操作方法)
转载请说明原出处,谢谢~~        今天在做单子是,客户要求做换肤功能,为此我专门写了一个换肤函数,并且把各种皮肤资源压缩为各个zip文件来换肤。
1098 0
|
Java 开发工具 图形学
Unity使用心得 之 ✨ Unity2019打包apk显示版本过低问题
Unity2019打包apk显示版本过低问题 可能不止2019有问题,正常用unity打包windows是没问题的,选择打包安卓就会出现下图所示类似问题 明明安装了JDK\SDK,而且我用unty2017、unity2018都用这个SDK打包安卓没出问题,19就出问题,就很头痛。 按照图片上这两个说明看,是指sdk版本不对,或者路径不对没检测到SDK(但是我17、18就能检测到,明显不是SDK路径等问题) 在网上搜了挺多这类问题,解决办法挺多,各不相同,但是也没有一个好好的解决方案,下面说说我的解决办法提供大家试试吧,要不然写完了打包不出来就很难受。
Unity使用心得 之 ✨ Unity2019打包apk显示版本过低问题
|
前端开发 容器
GEF入门实例_总结_06_为编辑器添加内容
一、前言 本文承接上一节:GEF入门实例_总结_05_显示一个空白编辑器 在上一节我们为我们的插件添加了一个空白的编辑器,这一节我们将为此编辑器添加内容。   二、GEF的MVC模式 在此只简单总结一下,后面会详细介绍。
1458 0
|
Android开发
Eclipse插件开发_学习_02_GEF入门实例
一、前言 这一节,我们将会创建一个GEF入门实例     二、新建RCP项目 1. New 一个 Plug-in Project     2.输入项目名 项目名:com.ray.gef.
1817 0
|
Android开发
第二十六章:自定义布局(十三)
Layout和LayoutToVisualElement定义了一组转换属性。这些是AnchorX,AnchorY,Rotation,RotationX,RotationY,Scale,TranslationX和TranslationY,它们根本不影响布局。
768 0
|
设计模式
QtQuickcontrols2控件使用参考
随着Qt的版本升级,其自带的controls控件库也不断升级,目前已经到了2.3的版本。本文通过解读Qt自带的gallery例程,说明新版本controls控件库的相关特性。其具体位置于: 因为相关的中文资料比较缺乏,所以这里的内容会详细整理,某种意义上可以当作使用手册来使用。
1113 0
|
编解码 测试技术 iOS开发
|
Shell Android开发
GEF常见问题6:使用对话框
除了利用Eclipse提供的属性视图以外,GEF应用程序里当然也可以通过弹出对话框修改模型信息。 要实现双击一个节点打开对话框,在NodePart里要增加的代码如下: public void performRequest(Request req) {     if(req.
1246 0
[GEF]实现模板功能
最近遇到一个需求是要在GEF应用里实现“模板”的功能,也就是像word那样在新建一个文件的时候,用户可以选择一个模板,然后以这个模板为基础进行编辑,而不用每次都从头开始。同时,用户要能够创建新模板和对模板进行编辑,在模板里可以指定一些对模型的限制,例如树的最大高度、子节点数目的限制,等等。
951 0