基础知识
表格
如同其它的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