私は、いくつかの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はアイテムの種類ごとに異なる色を持っている)、また2つの頂点間のエッジにいくつかの書き込みをしたい. それに加えて、頂点が自分のプロジェクトで作成したいくつかのオブジェクトであることを非常に望んでいるので、頂点をクリックすると、頂点に配置されたオブジェクトのインスタンスを取得します。
これまでのところ、描画アルゴリズムにあまり手を加えずにグラフを簡単に描画するために、2 つのフレームワークを試しました。
最初に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 );
}
}
このフレームワークは、Rectangles 内の頂点名とエッジの名前を使用してグラフを作成する際にうまく機能し、MouseListener を使用して頂点をクリックすると、頂点内にある文字列を取得できます。
しかし、 TreeLayout を持たせ、 Vertex をクリックすると返される可能性のあるオブジェクトとして頂点を追加する方法を見つけることができませんでした。この例にある汎用クラスを利用しようとしましたが、実行しようとすると例外しか発生しませんでした。インターネットで検索しましたが、このグラフにツリーレイアウトを適用する方法が見つかりませんでした
グラフを描画するためのより多くのオプションがある 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 ではいくつかの円しか得られず、頂点の名前が頂点形状の外にあります。頂点の形状が変化する例を発見しましたが、書き込みはまだ外側です。
したがって、これら 2 つのフレームワークで得られるものの間にあるグラフを描画する方法について、いくつかの提案をお願いします。形状内に頂点の名前を持ち、Treelayout を持ち、取得できるオブジェクトとして頂点を追加します。頂点をクリックすると返されます。
Marco13 からの回答は非常に役に立ちました。Rectangle の幅に String.length * 10 を設定することで、Rectangle を String に合うサイズにすることを考えました。
これは、このようなグラフを作成しようとしている他の人にとって役立つかもしれないと思います: この例のほとんどの一般的なクラスに表示される代わりに、必要なオブジェクトは何でも使用できます。文字列は頂点用で、整数はエッジ型用です。Transformer 関数内で、頂点またはエッジに割り当てられたオブジェクトを取得します。このように、特定のプロパティを持つオブジェクトにさまざまな形状、色、およびフォントを設定できます。
クリックすると Edge オブジェクトを返す MouseListener を作成する方法を理解しようとしていますが、それが簡単になることを願っています。