【问题标题】:How to create a hierarchical tree with collapsible nodes in JGraphX如何在 JGraphX 中创建具有可折叠节点的分层树
【发布时间】:2017-12-25 21:38:50
【问题描述】:

我需要一个组织结构图树,并且我希望能够在任何级别折叠和展开节点。我是 JGraphX 的新手,但从我读到的内容看来,实现折叠的方法是对顶点进行分组。问题是当我创建组时,它会将所有子顶点放在父顶点内。

下面是一些示例代码,提供了很好的布局但不支持折叠:

package com.mxgraph.examples.swing;

import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.SwingConstants;

import com.mxgraph.layout.mxCompactTreeLayout;
import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxPoint;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.view.mxGraph;
import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
public class HelloWorld extends JFrame
{

    /**
     * 
     */
    private static final long serialVersionUID = -2707712944901661771L;

    public HelloWorld()
    {
        super("Hello, puppies!");

        mxGraph graph = new mxGraph();
        Object parent = graph.getDefaultParent();

        graph.getModel().beginUpdate();
        try
        {
            //Notice that the parent is the default parent... 
            //The hierarchical structure looks great but I cannot collapse/expand the tree.
            Object vDogsRoot = graph.insertVertex(parent, null, "DOG", 0, 0, 80, 30);
            Object v2 = graph.insertVertex(parent, null, "Shar Pei", 0, 0, 80, 30);
            Object v3 = graph.insertVertex(parent, null, "Pug", 0, 0, 80, 30);
            Object v4 = graph.insertVertex(parent, null, "Cocker Spaniel", 0, 0, 80, 30);
            Object v5 = graph.insertVertex(parent, null, "Pit Bull", 0, 0, 80, 30);
            Object v6 = graph.insertVertex(parent, null, "Chihuahua", 0, 0, 80, 30);

            graph.insertEdge(parent, null, "", vDogsRoot, v2);
            graph.insertEdge(parent, null, "", vDogsRoot, v3);
            graph.insertEdge(parent, null, "", vDogsRoot, v4);
            graph.insertEdge(parent, null, "", vDogsRoot, v5);
            graph.insertEdge(parent, null, "", vDogsRoot, v6);

            mxHierarchicalLayout layout = new mxHierarchicalLayout(graph);
            layout.setUseBoundingBox(false);

            layout.execute(parent);
        }
        finally
        {
            graph.getModel().endUpdate();
        }

        mxGraphComponent graphComponent = new mxGraphComponent(graph);
        getContentPane().add(graphComponent);
    }

    public static void main(String[] args)
    {
        HelloWorld frame = new HelloWorld();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 320);
        frame.setVisible(true);
    }

}

生产:

很好的开始,但没有折叠按钮。以下代码演示了我遇到的问题。为了支持折叠,我尝试通过将顶点的父级从默认父级更改为树的根 vDogVertex 来创建一个组。这变得可折叠,但是所有子顶点都在 vDogVertex 内部,这会破坏树的布局。

package com.mxgraph.examples.swing;

import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.SwingConstants;

import com.mxgraph.layout.mxCompactTreeLayout;
import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
import com.mxgraph.model.mxGeometry;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxPoint;
import com.mxgraph.util.mxRectangle;
import com.mxgraph.view.mxGraph;
import com.mxgraph.layout.hierarchical.mxHierarchicalLayout;
public class HelloWorld extends JFrame
{

    /**
     * 
     */
    private static final long serialVersionUID = -2707712944901661771L;

