Bootstrap

使用JTable创建一个带有复选框的用于删除选中列的表格

基础知识

表格

如同其它的Swing组件,JTable使用MVC(模型、视图、控制器)设计方式,将可视化组件(JTable实例)从其数据(TableModel实现)中分离出来。TableModel为JTable提供显示的数据、表格的维数、表格中每一列所包含的数据类型、应该显示的列标题和是否允许编辑指定单元格的值等。

表格模型

创建表格一般要利用表格模型来创建表格。接口 TableModel定义了一个表格模型,抽象类 AbstractTableModel实现了 TableModel 接口的大部分方法,只有以下三个抽象方法没有实现。(1)public int getRowCount(),(2)public int getColumnCount(),(3)public Object getValueAt(int rowIndex , int columnIndex)。通过继承 AbstractTableModel 类实现上面三个抽象方法可以创建自己的表格模型类。实现类 DefaultTableModel便是由 Swing 提供的继承了 AbstractTableModel 类并实现了上面三个抽象方法的表格模型类。表格模型创建完成后,通过 JTable 类的构造方法 JTable(TableModel dm)创建表格,就可实现利用表格模型创建表格的过程。

表格单元渲染器

表格的外观等一般是由表格渲染器来控制的。具体说来,渲染器负责单元格的外观比如前景色、背景色,对齐方式以及单元格提示等。定制的渲染器必须实现TableCellRenderer接口及getTableCellRendererComponent方法。在该方法中,可以指定渲染器的文字、单元格提示、颜色、字体等。注意,此处的文字仅为显示的内容,不是单元格的实际数据(如实际内容是false的,但显示的可能是没有打勾的复选框图标)。

表格单元编辑器

表格的内容和事件响应等一般是由表格编辑器来控制的。编辑器默认为文本框形式,也可以使用下拉菜单、按钮、单选按钮等形式。

表格的基本使用

package ym.example.table;

import java.awt.BorderLayout;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

/**
 * @author ym
 */
public class BasicTable extends JFrame{

    /**
     * 表格的数据是存储在DefaultTableModel里面的
     */
    private Object[] columns = {"字段一", "字段二", "字段三", "字段四"};//字段
    private Object[][] data = {{1,2,3,4},{5,6,7,8}};//需要展示的数据,一般是二维数组
    private DefaultTableModel model = new DefaultTableModel(data, columns);
    private JTable table = new JTable(model);
    private JScrollPane scrollPane=new JScrollPane(table); 
    
    public BasicTable(){
        this.add(scrollPane,BorderLayout.CENTER);
        this.setTitle("表格的基本使用");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.pack();
    }
    
    public static void main(String[] args){
        new BasicTable();
    }
}

运行结果
在这里插入图片描述

表格的进阶使用

表格中的显示是由实现类DefaultTableCellRenderer实现的,表格中的编辑是由抽象类AbstractCellEditor和接口TableCellEditor实现的,根据需要可以重写和实现这两个类一个接口中的方法,基本能够实现表格的常用需求。

示例的源码结构

ym.example.table
       |
       +---JTableExample.java
       |
       +---MyDefaultTableModel.java
       |
       +---MyTableRenderer.java
       |
       +---MyTableCellEditor.java

继承DefaultTableCellRenderer类的MyTableRenderer类,重写了其中的getTableCellRendererComponent()方法

package ym.example.table;

import java.awt.Color;
import java.awt.Component;
 
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
 
public class MyTableRenderer extends DefaultTableCellRenderer{
	
	private static final long serialVersionUID = 1L;
 
	/**
     * 对表格进行渲染的时候单元格默认返回的是JLabel,可以根据需要返回不同的控件
     */
	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		// 第一列渲染成复选框
		if (column==0) {
			JCheckBox box=new JCheckBox(); // 复选框
			box.setOpaque(true);  // 设置成不透明
			box.setHorizontalAlignment(JCheckBox.CENTER); // 居中
			if (isSelected) {//点击表格的时候改变点击的行的背景色
				box.setBackground(new Color(135, 206, 250));
			} else {
				if (row % 2 == 0) { // 偶数行的前景、背景颜色
					box.setBackground(new Color(240, 250, 250));
					box.setForeground(table.getForeground());
				} else { // 奇数行的背景颜色
					box.setBackground(table.getBackground());
				}
			}
			boolean valu=(Boolean) value;
			box.setSelected(valu);
			return box;
		}
		// 其它列渲染成普通标签
		JLabel label = new JLabel();
		label.setOpaque(true);
        label.setHorizontalAlignment(JLabel.CENTER);
		if (isSelected) { // 点击表格的时候改变点击的行的背景色
			label.setBackground(new Color(135, 206, 250));
		} else {
			if (row % 2 == 0) {
				label.setBackground(new Color(240, 250, 250));
				label.setForeground(table.getForeground());
			} else {
				label.setBackground(table.getBackground());
			}
		}
		label.setText(value != null ? value.toString() : "");
		return label;
	}
}

