java - 如何在 Java 中制作 Treelayout 图

标签 java layout graph jung jgrapht

我正在开发一个程序,该程序读取一些 xml 文件并根据这些 xml 文件中的信息创建图表。

我在制作图表时遇到了困难。我希望我的图表看起来: http://pic.dhe.ibm.com/infocenter/elixent/v3r5/topic/com.ibm.ilog.elixir.doc/Content/Visualization/Documentation/Flex/Diagram4Flex/_media/TreeLayoutExample_default.png

所以,我希望它有一个树状布局,顶点的名称在一些彩色矩形内(pref 对不同种类的项目有不同的颜色),我还想在两个顶点之间的边缘上写一些东西。最重要的是,我非常希望顶点是我在我的项目中创建的一些对象,因此当我单击一个顶点以获取放置在顶点上的对象的实例时。

到目前为止,我尝试了两个框架来轻松绘制我的图形,而无需在绘制算法上做太多工作:

起初我尝试了 jgraph 框架:

    package mainPack;

    import java.awt.Color;
    import java.awt.Dimension;
    import java.awt.Rectangle;
    import java.util.ArrayList;
    import java.util.HashMap;
    import java.util.Map;

    import javax.swing.JApplet;
    import javax.swing.JFrame;

    import org.jgraph.JGraph;
    import org.jgraph.graph.DefaultGraphCell;
    import org.jgraph.graph.GraphConstants;
    import org.jgrapht.ListenableGraph;
    import org.jgrapht.ext.JGraphModelAdapter;
    import org.jgrapht.graph.ListenableDirectedGraph;
    import org.jgrapht.graph.DefaultEdge;
    import org.jgrapht.graph.ListenableDirectedWeightedGraph;

    /**
     * A demo applet that shows how to use JGraph to visualize JGraphT graphs.
     *
     * @author Barak Naveh
     *
     * @since Aug 3, 2003
     */
    public class Test extends JApplet {
  private static final Color     DEFAULT_BG_COLOR = Color.decode( "#FAFBFF" );
            private static final Dimension DEFAULT_SIZE = new Dimension( 530, 320 );

    // 
    private JGraphModelAdapter m_jgAdapter;

    /**
     * @see java.applet.Applet#init().
     */
    public void init(  ) {
        // create a JGraphT graph
        ListenableGraph g = new ListenableDirectedGraph( DefaultEdge.class );

        // create a visualization using JGraph, via an adapter
        m_jgAdapter = new JGraphModelAdapter( g );

        JGraph jgraph = new JGraph( m_jgAdapter );

        adjustDisplaySettings( jgraph );
        getContentPane(  ).add( jgraph );
        resize( DEFAULT_SIZE );

        // add some sample data (graph manipulated via JGraphT)
        g.addVertex( "v1" );
        g.addVertex( "v2" );
        g.addVertex( "v3" );
        g.addVertex( "v4" );

        g.addEdge( "v1", "v2", "1" );
        g.addEdge( "v2", "v3", "2" );
        g.addEdge( "v3", "v1", "3" );
        g.addEdge( "v4", "v3", "4" );

        // position vertices nicely within JGraph component
        positionVertexAt( "v1", 130, 40 );
        positionVertexAt( "v2", 60, 200 );
        positionVertexAt( "v3", 310, 230 );
        positionVertexAt( "v4", 380, 70 );

        // that's all there is to it!...
    }


    private void adjustDisplaySettings( JGraph jg ) {
        jg.setPreferredSize( DEFAULT_SIZE );

        Color  c        = DEFAULT_BG_COLOR;
        String colorStr = null;

        try {
            colorStr = getParameter( "bgcolor" );
        }
         catch( Exception e ) {}

        if( colorStr != null ) {
            c = Color.decode( colorStr );
        }

        jg.setBackground( c );
    }


    private void positionVertexAt( Object vertex, int x, int y ) {
        DefaultGraphCell cell = m_jgAdapter.getVertexCell( vertex );

        Map             attr = cell.getAttributes();
   //      Rectangle       b    =  new Rectangle((int)(Math.random()*1000),(int)(Math.random()*500),100,30);

        Rectangle       b    =  new Rectangle(20,50 ,100,30);



       GraphConstants.setBounds( attr, b );

         Map cellAttr = new HashMap(  );
         cellAttr.put( cell, attr );

         m_jgAdapter.edit( cellAttr, null, null, null );
    }

这个框架在制作图形时效果很好,矩形内有顶点名称,边上有名称,并且可以在使用 MouseListener 单击顶点时获取顶点内的字符串。

但我无法找到一种方法使其具有 TreeLayout 并添加顶点作为某些对象,当单击 Vertex 时我可能会返回这些对象。我尝试使用此示例中的通用类,但在尝试运行它时仅出现异常。我在 Internet 上搜索但找不到在此图上应用树布局的方法

我也尝试过 Java JUNG Framework,它有更多的绘图选项。我找到了这个例子:

    @SuppressWarnings("serial")
    public class TreeLayoutDemo extends JApplet {

/**
 * the graph
 */
Forest<String,Integer> graph;

Factory<DirectedGraph<String,Integer>> graphFactory = 
    new Factory<DirectedGraph<String,Integer>>() {

        public DirectedGraph<String, Integer> create() {
            return new DirectedSparseMultigraph<String,Integer>();
        }
    };

Factory<Tree<String,Integer>> treeFactory =
    new Factory<Tree<String,Integer>> () {

    public Tree<String, Integer> create() {
        return new DelegateTree<String,Integer>(graphFactory);
    }
};

Factory<Integer> edgeFactory = new Factory<Integer>() {
    int i=0;
    public Integer create() {
        return i++;
    }};

Factory<String> vertexFactory = new Factory<String>() {
    int i=0;
    public String create() {
        return "V"+i++;
    }};

/**
 * the visual component and renderer for the graph
 */
VisualizationViewer<String,Integer> vv;

VisualizationServer.Paintable rings;

String root;

TreeLayout<String,Integer> treeLayout;

RadialTreeLayout<String,Integer> radialLayout;

public TreeLayoutDemo() {

    // create a simple graph for the demo
    graph = new DelegateForest<String,Integer>();





    createTree();

    treeLayout = new TreeLayout<String,Integer>(graph);
    radialLayout = new RadialTreeLayout<String,Integer>(graph);
    radialLayout.setSize(new Dimension(600,600));
    vv =  new VisualizationViewer<String,Integer>(treeLayout, new Dimension(600,600));
    vv.setBackground(Color.white);
   vv.getRenderContext().setEdgeShapeTransformer(new EdgeShape.Line());
    vv.getRenderContext().setVertexLabelTransformer(new ToStringLabeller());
   // vv.getRenderContext().setVertexShapeTransformer(arg0);
    // add a listener for ToolTips
    vv.setVertexToolTipTransformer(new ToStringLabeller());
    vv.getRenderContext().setArrowFillPaintTransformer(new ConstantTransformer(Color.lightGray));
    rings = new Rings();

    Container content = getContentPane();
    final GraphZoomScrollPane panel = new GraphZoomScrollPane(vv);
    content.add(panel);

    final DefaultModalGraphMouse graphMouse = new DefaultModalGraphMouse();

    vv.setGraphMouse(graphMouse);

    JComboBox modeBox = graphMouse.getModeComboBox();
    modeBox.addItemListener(graphMouse.getModeListener());
    graphMouse.setMode(ModalGraphMouse.Mode.TRANSFORMING);

    final ScalingControl scaler = new CrossoverScalingControl();

    JButton plus = new JButton("+");
    plus.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            scaler.scale(vv, 1.1f, vv.getCenter());
        }
    });
    JButton minus = new JButton("-");
    minus.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            scaler.scale(vv, 1/1.1f, vv.getCenter());
        }
    });

    JToggleButton radial = new JToggleButton("Radial");
    radial.addItemListener(new ItemListener() {

        public void itemStateChanged(ItemEvent e) {
            if(e.getStateChange() == ItemEvent.SELECTED) {

                LayoutTransition<String,Integer> lt =
                    new LayoutTransition<String,Integer>(vv, treeLayout, radialLayout);
                Animator animator = new Animator(lt);
                animator.start();
                vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
                vv.addPreRenderPaintable(rings);
            } else {
                LayoutTransition<String,Integer> lt =
                    new LayoutTransition<String,Integer>(vv, radialLayout, treeLayout);
                Animator animator = new Animator(lt);
                animator.start();
                vv.getRenderContext().getMultiLayerTransformer().setToIdentity();
                vv.removePreRenderPaintable(rings);
            }
            vv.repaint();
        }});

    JPanel scaleGrid = new JPanel(new GridLayout(1,0));
    scaleGrid.setBorder(BorderFactory.createTitledBorder("Zoom"));

    JPanel controls = new JPanel();
    scaleGrid.add(plus);
    scaleGrid.add(minus);
    controls.add(radial);
    controls.add(scaleGrid);
    controls.add(modeBox);

    content.add(controls, BorderLayout.SOUTH);
}

