java绘制(可视化)树结构图

        以JPanel组件为画板,继承JPanel类并重写paint(Graphics g)函数,在函数中使用画笔g绘制树结构图。

实例代码——3个java源文件:Main.java、DrawNode.java、DrawTree.java

1、Main.java

package drawTree;

public class Main {
	public static void main(String[] args){
		DrawTree dt = new DrawTree();
		DrawNode dn0 = new DrawNode("纹理",0,1024);
		DrawNode dn0_1 = new DrawNode(dn0,"密度","清晰");
		DrawNode dn0_2 = new DrawNode(dn0,"触感","稍糊");
		DrawNode dn0_3 = new DrawNode(dn0,"no","模糊");
		DrawNode dn01_1 = new DrawNode(dn0_1,"no","0.4");
		DrawNode dn01_2 = new DrawNode(dn0_1,"yes","0.6");
		DrawNode dn01_3 = new DrawNode(dn0_1,"yes","0.8");
		DrawNode dn02_1 = new DrawNode(dn0_2,"no","硬滑");
		DrawNode dn02_2 = new DrawNode(dn0_2,"yes","软粘");
		dt.function(dn0);
	}
}

2、DrawNode.java

package drawTree;

public class DrawNode {
	String value = null;		//当前节点的属性
	DrawNode parentNode = null;	//父结点
	String lineValue = null;	//与父结点连接的属性
	int sonNodeNum = 0;			//子结点个数
	DrawNode[] sonNode = new DrawNode[10];	//子结点
	int depth = 0;				//深度
	int beginX = 0;				//以该节点为根节点的树前边界
	int endX = 0;				//以该节点为根节点的树后边界
	boolean draw = false;		//是否已经被绘制
	
	int selfX = 0;				//自身节点横坐标
	int selfY = 0;				//自身节点纵坐标
	int parentX = 0;			//父亲节点横坐标
	int parentY = 0;			//父亲节点纵坐标
	
	
	
	DrawNode(String value,int beginX, int endX){	//根节点构造函数
		this.value = value;
		this.beginX = beginX;
		this.endX = endX;
		this.depth = 0;
		this.selfX = beginX + (beginX+endX)/2;
		this.selfY = 0;
	}
	
	DrawNode(DrawNode parentNode, String value, String lineValue){	//不是根节点构造函数
		this.parentNode = parentNode;
		this.value = value;
		this.lineValue = lineValue;
		this.parentX = parentNode.selfX;
		this.parentY = parentNode.selfY;
		this.depth = parentNode.depth+1;
		//自身x坐标是要根据父结点的子结点的个数动态改变
		//this.selfX = parentNode.selfX+(-200+parentNode.sonNodeNum*200/(depth+1));	//这条语句可有可无,在树完全生成后,再确定每个节点的selfX
		this.selfY = parentNode.selfY+200;
		parentNode.sonNodeNum++;
		parentNode.sonNode[parentNode.sonNodeNum-1] = this;
		//setAllSonX(parentNode);
		
	}
	
	
}

3、DrawTree.java

package drawTree;

import java.awt.Graphics;
import java.awt.image.BufferedImage;

import javax.swing.*;

public class DrawTree {
	int WIDTH = 1024;
	int HEIGHT = 1024; 
	DrawNode root = null;
	
	
	void function(DrawNode dn){
		JFrame jf = new JFrame();
		jf.setTitle("树");
		jf.setSize(WIDTH, HEIGHT);
		MyPanel mp = new MyPanel();
		setX(dn);
		mp.root = dn;
		jf.add(mp);
		jf.setVisible(true);
	}
	
	//递归函数,设置树中每个节点的selfX
	void setX(DrawNode root){
		//设置子结点的beginX和endX
		int gap = (root.endX-root.beginX)/(root.sonNodeNum+1);
		for(int i=0;i<root.sonNodeNum;i++){
			root.selfX = root.beginX+(root.endX-root.beginX)/2;
			root.sonNode[i].selfX = root.beginX+(i+1)*gap;
			root.sonNode[i].beginX = root.sonNode[i].selfX-gap/2;
			root.sonNode[i].endX = root.sonNode[i].selfX + gap/2;
			root.sonNode[i].parentX = root.selfX;
			if(root.sonNode[i]!= null){
				setX(root.sonNode[i]);
			}
		}
	}
}


