3

我正在开发一个 Java 应用程序,并且正在使用 JUNG 库。在我的应用程序中,我首先创建一个DelegateTree并将其绘制到屏幕上:

public static GraphZoomScrollPane generateTree(Tree tree,
    GraphicalUserInterface gui) {

    /* Create a new tree */
    edu.uci.ics.jung.graph.Tree<Node, Edge> graphTree = new DelegateTree<Node, Edge>();

    /* Add all nodes and vertices to the tree */
    graphTree.addVertex(tree.getRoot());
    addChildren(tree.getRoot(), graphTree);

    /* Create the visualization */
    TreeLayout<Node, Edge> treeLayout = new TreeLayout<Node, Edge>(graphTree);
    VisualizationViewer<Node, Edge> vv = new VisualizationViewer<Node, Edge>(treeLayout);
    vv.setBackground(Color.WHITE);
    vv.getRenderContext().setEdgeLabelTransformer(new ToStringLabeller<Edge>());
    vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line<Node, Edge>());
    vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller<Node>());
    vv.getRenderer().getVertexLabelRenderer().setPosition(Renderer.VertexLabel.Position.S);

    vv.addGraphMouseListener(new ClickNode(gui, vv));
    final DefaultModalGraphMouse<Node, Edge> graphMouse = new DefaultModalGraphMouse<Node, Edge>();
    graphMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);
    vv.setGraphMouse(graphMouse);

    return new GraphZoomScrollPane(vv);
}

之后,用户可以将新的孩子添加到我的树的叶子上。但是当我这样做的时候

graphTree.addEdge(edge, parent, child);

然后重新绘制VisualizationViewer,可视化失去了“树”结构。它只是在父级上方的某个位置添加子级,并将该新子级的所有其他子级添加到它之上。

有没有更好的方法来动态地将孩子添加到我的树的叶子上?还是我必须使用其他东西来重绘而不是仅仅vv.repaint()

任何帮助将不胜感激。

发生的事情的一个例子:

http://www.dylankiss.be/JUNGExample.PNG

从根 (OUTLOOK) 开始,添加 3 个具有不同边缘(晴天、阴天、雨天)的子节点(叶子、叶子、叶子)后,它们只是彼此重叠。

编辑:这是addChildren()方法。

private static void addChildren(Node node, edu.uci.ics.jung.graph.Tree<Node, Edge> tree) {
    for (int i = 0; i < node.getChildren().size(); i++) {
        tree.addEdge(new Edge(node.getChildren().get(i).getParentValue()), node, node.getChildren().get(i));
        addChildren(node.getChildren().get(i), tree);
    }
}

编辑 2:这是 AWT ActionListener 的一部分,我在其中将新子级添加到树中。

while (there are still edges to be added) {
    value = name of new edge;
    child = new Node(this.m_node, value);
    this.m_node.addChild(child);
    graphTree.addEdge(new Edge(value), this.m_node, child);
}
4

1 回答 1

3

在这里发布负责添加新边的方法会有所帮助:)

但乍一看,您似乎在相同的两个节点(OUTLOOK 和 Leaf)之间添加了 3 个不同的边。我猜你正在这样做(或 Node 和 Edge 实例的等价物):

graphTree.addChild("sunny", "OUTLOOK", "Leaf");
graphTree.addChild("overcast", "OUTLOOK", "Leaf");
graphTree.addChild("rainy", "OUTLOOK", "Leaf");

在这种情况下,由于 JUNG 图保持节点的唯一性,您最终只有两个节点,并且它们之间有 3 条不同的边。当 JUNG 尝试显示此图时,您将获得两个节点和 3 个重叠边,就像您使用 EdgeShape.Line 一样。

如果您最初的目标确实是在两个节点之间设置 3 条不同的边缘,请尝试使用不同的边缘形状以避免重叠并获得更好的渲染效果,例如 EdgeShape.BentLine 等。

如果您想要 3 个不同的节点,则必须使用 3 个不同的名称,或 3 个不同的 Node 实例,它们不等于

祝你好运 :)

编辑

根据您的评论,我查看了 TreeLayout 源代码,并且有一个小问题导致无法动态更新布局。

要解决此问题,请改用此类:

import edu.uci.ics.jung.algorithms.layout.TreeLayout;
import java.awt.Point;
import java.util.Collection;

import edu.uci.ics.jung.graph.Forest;
import edu.uci.ics.jung.graph.util.TreeUtils;

public class DynamicTreeLayout<V, E>
    extends TreeLayout<V, E>
{
public DynamicTreeLayout(Forest<V, E> g) {
    this(g, DEFAULT_DISTX, DEFAULT_DISTY);
}

public DynamicTreeLayout(Forest<V, E> g, int distx) {
    this(g, distx, DEFAULT_DISTY);
}

public DynamicTreeLayout(Forest<V, E> g, int distx, int disty) {
    super(g, distx, disty);
}

protected void buildTree() {
    alreadyDone.clear(); // This was missing and prevented the layout to update positions

    this.m_currentPoint = new Point(20, 20);
    Collection<V> roots = TreeUtils.getRoots(graph);
    if (roots.size() > 0 && graph != null) {
        calculateDimensionX(roots);
        for (V v : roots) {
            calculateDimensionX(v);
            m_currentPoint.x += this.basePositions.get(v) / 2 + this.distX;
            buildTree(v, this.m_currentPoint.x);
        }
    }
}

private int calculateDimensionX(V v) {
    int localSize = 0;
    int childrenNum = graph.getSuccessors(v).size();

    if (childrenNum != 0) {
        for (V element : graph.getSuccessors(v)) {
            localSize += calculateDimensionX(element) + distX;
        }
    }
    localSize = Math.max(0, localSize - distX);
    basePositions.put(v, localSize);

    return localSize;
}

private int calculateDimensionX(Collection<V> roots) {
    int localSize = 0;
    for (V v : roots) {
        int childrenNum = graph.getSuccessors(v).size();

        if (childrenNum != 0) {
            for (V element : graph.getSuccessors(v)) {
                localSize += calculateDimensionX(element) + distX;
            }
        }
        localSize = Math.max(0, localSize - distX);
        basePositions.put(v, localSize);
    }

    return localSize;
}
}

如果您希望更新布局并为图形的每次修改重新绘制查看器,您还需要添加以下内容:

layout.setGraph(g);
vv.repaint();
于 2012-04-06T10:05:49.587 回答