class Rings implements VisualizationServer.Paintable {

    Collection<Double> depths;

    public Rings() {
        depths = getDepths();
    }

    private Collection<Double> getDepths() {
        Set<Double> depths = new HashSet<Double>();
        Map<String,PolarPoint> polarLocations = radialLayout.getPolarLocations();
        for(String v : graph.getVertices()) {
            PolarPoint pp = polarLocations.get(v);
            depths.add(pp.getRadius());
        }
        return depths;
    }

    public void paint(Graphics g) {
        g.setColor(Color.lightGray);

        Graphics2D g2d = (Graphics2D)g;
        Point2D center = radialLayout.getCenter();

        Rectangle2D rectangle = new Rectangle2D.Double();   // (center.getX()-10, center.getY()-20, 20, 40);

        Ellipse2D ellipse = new Ellipse2D.Double();
        for(double d : depths) {


            ellipse.setFrameFromDiagonal(center.getX()-d, center.getY()-d, 
                    center.getX()+d, center.getY()+d);

            rectangle.setFrameFromDiagonal(center.getX()-d, center.getY()-d, 
                    center.getX()+d, center.getY()+d);

            Shape shape = vv.getRenderContext().getMultiLayerTransformer().getTransformer(Layer.LAYOUT).transform(rectangle);
            g2d.draw(shape);
        }
    }