    public HelloWorld()
    {
        super("Hello, puppies!");

        mxGraph graph = new mxGraph();
        Object parent = graph.getDefaultParent();

        graph.getModel().beginUpdate();
        try
        {
            //Notice this time the parent is the vDogsRoot vertex. 
            //This creates a cell group if I understand correctly.
            Object vDogsRoot = graph.insertVertex(parent, null, "DOG", 0, 0, 80, 30, "");
            Object v2 = graph.insertVertex(vDogsRoot, null, "Shar Pei", 0, 0, 80, 30, "");
            Object v3 = graph.insertVertex(vDogsRoot, null, "Pug", 0, 0, 80, 30, "");
            Object v4 = graph.insertVertex(vDogsRoot, null, "Cocker Spaniel", 0, 0, 80, 30, "");
            Object v5 = graph.insertVertex(vDogsRoot, null, "Pit Bull", 0, 0, 80, 30, "");
            Object v6 = graph.insertVertex(vDogsRoot, null, "Chihuahua", 0, 0, 80, 30, "");

            graph.insertEdge(parent, null, "", vDogsRoot, v2);
            graph.insertEdge(parent, null, "", vDogsRoot, v3);
            graph.insertEdge(parent, null, "", vDogsRoot, v4);
            graph.insertEdge(parent, null, "", vDogsRoot, v5);
            graph.insertEdge(parent, null, "", vDogsRoot, v6);

            mxHierarchicalLayout layout = new mxHierarchicalLayout(graph);
            layout.setUseBoundingBox(false);

            layout.execute(vDogsRoot);  //apply the layout to the root group node.
            layout.execute(parent);
        }
        finally
        {
            graph.getModel().endUpdate();
        }

        mxGraphComponent graphComponent = new mxGraphComponent(graph);
        getContentPane().add(graphComponent);
    }

    public static void main(String[] args)
    {
        HelloWorld frame = new HelloWorld();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(400, 320);
        frame.setVisible(true);
    }

}

产生: (注意折叠按钮)

如何防止顶点位于单元组的父单元内?我希望树层次结构得到维护但可折叠。我是否在使用 Cell Groups 的正确路径上?我做错了什么?

我怀疑我只需要告诉单元组的父级 (vDogsRoot) 允许将单元格绘制到其边界之外,但我还没有看到这样做的方法。或者,也许我采取了完全错误的方法。认为这应该是一件微不足道的事情,但我尝试了许多不同的事情,并在谷歌上搜索/阅读了许多文档,但还没有成功。

更新 1:

组不是我在这里需要的。我只需要遍历有向树并切换显示所选节点下方的节点。在 mxGraph 示例文件夹中找到一个名为 tree.html 的 java 脚本示例。只需将该示例从 JavaScript 转换为 Java。

