前言:在开发java swing窗体程序时可能遇到以下的需求,比如要显示一个文件目录结构,文件目录树,有不同的分类,不同分类下有多个条目项。这就需要用到树组件。当需要显示一个表格,整齐的显示,就像excel那种形式,此时就需要表格组件。【注意这里讲的并不是格子布局】
(一)树组件
核心类JTree,一个JTree的对象就代表一个树组件,创建树前应该先创节点,然后再去指 定节点间关系,最后形成树。
节点类型:
- 根节点:仅有一个(树根)
- 分支节点:带叶节点的分支(树枝)
- 叶节点:不带子节点了(树叶)
分支节点可以点击图标展开或者收起
默认显示只会显示根节点和它直接相连的子节点
想作为节点需要实现 MutableTreeNode接口, 但不必我们自己写类来实现接口,在 java.swing.tree这个包中已经提供了一个叫做:DefaultMutableTreeNode 通过创建这个类对象就可以作为节点,该类有两个构造方法
DefaultMutableTreeNode(Object userObject);
DefaultMutableTreeNode(Object userObject,boolean allowChild)
第一个构造方法:默认允许该节点能有子节点,其可以通过add()方法添加其他节点。通过 该构造函数创建的节点,可以通过setAllowsChildren(boolean b)来设置其是否允许添加子节点。
第二个构造方法:即在创建节点的时候就指定了其是否允许添加子节点
需要注意的是,其中userObject是一个Object类型对象,构造时需传入的对象,其表示这 个节点中存储的内容。
在实际使用中,这个Object参数,如果这个节点不是叶子节点,传入的都是字符串,代表 这个分支的含义。叶子节点的话,传入的是类的对象或者是自己的定义类的对象。此时这个节点显示的内容将会是这个类的toString()方法,所以想要他正确的显示,需要重写自定类的toString方法
当所有节点创建好之后,并用add函数处理好,分支节点和页节点关系后。从中选取一个作 为根节点(不能出现多个),调用JTree类的构造函数JTree(TreeNode root),传入 DefaultMutableTreeNode对象。即可生成树,窗口本身再调用add()函数,将JTree对象加入进去。
点击树上的节点会自动触发TreeSelectionEvent事件(注意:是指叶子节点,点分支节点 不会触发事件,只会收起和展开),其需要一个监听器,这个类需要实现 TreeSelectionListener接口。 该接口中的核心函数valueChanged(TreeSelectionEvent e)需要实现。 Jtree对象可以通过addTreeSelectionListener()来添加监视器。
以下是一个小demo来演示树组件
/**
* 数据模型类,用于存储在树的节点当中
*/
public class Goods {
private String name;
private double price;
public Goods(String name,double price)
{
this.name=name;
this.price=price;
}
public String getName() {
return name;
}
public double getPrice() {
return price;
}
@Override
public String toString()
{
//叶节点显示出来的内容,这里叶节点应当将商品名字
return name;
}
}
public class SimpleListener implements TreeSelectionListener {
private JTree tree;//这个树
private JTextArea textArea;//显示区域
public void setTree(JTree tree) {
this.tree = tree;
}
public void setTextArea(JTextArea textArea) {
this.textArea = textArea;
}
public void valueChanged(TreeSelectionEvent e) {
//获得当前树选中的叶子节点
DefaultMutableTreeNode selectedNode=(DefaultMutableTreeNode) tree.getLa
stSelectedPathComponent();
if(selectedNode.isLeaf())
{
//选中的节点为叶子节点的情况下。JtextArea才会有变化
Goods selectGoods=(Goods) selectedNode.getUserObject();//获得选中节点存储
的东西
//将该商品信息进行显示
textArea.append(selectGoods.getName()+"价格
为"+selectGoods.getPrice()+"\n");
}
}
}
public class SimpleForm extends JFrame {
private JTree tree;//树组件
private JTextArea textArea;//显示信息
private SimpleListener listener;
public SimpleForm()
{
//Gui部分
setLayout(new GridLayout(1,2));
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setVisible(true);
setBounds(80,80,300,300);
textArea=new JTextArea();
add(new JScrollPane(textArea));
//树结构部分
DefaultMutableTreeNode rootNode=new DefaultMutableTreeNode("商品");//定
义根节点
DefaultMutableTreeNode TVtypeNode=new DefaultMutableTreeNode("电视
类");//定义子节点(有分支)
DefaultMutableTreeNode PhoneTypeNode=new DefaultMutableTreeNode("手机
类");//定义子节点(有分支
//定义叶节点的对象
Goods changhongTV=new Goods("长虹电视",1000);
Goods haierTV=new Goods("海尔电视",2000);
Goods nokiaPhone=new Goods("诺基亚手机",500);
Goods samsungPhone=new Goods("三星手机",600);
//创建叶节点
DefaultMutableTreeNode changhongTvNode=new DefaultMutableTreeNode(chang
hongTV);
DefaultMutableTreeNode haierTvNode=new DefaultMutableTreeNode(haierTV);
DefaultMutableTreeNode nokiaNode=new
DefaultMutableTreeNode(nokiaPhone);
DefaultMutableTreeNode samsungNode=new DefaultMutableTreeNode(samsungPh
one);
//指定父子关系
TVtypeNode.add(changhongTvNode);
TVtypeNode.add(haierTvNode);
PhoneTypeNode.add(nokiaNode);
PhoneTypeNode.add(samsungNode);
rootNode.add(TVtypeNode);
rootNode.add(PhoneTypeNode);
//实例化树,并设置根节点
tree=new JTree(rootNode);
//把树加入该界面进行显示
add(new JScrollPane(tree));
//设置监听器
listener=new SimpleListener();
listener.setTree(tree);
listener.setTextArea(textArea);
//添加监听器
tree.addTreeSelectionListener(listener);
}
}
public class Main {
public static void main(String[] args)
{
SimpleForm form=new SimpleForm();
}
}
效果如下
(二)表组件
即用于显示表格,且允许对其中的数据进行编辑,其有常见的3种构造方法
JTable();//创建默认的表格模型
JTable(int a,int b);//创建a行,b列的默认表格
JTable(Object data[][],Object columnName[]);//创建默认表格对象,并向其中填入
数据data二维数组,columnName数组中,存储的是列名
需要注意的是
第3种构造方法,可以传入Object的对象,和刚刚的JTree树组件一样,其可以传入字符 串,也可以传入自定对象,当传入自定对象时,其显示出来的东西就是该类对象调用 toString()函数后显示的内容。 所以,这个自定类需要重写自己的toString方法
下面是一个案例
public class SimpleListener implements ActionListener {
private JTable table;
private Object [][]data;
public void setTable(JTable table) {
this.table = table;
}
public void setData(Object[][] data) {
this.data = data;
}
public void actionPerformed(ActionEvent actionEvent)
{
for(int i=0;i<8;i++)
{
double sum=0;
boolean isNum=true;
for(int j=1;j<=2;j++) {
try {
sum += Double.parseDouble(data[i][j].toString());
} catch (Exception e) {
//说明输入了不是数字的内容
isNum = false;
table.repaint();//表格重新绘制
}
if (isNum == true) {
//总分一栏
data[i][3] = String.valueOf(sum);
table.repaint();//表格重新绘制
}
}
}
}
}
public class SimpleWindow extends JFrame {
private JTable table;
private Object [][]data;
private Object []columName;
private JButton button;
private SimpleListener listener;
public SimpleWindow()
{
//GUI部分
setLayout(new BorderLayout());
columName=new Object[]{"姓名","英语","数学","总成绩"};//该表格表头
data=new Object[8][4];//该表格将会是8行4列
for(int i=0;i<=data.length-1;i++)
{
for(int j=0;j<=data[i].length-1;j++)
{
if(j!=0)
{
//即非第一列,第一列应该为姓名,其余列默认都为0
data[i][j]=0;
}else {
//第一列设置为姓名
data[i][j]="姓名";
}
}
}
button=new JButton("计算总成绩");
table=new JTable(data,columName);
//注意!必须把JTable加载JScrollPane中,否则显示不出表头
add(new JScrollPane(table),BorderLayout.CENTER);
add(button,BorderLayout.SOUTH);
setVisible(true);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
setBounds(100,100,200,200);
//设置监听器
listener=new SimpleListener();
listener.setData(data);
listener.setTable(table);
//添加监听器
button.addActionListener(listener);
}
}
public class Main {
public static void main(String []args)
{
SimpleWindow window=new SimpleWindow();
}
}
效果如下
Add:关于表JTable的一些设置:
默认:该表的表头和值是可修改的。
- 使表头不可拖动
//注意bookTable为JTable对象
booksTable.getTableHeader().setReorderingAllowed(false);
- 使表中数据不可更改
booksTable=new JTable(data,columnName){
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
(三)计时器组件
在Javax.swing包中的Timer类(Java.util也有个Timer,不是那个),是一个计时器组 件。其有两种构造方法
new Timer(int a,Object b);//设置振铃周期,并设置监听器
new Timer(int a);//仅设置振铃周期,此后还需要timer对象addActionListener()
来指定监听器
其中a代表周期,即每过a毫秒震铃一次,b是监听器,即实现了ActionListener接口的类对 象。振铃时就会触发ActionEvent事件,从而执行接口回调actionPerormed方法。
该类的常用实例方法还有:
setReapeats(boolean );//设置是否重复,默认为true,设置为false后,时间到了就只会振铃一次,不会重复执行
setInitialDelay(int delay);//设置首次振铃的延时
start();//开始计时
stop();//停止计时
restart();//继续计时
案例如下
public class WindowTimer extends JFrame implements ActionListener{
private JTextField text;
private JButton startBtn,stopBtn,continueBtn;
private Timer timer;
private SimpleDateFormat format;//日期输出格式
public WindowTime()
{
//GUI部分
text=new JTextField(10);//用来显示时间
startBtn=new JButton("开始");
stopBtn=new JButton("停止");
continueBtn=new JButton("继续");
setLayout(new FlowLayout());//设置布局
add(startBtn);
add(stopBtn);
add(continueBtn);
add(text);
setSize(500,500);
setVisiable(true);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//设置timer计时器,和日期格式化
format=new SimpleDateFormat("hh:mm:ss");
timer=new Timer(1000,this);//1s振铃一次
//设置监听器,该类本身就是监听器,不用设置,引用可以直接拿到
//添加监听器,3个按钮和一个timer共用一个Listener
startBtn.addActionListener(this);
stopBtn.addActionListener(this);
continueBtn.addActionListener(this);
timer.addActionListener(this);
}
public void actionPerformed(ActionEvent e)
{
if(e.getSource()==timer)
{
//触发源是计时器,那么需要设置时间
Date currentDate=new Date();
text.setText(fomrat.(currentDate));
}else if(e.getSource()==startBtn)
{
//触发源是开始按钮
timer.start();
}else if(e.getSource()==stopBtn)
{
//触发源是结束按钮
timer.stop();
}else if(e.getSource()==continueBtn)
{
//触发源是继续按钮
timer.reStart();
}
}
}