继承AbstractCellEditor和实现TableCellEditor的MyTableCellEditor类(工具类,可以添加JTextField,JCheckBox,JComboBox等控件到单元格中)

package ym.example.table;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.io.Serializable;
import java.util.EventObject;
import javax.swing.AbstractCellEditor;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.table.TableCellEditor;

public class MyTableCellEditor extends AbstractCellEditor implements TableCellEditor {

    protected JComponent editorComponent; // 编辑组件
    protected EditorDelegate delegate;    // 编辑代表
    protected int clickCountToStart = 1;

    public MyTableCellEditor(final JTextField textField) {
        editorComponent = textField;
        this.clickCountToStart = 1;
        delegate = new EditorDelegate() {
            public void setValue(Object value) {
                textField.setText((value != null) ? value.toString().trim() : "");
            }

            public Object getCellEditorValue() {
                return textField.getText();
            }
        };
        textField.addActionListener(delegate);
    }

    public MyTableCellEditor(final JCheckBox checkBox) {
        editorComponent = checkBox;
        checkBox.setSelected(false);
        checkBox.setHorizontalAlignment(JCheckBox.CENTER);
        delegate = new EditorDelegate() {
            public void setValue(Object value) {
                boolean selected = false;
                if (value instanceof Boolean) {
                    selected = ((Boolean) value).booleanValue();
                } else if (value instanceof String) {
                    selected = value.equals("true");
                }
                checkBox.setSelected(selected);
            }

            public Object getCellEditorValue() {
                return Boolean.valueOf(checkBox.isSelected());
            }
        };
        checkBox.addActionListener(delegate);
        checkBox.setRequestFocusEnabled(false);
    }

    public MyTableCellEditor(final JComboBox comboBox) {
        editorComponent = comboBox;
        comboBox.putClientProperty("JComboBox.isTableCellEditor", Boolean.TRUE);
        delegate = new EditorDelegate() {
            public void setValue(Object value) {
                comboBox.setSelectedItem(value);
            }

            public Object getCellEditorValue() {
                return comboBox.getSelectedItem();
            }

            public boolean shouldSelectCell(EventObject anEvent) {
                if (anEvent instanceof MouseEvent) {
                    MouseEvent e = (MouseEvent) anEvent;
                    return e.getID() != MouseEvent.MOUSE_DRAGGED;
                }
                return true;
            }

            public boolean stopCellEditing() {
                if (comboBox.isEditable()) {
                    // Commit edited value.
                    comboBox.actionPerformed(new ActionEvent(
                            MyTableCellEditor.this, 0, ""));
                }
                return super.stopCellEditing();
            }
        };
        comboBox.addActionListener(delegate);
    }

    public Component getComponent() {
        return editorComponent;
    }

    public void setClickCountToStart(int count) {
        clickCountToStart = count;
    }

    public int getClickCountToStart() {
        return clickCountToStart;
    }

    @Override
    public Object getCellEditorValue() {
        return delegate.getCellEditorValue();
    }

    @Override
    public boolean isCellEditable(EventObject anEvent) {
        if (anEvent != null && delegate != null) {
            return delegate.isCellEditable(anEvent);
        } else {
            return false;
        }
    }

    @Override
    public boolean shouldSelectCell(EventObject anEvent) {
        return delegate.shouldSelectCell(anEvent);
    }

    @Override
    public boolean stopCellEditing() {
        return delegate.stopCellEditing();
    }

    @Override
    public void cancelCellEditing() {
        delegate.cancelCellEditing();
    }

    public Component getTreeCellEditorComponent(JTree tree, Object value,
            boolean isSelected,
            boolean expanded,
            boolean leaf, int row) {
        String stringValue = tree.convertValueToText(value, isSelected,
                expanded, leaf, row, false);

        delegate.setValue(stringValue);
        return editorComponent;
    }

    @Override
    public Component getTableCellEditorComponent(JTable table, Object value,
            boolean isSelected,
            int row, int column) {
        delegate.setValue(value);
        return editorComponent;
    }

    protected class EditorDelegate implements ActionListener, ItemListener, Serializable {

        /**
         * The value of this cell.
         */
        protected Object value;

        public Object getCellEditorValue() {
            return value;
        }
        public void setValue(Object value) {
            this.value = value;
        }

        public boolean isCellEditable(EventObject anEvent) {
            if (anEvent instanceof MouseEvent) {
                return ((MouseEvent) anEvent).getClickCount() >= clickCountToStart;
            }
            return true;
        }
        public boolean shouldSelectCell(EventObject anEvent) {
            return true;
        }
        public boolean startCellEditing(EventObject anEvent) {
            return true;
        }
        public boolean stopCellEditing() {
            fireEditingStopped();
            return true;
        }
        public void cancelCellEditing() {
            fireEditingCanceled();
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            MyTableCellEditor.this.stopCellEditing();
        }
        @Override
        public void itemStateChanged(ItemEvent e) {
            MyTableCellEditor.this.stopCellEditing();
        }
    }
}

继承DefaultTableModel的MyDefaultTableModel类,重写其中的isCellEditable(),使只有第一列的单元格能够编辑