    public boolean useTransform() {
        return true;
    }
}

/**
 * 
 */
private void createTree() {
    graph.addVertex("V0");
    graph.addEdge(edgeFactory.create(), "V0", "V1"); 
    graph.addEdge(edgeFactory.create(), "V0", "V2");
    graph.addEdge(edgeFactory.create(), "V1", "V4");
    graph.addEdge(edgeFactory.create(), "V2", "V3");
    graph.addEdge(edgeFactory.create(), "V2", "V5");
    graph.addEdge(edgeFactory.create(), "V4", "V6");
    graph.addEdge(edgeFactory.create(), "V4", "V7");
    graph.addEdge(edgeFactory.create(), "V3", "V8");
    graph.addEdge(edgeFactory.create(), "V6", "V9");
    graph.addEdge(edgeFactory.create(), "V4", "V10");

    graph.addVertex("A0");
    graph.addEdge(edgeFactory.create(), "A0", "A1");
    graph.addEdge(edgeFactory.create(), "A0", "A2");
    graph.addEdge(edgeFactory.create(), "A0", "A3");

    graph.addVertex("B0");
    graph.addEdge(edgeFactory.create(), "B0", "B1");
    graph.addEdge(edgeFactory.create(), "B0", "B2");
    graph.addEdge(edgeFactory.create(), "B1", "B4");
    graph.addEdge(edgeFactory.create(), "B2", "B3");
    graph.addEdge(edgeFactory.create(), "B2", "B5");
    graph.addEdge(edgeFactory.create(), "B4", "B6");
    graph.addEdge(edgeFactory.create(), "B4", "B7");
    graph.addEdge(edgeFactory.create(), "B3", "B8");
    graph.addEdge(edgeFactory.create(), "B6", "B9");




}


/**
 * a driver for this demo
 */
public static void main(String[] args) {
    JFrame frame = new JFrame();
    Container content = frame.getContentPane();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    content.add(new TreeLayoutDemo());
    frame.pack();
    frame.setVisible(true);
}

使用此框架,我可以将顶点添加为我创建的一些对象,并在顶点名称上显示该对象在 toString() 方法中返回的内容。它还具有我非常想要的 TreeLayout 算法,实现了但我无法设法改变顶点的外观。我希望它们看起来像 JGraph 框架绘制的顶点,但是使用 JUNG 我只得到一些圆圈并且顶点名称在顶点形状之外。我发现了一个改变顶点形状的例子,但文字仍然在外面。

所以,我非常想要一些关于如何绘制介于这两个框架之间的图形的建议:在形状中具有顶点名称,具有 Treelayout 并添加顶点作为一些对象我可以在点击顶点时返回。

Marco13 的回答非常有用。我想通过为矩形的宽度设置 String.length * 10 来使矩形的大小适合他的字符串。

我认为这可能对尝试制作如下图的其他人有用:在本示例中,可以使用任何需要的对象,而不是出现在大多数通用类中的那个,字符串用于顶点,整数用于边类型。在 Transformer 函数中,您可以获得分配给顶点或边的对象。像这样,我可以为具有某些特定属性的对象设置不同的形状、颜色和字体。

我正在研究如何制作一个 MouseListener,当我点击它时它会返回边缘对象,但我希望这会很容易。

最佳答案

您可以像这样在第二个示例中配置 VisualizationViewer:

    vv.getRenderContext().setVertexShapeTransformer(new Transformer<String, Shape>()
    {
        @Override
        public Shape transform(String vertex)
        {
            return new Rectangle2D.Double(-10,-10,40,20);
        }
    });

    BasicVertexLabelRenderer<String, Integer> vertexLabelRenderer = 
        new BasicVertexLabelRenderer<String, Integer>();
    vertexLabelRenderer.setPosition( Renderer.VertexLabel.Position.CNTR);
    vv.getRenderer().setVertexLabelRenderer(vertexLabelRenderer);

这会将顶点渲染为矩形,并将标签放在中心。扩展(如调整内容的矩形大小)可能有点繁琐,但应该是可行的。

关于java - 如何在 Java 中制作 Treelayout 图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22809489/

相关文章:

javascript - 如何将文本与居中文本的左侧对齐?

jquery - Highcharts - 如何减少类别之间的空间?

c# - floyd warshall 上的并行 linq

c++ - 在 QCustomPlot 中,如何实时为相同数据绘制折线图和条形图?

java - 使用 Spring MVC 管理 REST 响应

java - JUnit 测试中的注释数量不正确

Java多次调用构造函数

java - 类未返回预期的输出

css - 为什么我的 div 太宽了?

java - 如何删除edittext字段的边框