【问题讨论】:

    标签: java jgraphx


    【解决方案1】:

    哎呀,不知道我对此有何感受,但这里有一个解决方案。我将 tree.html example 从 JavaScript 部分转换为 Java。我没有将所有代码都转换为 Java;我什至没有尝试,因为我不在乎折叠按钮的位置。我确实得到了我想要的功能。我确实添加了一些超级方法正在执行的代码,以防该部分很重要。

    如果有人想完成转换示例并将其提供给我,我将很乐意为您提供答案,而不是为自己提供答案。获得答案的其他方法 - 指出我的代码中的错误,以某种方式改进它或提供更好的代码方法。

    这是我的 Java 代码:

    package com.mxgraph.examples.swing;
    
    import java.util.ArrayList;
    import java.util.List;
    
    import javax.swing.JFrame;
    
    import com.mxgraph.layout.mxCompactTreeLayout;
    import com.mxgraph.swing.mxGraphComponent;
    import com.mxgraph.util.mxEvent;
    import com.mxgraph.util.mxEventObject;
    import com.mxgraph.util.mxEventSource.mxIEventListener;
    import com.mxgraph.view.mxGraph;
    
    /**
     * A foldable directed acyclic graph (DAG) where each child has only one parent. AKA a Tree.
     * 
     * @author some programmer
     *
     */
    class FoldableTree extends mxGraph
    {
        /**
         * Need to add some conditions that will get us the expand/collapse icon on the vertex.
         */
        @Override
        public boolean isCellFoldable(Object cell, boolean collapse)
        {
            //I want to keep the original behavior for groups in case I use a group someday.
            boolean result = super.isCellFoldable(cell, collapse);
            if(!result)
            {
                //I also want cells with outgoing edges to be foldable...
                return this.getOutgoingEdges(cell).length > 0;
            }
            return result;
        }
    
        /**
         * Need to define how to fold cells for our DAG. In this case we want to traverse the tree collecting
         * all child vertices and then hide/show them and their edges as needed. 
         */
        @Override
        public Object[] foldCells(boolean collapse, boolean recurse, Object[] cells, boolean checkFoldable)
        {
            //super.foldCells does this so I will too...
            if(cells == null)
            {
                cells = getFoldableCells(getSelectionCells(), collapse);
            }
    
            this.getModel().beginUpdate();
    
            try
            {           
                toggleSubtree(this, cells[0], !collapse);
                this.model.setCollapsed(cells[0], collapse);
                fireEvent(new mxEventObject(mxEvent.FOLD_CELLS, "cells", cells, "collapse", collapse, "recurse", recurse));
            }
            finally
            {
                this.getModel().endUpdate();
            }
    
            return cells;
        }
    
        // Updates the visible state of a given subtree taking into
        // account the collapsed state of the traversed branches
        private void toggleSubtree(mxGraph graph, Object cellSelected, boolean show)
        {
            List<Object> cellsAffected = new ArrayList<>();
            graph.traverse(cellSelected, true, new mxICellVisitor() {                   
                        @Override
                        public boolean visit(Object vertex, Object edge) {
                            // We do not want to hide/show the vertex that was clicked by the user to do not
                            // add it to the list of cells affected.
                            if(vertex != cellSelected)
                            {
                                cellsAffected.add(vertex);
                            }
    
                            // Do not stop recursing when vertex is the cell the user clicked. Need to keep
                            // going because this may be an expand.
                            // Do stop recursing when the vertex is already collapsed.
                            return vertex == cellSelected || !graph.isCellCollapsed(vertex); 
                        }
                    });
    
            graph.toggleCells(show, cellsAffected.toArray(), true/*includeEdges*/);     
        }
    }
    
    public class ChampsTree extends JFrame
    {
        private static final long serialVersionUID = -2707712944901661771L;
    
        public ChampsTree()
        {
            super("Hello, World!");
    
            FoldableTree graph = new FoldableTree();
    
            mxCompactTreeLayout layout = new mxCompactTreeLayout(graph, false);         
            layout.setUseBoundingBox(false);
            layout.setEdgeRouting(false);
            layout.setLevelDistance(30);
            layout.setNodeDistance(10);
    
            Object parent = graph.getDefaultParent();
    
            graph.getModel().beginUpdate();
            try
            {           
                Object root = graph.insertVertex(parent, "treeRoot", "Root", 0, 0, 60, 40);
    
                Object v1 = graph.insertVertex(parent, "v1", "Child 1", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", root, v1);
    
                Object v2 = graph.insertVertex(parent, "v2", "Child 2", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", root, v2);
    
                Object v3 = graph.insertVertex(parent, "v3", "Child 3", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", root, v3);
    
                Object v11 = graph.insertVertex(parent, "v11", "Child 1.1", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", v1, v11);
    
                Object v12 = graph.insertVertex(parent, "v12", "Child 1.2", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", v1, v12);
    
                Object v21 = graph.insertVertex(parent, "v21", "Child 2.1", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", v2, v21);
    
                Object v22 = graph.insertVertex(parent, "v22", "Child 2.2", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", v2, v22);
    
                Object v221 = graph.insertVertex(parent, "v221", "Child 2.2.1", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", v22, v221);
    
                Object v222 = graph.insertVertex(parent, "v222", "Child 2.2.2", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", v22, v222);
    
                Object v31 = graph.insertVertex(parent, "v31", "Child 3.1", 0, 0, 60, 40);
                graph.insertEdge(parent, null, "", v3, v31);            
    
                layout.execute(parent);         
            }
            finally
            {
                graph.getModel().endUpdate();
            }
    
            graph.addListener(mxEvent.FOLD_CELLS,  new mxIEventListener() {
    
                @Override
                public void invoke(Object sender, mxEventObject evt) {
                    layout.execute(graph.getDefaultParent());
                }
            });
    
            mxGraphComponent graphComponent = new mxGraphComponent(graph);
    
            getContentPane().add(graphComponent);
        }
    
        public static void main(String[] args)
        {
            ChampsTree frame = new ChampsTree();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400, 320);
            frame.setVisible(true);
        }
    }
    

    请注意,树在折叠时变得更加紧凑(其余节点更靠近在一起)。这是因为在折叠发生后调用布局的处理程序。这降低了树的视觉复杂性,这很好,因为我的真实树会很大。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-01
      • 2023-03-08
      • 1970-01-01
      • 2019-03-02
      相关资源
      最近更新 更多