由于项目中要用到流程图来展示数据之间的链关系,于是决定用开源的jgraph来做,并将图形嵌入到b/s结构的项目中,所以用到了applet来将jgraph流程图显示在网页。由于之前没有接触过jgraph和 applet,不得不边查资料边琢磨着做,做的比较粗糙但也达到了预期效果,现将学习心得和所遇问题总结一下,仅供借鉴。
1. Jgraph简介
Jgraph是一个开源的,兼容Swing的图形组件,具有相当高的交互性和自动化,是一套为图定做的组件。其主要用途是在一些需要表示图结构的应用中,比如流程图、UML、交通线路、网络等等。
Jgraph常用类说明
org.jgraph.graph.GraphModel :默认实现类为DefaultGraphModel,能满足一般需求,一张图(或一个jgraph类)中必不可少的一个成员变量,好比是一个图的画布,先准备好画布,才能在画布上添各种色彩;
org.jgraph.graph.DefaultGraphCell(Vertex):可以携带对象,由于JGraph是只负责表示的,并不真正负责数据的操作。那么在图形和数据间就需要一个使者,这就是Vertex ,Vertex 可以是文字、图形等对象。
org.jgraph.graph.DefaultPort(Port):Port 是一般比较陌生的单位,在图的算法中并不设计Port,但在图形表示中它十分有用。他是Vertex上的一个端口,可以通过端口连接其他Vertex,而在JGraph中Port还可以用于改变Edge的形状等等。
org.jgraph.graph.DefaultEdge(Edge):Edge 是只能连接Port而不是Vertex的。
org.jgraph.graph.GraphConstants:可以对所有单元属性的值进行修改,一个jgraph常用工具类。
一个简单的例子:
package jgraph;
import java.awt.Color;
import java.awt.geom.Rectangle2D;
import java.util.*;
import javax.swing.*;
import org.jgraph.*;
import org.jgraph.graph.*;
public class Demo {
public static void main(String[] args) {
// Construct Model and Graph
GraphModel model = new DefaultGraphModel();
JGraph graph = new JGraph(model);
graph.setSelectionEnabled(true);
// Create Nested Map (from Cells to Attributes)
// 此Map中记录所有属性,其中的键-值对是cell-cellAttribute
// 每个cellAttribute又是一个Map,其键-值对是具体一个cell的属性-值
Map attributes = new Hashtable();
// 以下建立两个顶点(cell)Hello和World,并分别设置他们的属性Map
// Create Hello Vertex
DefaultGraphCell hello = new DefaultGraphCell("北京");
// Create Hello Vertex Attributes
Map helloAttrib = new Hashtable();
attributes.put(hello, helloAttrib);
// Set bounds
Rectangle2D helloBounds = new Rectangle2D.Double(20, 20, 40, 20);
GraphConstants.setBounds(helloAttrib, helloBounds);
// Set black border
GraphConstants.setBorderColor(helloAttrib, Color.black);
// Add a Port
// 每个顶点为了与其他顶点相邻接,必须添加节点(cell)
DefaultPort hp = new DefaultPort();
hello.add(hp);
// Create World Vertex
DefaultGraphCell world = new DefaultGraphCell("石家庄");
// Create World Vertex Attributes
Map worldAttrib = new Hashtable();
attributes.put(world, worldAttrib);
// Set bounds
Rectangle2D worldBounds = new Rectangle2D.Double(140, 140, 40, 20);
GraphConstants.setBounds(worldAttrib , worldBounds);
// Set fill color
GraphConstants.setBackground(worldAttrib, Color.orange);
GraphConstants.setOpaque(worldAttrib, true);
// Set raised border
GraphConstants.setBorder(worldAttrib,
BorderFactory.createRaisedBevelBorder());
// Add a Port
DefaultPort wp = new DefaultPort();
world.add(wp);
// 建立联接两个顶点的边
// Create Edge
DefaultEdge edge = new DefaultEdge();
// Create Edge Attributes
Map edgeAttrib = new Hashtable();
attributes.put(edge, edgeAttrib);
// Set Arrow
int arrow = GraphConstants.ARROW_CLASSIC;
GraphConstants.setLineEnd(edgeAttrib , arrow);
GraphConstants.setEndFill(edgeAttrib, true);
// Connect Edge
// 边的两个端点就是两个顶点的child节点(port)
ConnectionSet cs = new ConnectionSet(edge, hp, wp);
Object[] cells = new Object[]{edge, hello, world};
// Insert into Model
// model构件完成
model.insert(cells, attributes, cs, null, null);
// Show in Frame
JFrame frame = new JFrame();
frame.getContentPane().add(new JScrollPane(graph));
//frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
}
}
2. 关于页面自动布局的问题
jgraph图里的单元通过赋予相应的坐标来达到布局的布局的效果,但当单元节点多并加上各种关联之后,手动布局就会相当繁琐,这时候就需要通过一定算法的自动布局来达到效果。
下面是网上一段自动布局结合项目后修改的例子:
package test;
public class TestGraph extends Applet implements MouseListener{
public Map gefNodeMap = null;
public Map graphNodeMap = null;
public List edgeList = null;
DirectedGraph directedGraph = null;
JGraph graph = null;
URLConnection connect;
List tempList;
public TestGraph() {
}
public void init() {
String hh = this.getParameter("hh", "04020200");
String khdm = this.getParameter("khdm", "040290000001697");
List edgeBeanList = this.send(hh, khdm, null);
tempList = edgeBeanList;
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
e.printStackTrace();
}
graphInit();
paintGraph(edgeBeanList);
}
public String getParameter(String key, String def) {
return getParameter(key) != null ? getParameter(key) : def;
}
private void paintGraph(List edgeBeanList) {
try {
gefNodeMap = new HashMap();
graphNodeMap = new HashMap();
edgeList = new ArrayList();
directedGraph = new DirectedGraph();
GraphModel model = new DefaultGraphModel();
graph.setModel(model);
Map attributes = new Hashtable();
Map edgeAttrib = new Hashtable();
GraphConstants.setLineEnd(edgeAttrib, GraphConstants.ARROW_CLASSIC);
GraphConstants.setEndFill(edgeAttrib, true);
graph.setJumpToDefaultPort(true);
Iterator edgeBeanIt = edgeBeanList.iterator();
while (edgeBeanIt.hasNext()) {
EdgeBean edgeBean = (EdgeBean) edgeBeanIt.next();
NodeBean sourceAction = edgeBean.getsourceNodeBean();
NodeBean targetAction = edgeBean.gettargetNodeBean();
addEdge(sourceAction, targetAction, 20, edgeBean.getEdgeDesc());
}
try {
new DirectedGraphLayout().visit(directedGraph);
} catch (Exception e1) {
new NodeJoiningDirectedGraphLayout().visit(directedGraph);
}
Collection nodeCollection = graphNodeMap.values();
if (nodeCollection != null) {
Iterator nodeIterator = nodeCollection.iterator();
if (nodeIterator != null) {
while (nodeIterator.hasNext()) {
DefaultGraphCell node = (DefaultGraphCell) nodeIterator
.next();
NodeBean userObject = (NodeBean) node.getUserObject();
if (userObject == null) {
continue;
}
Node gefNode = (Node) gefNodeMap.get(userObject);
Map nodeAttrib = new Hashtable();
Color c = Color.green;
if (userObject.getType().equals("1")) {
c = new Color(240, 176, 176);
} else if (userObject.getType().equals("2")) {
c = new Color(254, 232, 95);
} else {
c = new Color(127, 191, 81);
}
GraphConstants.setBackground(nodeAttrib, c);
GraphConstants.setOpaque(nodeAttrib, true);
GraphConstants.setBorder(nodeAttrib, BorderFactory
.createRaisedBevelBorder());
GraphConstants.setBorderColor(nodeAttrib, c);
Rectangle2D Bounds = new Rectangle2D.Double(gefNode.x,
gefNode.y, GraphProp.NODE_WIDTH,
GraphProp.NODE_HEIGHT);
GraphConstants.setBounds(nodeAttrib, Bounds);
attributes.put(node, nodeAttrib);
}// while
}
}
if (edgeList == null) {
return;
}
for (int i = 0; i < edgeList.size(); i++) {
UnionEdge unionEdge = (UnionEdge) edgeList.get(i);
if (unionEdge == null) {
continue;
}
ConnectionSet cs = new ConnectionSet(unionEdge.getEdge(),
unionEdge.getSourceNode().getChildAt(0), unionEdge
.getTargetNode().getChildAt(0));
Object[] cells = new Object[] { unionEdge.getEdge(),
unionEdge.getSourceNode(), unionEdge.getTargetNode() };
attributes.put(unionEdge.getEdge(), edgeAttrib);
model.insert(cells, attributes, cs, null, null);
}
this.labelIntroduce(model, attributes);
graph.repaint();
} catch (Exception e) {
e.printStackTrace();
}
}
private void graphInit() {
GraphModel model = new DefaultGraphModel();
graph = new JGraph(model);
graph.setSelectionEnabled(true);
graph.addMouseListener(this);
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(550, 430));
panel.setLayout(new BorderLayout());
panel.add(new JScrollPane(graph), BorderLayout.CENTER);
this.add(panel);
}