用Java2D画出树的结构_v0.1.0
2015-11-18 10:10
495 查看
原文地址:http://blog.csdn.net/kakashi8841/article/details/5996778
先看效果图:
定义树的数据结构
[java] view
plaincopy
/**
* 2010-11-8
* John
*/
package tree;
import java.util.ArrayList;
import java.util.List;
/**
* 树的结构
* @author John
*
*/
public class Node {
private String name; //该结点名字
private int layer = 0; //该结点层级
private List<Node> childs = null; //保存该结点的孩子
public Node(String name){
this.name = name;
}
/**
* 增加一个孩子
* @param n 要作为孩子增加的结点
*/
public void add(Node n){
if(childs == null)
childs = new ArrayList<Node>();
n.setLayer(layer+1);
setChildLayout(n);
childs.add(n);
}
/**
* 递归设置孩子的层级
* @param n
*/
private void setChildLayout(Node n){
if(n.hasChild()){
List<Node> c = n.getChilds();
for(Node node : c){
node.setLayer(node.getLayer()+1);
setChildLayout(node);
}
}
}
/**
* 获取结点名
* @return 结点名
*/
public String getName() {
return name;
}
/**
* 设置结点名
* @param name 结点名
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取该结点的层级
* @return 该结点的层级
*/
public int getLayer() {
return layer;
}
/**
* 设置该结点的层级
* @param layer 该结点的层级
*/
public void setLayer(int layer) {
this.layer = layer;
}
/**
* 获取该结点的孩子
* @return 所有孩子结点
*/
public List<Node> getChilds() {
return childs;
}
/**
* 检查是否存在孩子
* @return 是则返回true,否则返回false
*/
public boolean hasChild(){
return childs == null ? false : true;
}
/**
* 递归打印所有的结点(包括子结点)
* @param n 要打印的根结点
*/
public void printAllNode(Node n){
System.out.println(n);
if(n.hasChild()){
List<Node> c = n.getChilds();
for(Node node : c){
printAllNode(node);
}
}
}
public String getAllNodeName(Node n){
String s = n.toString()+"/n";
if(n.hasChild()){
List<Node> c = n.getChilds();
for(Node node : c){
s+=getAllNodeName(node)+"/n";
}
}
return s;
}
public String toString(){
return layer+"层/t: "+name;
}
}
Node的测试类:
[java] view
plaincopy
/**
* 2010-11-9
* John
*/
package tree.demo;
import tree.Node;
/**
* @author John
*
*/
public class TestPrintNode {
public static void main(String[] args){
Node n = new Node("root");
n.add(new Node("a1"));
n.add(new Node("a2"));
Node n2 = new Node("a3");
n2.add(new Node("b1"));
n2.add(new Node("b2"));
n2.add(new Node("b3"));
Node n3 = new Node("b4");
n2.add(n3);
n3.add(new Node("c1"));
n3.add(new Node("c2"));
n.add(n2);
n.printAllNode(n); //输出树
}
}
画树的Panel
[java] view
plaincopy
/**
* 2010-11-9
* John
*/
package tree;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.util.List;
import javax.swing.JPanel;
/**
* TODO 同一层结点过多有BUG,应该对每一层的所有结点都进行个数统计,之后才绘制。
* @author John
*
*/
public class TreePanel extends JPanel {
private Node tree; //保存整棵树
private int gridWidth = 80; //每个结点的宽度
private int gridHeight = 20; //每个结点的高度
private int vGap = 50; //每2个结点的垂直距离
private int hGap = 30; //每2个结点的水平距离
private int startY = 10; //根结点的Y,默认距离顶部10像素
private int startX = 0; //根结点的X,默认水平居中对齐
private int childAlign; //孩子对齐方式
public static int CHILD_ALIGN_ABSOLUTE = 0; //相对Panel居中
public static int CHILD_ALIGN_RELATIVE = 1; //相对父结点居中
private Font font = new Font("微软雅黑",Font.BOLD,14); //描述结点的字体
private Color gridColor = Color.BLACK; //结点背景颜色
private Color linkLineColor = Color.BLACK; //结点连线颜色
private Color stringColor = Color.WHITE; //结点描述文字的颜色
/**
* 默认构造
*/
public TreePanel(){
this(null,CHILD_ALIGN_ABSOLUTE);
}
/**
* 根据传入的Node绘制树,以绝对居中的方式绘制
* @param n 要绘制的树
*/
public TreePanel(Node n){
this(n,CHILD_ALIGN_ABSOLUTE);
}
/**
* 设置要绘制时候的对齐策略
* @param childAlign 对齐策略
* @see tree.TreePanel#CHILD_ALIGN_RELATIVE
* @see tree.TreePanel#CHILD_ALIGN_ABSOLUTE
*/
public TreePanel(int childAlign){
this(null,childAlign);
}
/**
* 根据孩子对齐策略childAlign绘制的树的根结点n
* @param n 要绘制的树的根结点
* @param childAlign 对齐策略
*/
public TreePanel(Node n, int childAlign){
super();
setTree(n);
this.childAlign = childAlign;
}
/**
* 设置用于绘制的树
* @param n 用于绘制的树的
*/
public void setTree(Node n) {
tree = n;
}
//重写而已,调用自己的绘制方法
public void paintComponent(Graphics g){
startX = (getWidth()-gridWidth)/2;
super.paintComponent(g);
g.setFont(font);
drawAllNode(tree, startX, g);
}
/**
* 递归绘制整棵树
* @param n 被绘制的Node
* @param xPos 根节点的绘制X位置
* @param g 绘图上下文环境
*/
public void drawAllNode(Node n, int x, Graphics g){
int y = n.getLayer()*(vGap+gridHeight)+startY;
int fontY = y + gridHeight - 5; //5为测试得出的值,你可以通过FM计算更精确的,但会影响速度
g.setColor(gridColor);
g.fillRect(x, y, gridWidth, gridHeight); //画结点的格子
g.setColor(stringColor);
g.drawString(n.toString(), x, fontY); //画结点的名字
if(n.hasChild()){
List<Node> c = n.getChilds();
int size = n.getChilds().size();
int tempPosx = childAlign == CHILD_ALIGN_RELATIVE
? x+gridWidth/2 - (size*(gridWidth+hGap)-hGap)/2
: (getWidth() - size*(gridWidth+hGap)+hGap)/2;
int i = 0;
for(Node node : c){
int newX = tempPosx+(gridWidth+hGap)*i; //孩子结点起始X
g.setColor(linkLineColor);
g.drawLine(x+gridWidth/2, y+gridHeight, newX+gridWidth/2, y+gridHeight+vGap); //画连接结点的线
drawAllNode(node, newX, g);
i++;
}
}
}
public Color getGridColor() {
return gridColor;
}
/**
* 设置结点背景颜色
* @param gridColor 结点背景颜色
*/
public void setGridColor(Color gridColor) {
this.gridColor = gridColor;
}
public Color getLinkLineColor() {
return linkLineColor;
}
/**
* 设置结点连接线的颜色
* @param gridLinkLine 结点连接线的颜色
*/
public void setLinkLineColor(Color gridLinkLine) {
this.linkLineColor = gridLinkLine;
}
public Color getStringColor() {
return stringColor;
}
/**
* 设置结点描述的颜色
* @param stringColor 结点描述的颜色
*/
public void setStringColor(Color stringColor) {
this.stringColor = stringColor;
}
public int getStartY() {
return startY;
}
/**
* 设置根结点的Y位置
* @param startY 根结点的Y位置
*/
public void setStartY(int startY) {
this.startY = startY;
}
public int getStartX() {
return startX;
}
/**
* 设置根结点的X位置
* @param startX 根结点的X位置
*/
public void setStartX(int startX) {
this.startX = startX;
}
}
测试TreePanel
[java] view
plaincopy
/**
* 2010-11-9
* John
*/
package tree.demo;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Panel;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import tree.Node;
import tree.TreePanel;
/**
* @author John
*
*/
public class TestDrawTree extends JFrame{
public TestDrawTree(){
super("Test Draw Tree");
initComponents();
}
public static void main(String[] args){
TestDrawTree frame = new TestDrawTree();
frame.setSize(800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void initComponents(){
/*
* 初始化树的数据
*/
Node n = new Node("root");
Node a1 = new Node("a1");
Node a2 = new Node("a2");
n.add(a1);
n.add(a2);
Node a3 = new Node("a3");
Node b1 = new Node("b1");
Node d1 = new Node("d1");
Node d2 = new Node("d2");
b1.add(d1);
b1.add(d2);
a3.add(b1);
a3.add(new Node("b2"));
a3.add(new Node("b3"));
Node n3 = new Node("b4");
a3.add(n3);
n3.add(new Node("c1"));
n3.add(new Node("c2"));
n.add(a3);
//n.printAllNode(n); //输出树
/*
* 创建一个用于绘制树的面板并将树传入,使用相对对齐方式
*/
TreePanel panel1 = new TreePanel(TreePanel.CHILD_ALIGN_RELATIVE);
panel1.setTree(n);
/*
* 创建一个用于绘制树的面板并将树传入,使用绝对对齐方式
*/
TreePanel panel2 = new TreePanel(TreePanel.CHILD_ALIGN_ABSOLUTE);
panel2.setTree(n);
panel2.setBackground(Color.BLACK);
panel2.setGridColor(Color.WHITE);
panel2.setLinkLineColor(Color.WHITE);
panel2.setStringColor(Color.BLACK);
JPanel contentPane = new JPanel();
contentPane.setLayout(new GridLayout(2,1));
contentPane.add(panel1);
contentPane.add(panel2);
add(contentPane,BorderLayout.CENTER);
}
}
先看效果图:
定义树的数据结构
[java] view
plaincopy
/**
* 2010-11-8
* John
*/
package tree;
import java.util.ArrayList;
import java.util.List;
/**
* 树的结构
* @author John
*
*/
public class Node {
private String name; //该结点名字
private int layer = 0; //该结点层级
private List<Node> childs = null; //保存该结点的孩子
public Node(String name){
this.name = name;
}
/**
* 增加一个孩子
* @param n 要作为孩子增加的结点
*/
public void add(Node n){
if(childs == null)
childs = new ArrayList<Node>();
n.setLayer(layer+1);
setChildLayout(n);
childs.add(n);
}
/**
* 递归设置孩子的层级
* @param n
*/
private void setChildLayout(Node n){
if(n.hasChild()){
List<Node> c = n.getChilds();
for(Node node : c){
node.setLayer(node.getLayer()+1);
setChildLayout(node);
}
}
}
/**
* 获取结点名
* @return 结点名
*/
public String getName() {
return name;
}
/**
* 设置结点名
* @param name 结点名
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取该结点的层级
* @return 该结点的层级
*/
public int getLayer() {
return layer;
}
/**
* 设置该结点的层级
* @param layer 该结点的层级
*/
public void setLayer(int layer) {
this.layer = layer;
}
/**
* 获取该结点的孩子
* @return 所有孩子结点
*/
public List<Node> getChilds() {
return childs;
}
/**
* 检查是否存在孩子
* @return 是则返回true,否则返回false
*/
public boolean hasChild(){
return childs == null ? false : true;
}
/**
* 递归打印所有的结点(包括子结点)
* @param n 要打印的根结点
*/
public void printAllNode(Node n){
System.out.println(n);
if(n.hasChild()){
List<Node> c = n.getChilds();
for(Node node : c){
printAllNode(node);
}
}
}
public String getAllNodeName(Node n){
String s = n.toString()+"/n";
if(n.hasChild()){
List<Node> c = n.getChilds();
for(Node node : c){
s+=getAllNodeName(node)+"/n";
}
}
return s;
}
public String toString(){
return layer+"层/t: "+name;
}
}
Node的测试类:
[java] view
plaincopy
/**
* 2010-11-9
* John
*/
package tree.demo;
import tree.Node;
/**
* @author John
*
*/
public class TestPrintNode {
public static void main(String[] args){
Node n = new Node("root");
n.add(new Node("a1"));
n.add(new Node("a2"));
Node n2 = new Node("a3");
n2.add(new Node("b1"));
n2.add(new Node("b2"));
n2.add(new Node("b3"));
Node n3 = new Node("b4");
n2.add(n3);
n3.add(new Node("c1"));
n3.add(new Node("c2"));
n.add(n2);
n.printAllNode(n); //输出树
}
}
画树的Panel
[java] view
plaincopy
/**
* 2010-11-9
* John
*/
package tree;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.util.List;
import javax.swing.JPanel;
/**
* TODO 同一层结点过多有BUG,应该对每一层的所有结点都进行个数统计,之后才绘制。
* @author John
*
*/
public class TreePanel extends JPanel {
private Node tree; //保存整棵树
private int gridWidth = 80; //每个结点的宽度
private int gridHeight = 20; //每个结点的高度
private int vGap = 50; //每2个结点的垂直距离
private int hGap = 30; //每2个结点的水平距离
private int startY = 10; //根结点的Y,默认距离顶部10像素
private int startX = 0; //根结点的X,默认水平居中对齐
private int childAlign; //孩子对齐方式
public static int CHILD_ALIGN_ABSOLUTE = 0; //相对Panel居中
public static int CHILD_ALIGN_RELATIVE = 1; //相对父结点居中
private Font font = new Font("微软雅黑",Font.BOLD,14); //描述结点的字体
private Color gridColor = Color.BLACK; //结点背景颜色
private Color linkLineColor = Color.BLACK; //结点连线颜色
private Color stringColor = Color.WHITE; //结点描述文字的颜色
/**
* 默认构造
*/
public TreePanel(){
this(null,CHILD_ALIGN_ABSOLUTE);
}
/**
* 根据传入的Node绘制树,以绝对居中的方式绘制
* @param n 要绘制的树
*/
public TreePanel(Node n){
this(n,CHILD_ALIGN_ABSOLUTE);
}
/**
* 设置要绘制时候的对齐策略
* @param childAlign 对齐策略
* @see tree.TreePanel#CHILD_ALIGN_RELATIVE
* @see tree.TreePanel#CHILD_ALIGN_ABSOLUTE
*/
public TreePanel(int childAlign){
this(null,childAlign);
}
/**
* 根据孩子对齐策略childAlign绘制的树的根结点n
* @param n 要绘制的树的根结点
* @param childAlign 对齐策略
*/
public TreePanel(Node n, int childAlign){
super();
setTree(n);
this.childAlign = childAlign;
}
/**
* 设置用于绘制的树
* @param n 用于绘制的树的
*/
public void setTree(Node n) {
tree = n;
}
//重写而已,调用自己的绘制方法
public void paintComponent(Graphics g){
startX = (getWidth()-gridWidth)/2;
super.paintComponent(g);
g.setFont(font);
drawAllNode(tree, startX, g);
}
/**
* 递归绘制整棵树
* @param n 被绘制的Node
* @param xPos 根节点的绘制X位置
* @param g 绘图上下文环境
*/
public void drawAllNode(Node n, int x, Graphics g){
int y = n.getLayer()*(vGap+gridHeight)+startY;
int fontY = y + gridHeight - 5; //5为测试得出的值,你可以通过FM计算更精确的,但会影响速度
g.setColor(gridColor);
g.fillRect(x, y, gridWidth, gridHeight); //画结点的格子
g.setColor(stringColor);
g.drawString(n.toString(), x, fontY); //画结点的名字
if(n.hasChild()){
List<Node> c = n.getChilds();
int size = n.getChilds().size();
int tempPosx = childAlign == CHILD_ALIGN_RELATIVE
? x+gridWidth/2 - (size*(gridWidth+hGap)-hGap)/2
: (getWidth() - size*(gridWidth+hGap)+hGap)/2;
int i = 0;
for(Node node : c){
int newX = tempPosx+(gridWidth+hGap)*i; //孩子结点起始X
g.setColor(linkLineColor);
g.drawLine(x+gridWidth/2, y+gridHeight, newX+gridWidth/2, y+gridHeight+vGap); //画连接结点的线
drawAllNode(node, newX, g);
i++;
}
}
}
public Color getGridColor() {
return gridColor;
}
/**
* 设置结点背景颜色
* @param gridColor 结点背景颜色
*/
public void setGridColor(Color gridColor) {
this.gridColor = gridColor;
}
public Color getLinkLineColor() {
return linkLineColor;
}
/**
* 设置结点连接线的颜色
* @param gridLinkLine 结点连接线的颜色
*/
public void setLinkLineColor(Color gridLinkLine) {
this.linkLineColor = gridLinkLine;
}
public Color getStringColor() {
return stringColor;
}
/**
* 设置结点描述的颜色
* @param stringColor 结点描述的颜色
*/
public void setStringColor(Color stringColor) {
this.stringColor = stringColor;
}
public int getStartY() {
return startY;
}
/**
* 设置根结点的Y位置
* @param startY 根结点的Y位置
*/
public void setStartY(int startY) {
this.startY = startY;
}
public int getStartX() {
return startX;
}
/**
* 设置根结点的X位置
* @param startX 根结点的X位置
*/
public void setStartX(int startX) {
this.startX = startX;
}
}
测试TreePanel
[java] view
plaincopy
/**
* 2010-11-9
* John
*/
package tree.demo;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.awt.Panel;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import tree.Node;
import tree.TreePanel;
/**
* @author John
*
*/
public class TestDrawTree extends JFrame{
public TestDrawTree(){
super("Test Draw Tree");
initComponents();
}
public static void main(String[] args){
TestDrawTree frame = new TestDrawTree();
frame.setSize(800, 600);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public void initComponents(){
/*
* 初始化树的数据
*/
Node n = new Node("root");
Node a1 = new Node("a1");
Node a2 = new Node("a2");
n.add(a1);
n.add(a2);
Node a3 = new Node("a3");
Node b1 = new Node("b1");
Node d1 = new Node("d1");
Node d2 = new Node("d2");
b1.add(d1);
b1.add(d2);
a3.add(b1);
a3.add(new Node("b2"));
a3.add(new Node("b3"));
Node n3 = new Node("b4");
a3.add(n3);
n3.add(new Node("c1"));
n3.add(new Node("c2"));
n.add(a3);
//n.printAllNode(n); //输出树
/*
* 创建一个用于绘制树的面板并将树传入,使用相对对齐方式
*/
TreePanel panel1 = new TreePanel(TreePanel.CHILD_ALIGN_RELATIVE);
panel1.setTree(n);
/*
* 创建一个用于绘制树的面板并将树传入,使用绝对对齐方式
*/
TreePanel panel2 = new TreePanel(TreePanel.CHILD_ALIGN_ABSOLUTE);
panel2.setTree(n);
panel2.setBackground(Color.BLACK);
panel2.setGridColor(Color.WHITE);
panel2.setLinkLineColor(Color.WHITE);
panel2.setStringColor(Color.BLACK);
JPanel contentPane = new JPanel();
contentPane.setLayout(new GridLayout(2,1));
contentPane.add(panel1);
contentPane.add(panel2);
add(contentPane,BorderLayout.CENTER);
}
}
相关文章推荐
- Eclipse调试:F5、F6、F7、F8
- 深入理解java中的try-catch-finally
- 学习spring汇总
- Eclipse将引用了第三方jar包的Java项目打包成jar文件的两种方法
- SSH:Spring框架(IOC配置)
- Java实现图片上传
- JavaWeb 服务启动时,在后台启动加载一个线程
- SSH:Spring框架(模拟IOC)
- Spring data jpa实现CRUD的三种方式
- Spring IoC
- 对象排序
- 编译单个Java文件引入jar包
- Spring框架下编写事物回滚小记
- 关于eclipse无法连接到手机的问题
- 利用classloader动态加载jar包
- Java序列化与反序列化
- java重载与覆盖
- 【转】Java enum的用法详解
- xml形式装配bean——spring in action chapter 2
- (Java Web)开发 高并发处理