swing树形图



package zhipu.fenxi.tree;

import zhipu.view.treechart.Node;

import javax.swing.*;
import java.awt.*;

/** 
 * @author John 
 * 
 */  
public class TestDrawTree extends JFrame{
    public TestDrawTree(){
        super("Test Draw Tree");
        initComponents();
        this.setTitle("添加商品");
        this.setSize(840, 660);
        this.setVisible(true);
        this.setLocationRelativeTo(null);
        this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
    }
    public void initComponents(){

        int a=1;
        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);

        JScrollPane  jScrollPane=new JScrollPane(panel1);
        add(jScrollPane,BorderLayout.CENTER);
        /**
         * 创建一个用于绘制树的面板并将树传入,使用绝对对齐方式
         */  
//        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);

    }
    public static void main(String[] args){
        TestDrawTree frame = new TestDrawTree();

        frame.setSize(800, 600);
        frame.setVisible(true);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

}  


package zhipu.fenxi.tree;

import zhipu.view.treechart.Node;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;

/** 
 * TODO 同一层结点过多有BUG,应该对每一层的所有结点都进行个数统计,之后才绘制。 
 * @author John 
 * 
 */  
public class TreePanel extends JPanel {  
  
    private Node tree;              //保存整棵树
    private int gridWidth = 20;     //每个结点的宽度
    private int gridHeight = 80;    //每个结点的高度
    private int vGap = 50;          //每2个结点的垂直距离  
    private int hGap = 30;          //每2个结点的水平距离
      
    private int startX = 10;        //根结点的Y,默认距离顶部10像素
    private int startY = 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.YELLOW;      //结点背景颜色
    private Color linkLineColor = Color.BLACK;  //结点连线颜色  
    private Color stringColor = Color.BLACK;    //结点描述文字的颜色
      
    /** 
     * 默认构造 
     */  
    public TreePanel(){  
        this(null,CHILD_ALIGN_ABSOLUTE);  
    }  
      
    /** 
     * 根据传入的Node绘制树,以绝对居中的方式绘制 
     * @param n 要绘制的树 
     */  
    public TreePanel(Node n){  
        this(n,CHILD_ALIGN_ABSOLUTE);  
    }  
      
    /** 
     * 设置要绘制时候的对齐策略 
     * @param childAlign 对齐策略
     */  
    public TreePanel(int childAlign){  
        this(null,childAlign);  
    }  
      
    /** 
     * 根据孩子对齐策略childAlign绘制的树的根结点n 
     * @param n 要绘制的树的根结点 
     * @param childAlign 对齐策略 
     */  
    public TreePanel(Node n, int childAlign){  
        super();  
        setTree(n);
        this.setPreferredSize(new Dimension(800,1000));
        this.childAlign = childAlign;  
    }  
      
    /** 
     * 设置用于绘制的树 
     * @param n 用于绘制的树的 
     */  
    public void setTree(Node n) {  
        tree = n;  
    }  
      float flag=1;
    JButton j1;
    //重写而已,调用自己的绘制方法  
    public void paintComponent(Graphics g){
        startY = (getHeight()-gridHeight)/2;
        super.paintComponent(g);
        if(j1==null) {
            j1 = new JButton("放大"); //按钮和按钮监听
            j1.setBounds(30, 300, 80, 30);
            j1.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub
                    flag *= 1.1;
                    gridWidth *= flag;     //每个结点的宽度
                    gridHeight *= flag;   //每个结点的高度
                    vGap *= flag;      //每2个结点的垂直距离
                    hGap *= flag;        //每2个结点的水平距离
                    repaint(); //重绘
                }
            });
            add(j1);
            JButton j2 = new JButton("缩小");
            j2.setBounds(150, 300, 80, 30);
            j2.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub
                    flag *= 0.9;
                    gridWidth *= flag;     //每个结点的宽度
                    gridHeight *= flag;   //每个结点的高度
                    vGap *= flag;      //每2个结点的垂直距离
                    hGap *= flag;        //每2个结点的水平距离
                    repaint();
                }
            });
            add(j2);
        }
        g.setFont(font);

        drawAllNode(tree, startY, g);
    }

    //居中显示文本
    public void drawString(Graphics g, String str, int xPos, int yPos) {

        int strWidth = g.getFontMetrics().stringWidth(str);
        g.drawString(str, xPos + strWidth / 2, yPos);
    }

    /** 
     * 递归绘制整棵树 
     * @param n 被绘制的Node 
     * @param y 根节点的绘制X位置
     * @param g 绘图上下文环境 
     */  
    public void drawAllNode(Node n, int y, Graphics g){
        int x = n.getLayer()*(hGap+gridWidth)+ startX;
        int fontX = x + gridWidth/2 - 5;     //5为测试得出的值,你可以通过FM计算更精确的,但会影响速度
          int aa=2;
        g.setColor(gridColor);  
        g.fillRect( x,y, gridWidth, gridHeight);    //画结点的格子
          
        g.setColor(stringColor);

        g.drawString(n.toString(),fontX, y+gridHeight/2 );       //画结点的名字
          
        if(n.hasChild()){
             aa=2;
            List<Node> c = n.getChilds();  
            int size = n.getChilds().size();
            int tempPosy = childAlign == CHILD_ALIGN_RELATIVE
                         ? y+gridHeight/2 - (size*(gridHeight+vGap)-vGap)/2
                         : (getHeight() - size*(gridHeight+vGap)+vGap)/2;
            int i = 0;  
            for(Node node : c){
                aa=2;
                int newY = tempPosy+(gridHeight+vGap)*i; //孩子结点起始X
                g.setColor(linkLineColor);
                g.drawLine(x+gridWidth, y+gridHeight/2, x+gridWidth+hGap/2,y+gridHeight/2);   //画连接结点的线
                g.drawLine(x+gridWidth+hGap/2,y+gridHeight/2,  x+gridWidth+hGap/2,newY+gridHeight/2 );   //画连接结点的线
                g.drawLine(x+gridWidth+hGap/2,newY+gridHeight/2, x+gridWidth+hGap, newY+gridHeight/2 );   //画连接结点的线
//                g.drawLine(x+gridWidth/2, y+gridHeight, newX+gridWidth/2, y+gridHeight+vGap);   //画连接结点的线
                drawAllNode(node, newY, 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 getStartX() {
        return startX;
    }  
  
    /** 
     * 设置根结点的Y位置 
     * @param startX 根结点的Y位置
     */  
    public void setStartX(int startX) {
        this.startX = startX;
    }  
  
    public int getStartY() {
        return startY;
    }  
  
    /** 
     * 设置根结点的X位置 
     * @param startY 根结点的X位置
     */  
    public void setStartY(int startY) {
        this.startY = startY;
    }  
  
      
}  


package zhipu.view.treechart;
  
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;  
    }  

    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);  //输出树  
    }  
  
}  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI算法网奇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值