package ym.example.table;

import javax.swing.table.DefaultTableModel;

/**
 * 继承默认表格模型的表格模型
 * @author ym
 */
class MyDefaultTableModel extends DefaultTableModel {

    /**
     * 控制表格的某个单元格是否能编辑,此处规定只有第一列的单元格能够编辑
     * @param rowIndex
     * @param columnIndex
     * @return 
     */
    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        if(columnIndex==0){
            return true;
        }
        return false;
    }
}

主代码

package ym.example.table;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.Box;

import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
/**
 * 这段代码展示如何使用组合列表框作为表格中的元素 使得可以在列表框中选择所需要的数据,相当于输入不同数据
 * 
 * @author burns
 * 
 */
public class JTableExample extends JFrame{
    
    private JButton saveBtn=null;
    private MyDefaultTableModel tableModel=null;
    private JTable table=null;
    private JScrollPane scrollPane=null;
    
    private String[] columnTitle = {"选择", "姓名", "居住地", "性别", "年龄"};
    private Object[][] tableData = {
            { false ,"太上老君", "兜率宫", "男", 10000 },
            { false,"元始天尊", "玉虚宫", "男" , 10000 },
            { false,"通天教主", "碧游宫", "男" , 10000 },
            { false,"女娲",     "娲皇宫", "女" , 10000 },
            { false,"准提道人", "灵山",   "男" , 10000 },
            { false,"接引道人", "灵山",   "男" , 10000 }};

    public JTableExample() {
        initTable();
        initComponent();
        initLayout();
        initListener();
        this.setTitle("删除表格中的数据");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
        this.pack();
    }
    
    public void initComponent(){
        saveBtn=new JButton("删除");
    }
    
    public void initLayout(){
        Box horizontal=Box.createHorizontalBox();
        horizontal.add(Box.createHorizontalGlue());
        horizontal.add(saveBtn);
        this.add(horizontal,BorderLayout.NORTH);
        this.add(scrollPane, BorderLayout.CENTER);
    }
    
    public void initListener(){
        saveBtn.addActionListener(new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent e){
                List<String> list=new ArrayList<String>();
                for(int i=0;i<table.getRowCount();){
                    if((Boolean)table.getValueAt(i, 0)){
                        list.add((String)table.getValueAt(i,1));
                        /**
                         * 从模型中删除指定的行。删除行后将会把通知发送给所有的侦听器。
                         */
                        tableModel.removeRow(i);
                        i=0;
                        continue;
                    }
                    i++; // 不能放到for中,否则在全删时会有漏删
                }
                System.out.println("需要删除的数据:"+list);
            }
        });
    }
    
    public void initTable(){

        tableModel=new MyDefaultTableModel();
        tableModel.setDataVector(tableData, columnTitle);
        table = new JTable(tableModel); // 利用MyTableModel来建立JTable
        table.setToolTipText("圣人信息"); // 设置工具提示文本
        scrollPane = new JScrollPane(table);
        /**
         * 利用JTable所提供的getColumnModel()方法取得TableColumnModel对象
         * 再由TableColumnModel类所提供的getColumn()方法取得TableColumn对象
         * TableColumn类可针对表格中的每一列做具体的设置 例如设置字段的宽度,
         * 某行的标头(单元格渲染器),设置输入较复杂的数据类型等(单元格编辑器)。
         */
        // 对每一列设置单元格渲染器
        for(int i=0;i<table.getColumnCount();i++){
            table.getColumnModel().getColumn(i).setCellRenderer(new MyTableRenderer());
        }
        // 设置表格第一列的单元格编辑器为复选框
        table.getColumnModel().getColumn(0).setCellEditor(new MyTableCellEditor(new JCheckBox()));
    }

    public static void main(String[] args) {
        new JTableExample();
    }
}

运行结果
在这里插入图片描述

对表格进行排序

从JDK 1.6 开始,提供了对表格进行排序的功能。通过 JTable 类的 setRowSoreter(RowSortersorter)方法可以为表格设置排序器。TableRowSorter 类是由Swing 提供的排序器类。为表格设置排序器的典型代码如下:

DefaultTableModel tableModel = new DefaultTableModel(); //创建表格模型
JTable table = new JTable(tableModel); //创建表格
table.setRowSorter(new TableRowSorter(tableModel)); //设置排序器

如果为表格设置了排序器,当单击表格的某一列头时,在该列名称的后面将出现▲标记,说明按该列升序排列表格中的所有行;当再次单击该列头时,标记将变成▼,说明按该列降序排列表格中的所有行。

注意:在使用表格排序器时,通常要为其设置表格模型。一种方法是通过构造方法 TableRowSorter(TableModel model)创建排序器;另一种方法是通过 setModel(TableModel model)方法为排序器设置表格模型。

运行结果
在这里插入图片描述
对“居住地”列进行排序后的结果
在这里插入图片描述

Java Swing实现JTable检测单元格数据变更事件的方法示例:https://www.jb51.net/article/128176.htm

;