class MyPanel extends JPanel{
	DrawNode root = null;
	 
	private static final long serialVersionUID = 1L;
	
	public void paint(Graphics g){
		//调用paint获得组件JPanel的画笔,以组件为画板
		DrawNode tmp = root;
		int x = 0;
		int num = 0;
		if(tmp != null){
			num = 1;
		}
		//类似非递归函数遍历树的节点
		while(x<num){	//
			int depth = tmp.depth;
			if(tmp.draw == false){
				if(tmp.sonNodeNum==0){
					
				}else{
					num = num + tmp.sonNodeNum;
				}
				g.drawOval(tmp.selfX, tmp.selfY, 50, 50);
				g.drawString(tmp.value, tmp.selfX+25, tmp.selfY+25);
				if(tmp != root){
					g.drawLine(tmp.selfX+25, tmp.selfY+25, tmp.parentX+25, tmp.parentY+25);
					g.drawString(tmp.lineValue, (tmp.selfX+tmp.parentX+50)/2, (tmp.selfY+tmp.parentY+50)/2);
				}
				tmp.draw = true;
				x++;
			}else{
				int y = -1;
				for(int i=0;i<tmp.sonNodeNum;i++){
					if(tmp.sonNode[i].draw == false){
						y=i;
						break;
					}
				}
				if(y!=-1){	//还有子结点为绘画。
					tmp = tmp.sonNode[y];
					continue;	//进入子结点,重新循环
				}else{		//之下的全部结点都以绘完
					if(tmp ==root){
						break;	//为根节点就退出
					}else{
						tmp = tmp.parentNode;
						continue;
					}
				}
			}
			if(tmp.sonNodeNum == 0){	//叶子节点,回到父结点
				tmp = tmp.parentNode;
			}else{						//不是叶子节点,进入下一层
				tmp = tmp.sonNode[0];
			}
		}
		
	}
}
	


运行结果:

新人,代码不好,多多包含。。。

        之后可能会尽可能地完善一下。。

补充01:

代码运行方式:

        1、放在eclipse项目的同一个包下,且三个java文件中的package要一致,即可直接运行。

        2、控制台运行步骤:

                

 

编写Java数据可视化框架源代码需要遵循以下步骤: 1. 首先,需要确定该数据可视化框架的目标和功能,例如绘制柱状图、折线图或饼图等。 2. 接下来,需要确定使用的绘图库或图库。Java中常用的有JavaFX和Swing等,选择合适的库来绘制。 3. 设计框架的类结构。根据所选的图库和实现的功能,设计出合适的类和接口,例如绘图组件、图表组件、数据模型等。 4. 实现数据的读取和处理功能。根据需求,可以从文件或数据库中读取数据,然后对数据进行处理,例如计算统计信息或排序等。 5. 实现图绘制功能。利用所选的图库,将数据转化为图,并进行绘制。可以根据数据的特点,选择合适的绘制方法,如使用柱状图绘制连续数据,或使用折线图绘制趋势。 6. 实现图的交互功能。为了增强用户体验,可以为图添加交互功能,如鼠标悬停显示数据详情、点击图进行放大等。 7. 进行测试和调试。在实现过程中,需要对每个功能进行测试和调试,确保框架的正确性和稳定性。 8. 提供文档和示例。编写代码时,要提供详细的文档说明,包括框架的使用方法和接口说明。同时,可以提供示例代码,帮助其他开发人员理解和使用该框架。 总的来说,编写Java数据可视化框架源代码需要充分了解所需功能和输出式,根据需求选择合适的图库,进行类的设计和功能实现,并进行适当的测试和调试。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值