JavaSwing_4.8: JTable(表格)
- 概述
官方JavaDocsApi: javax.swing.JTable
JTable,表格。JTable 是用来显示和编辑常规二维单元表。
- 创建简单的表格
package com.xiets.swing;
import javax.swing.;
import java.awt.;
public class Main {
public static void main(String[] args) {
JFrame jf = new JFrame("测试窗口");
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 创建内容面板,使用边界布局
JPanel panel = new JPanel(new BorderLayout());
// 表头(列名)
Object[] columnNames = {"姓名", "语文", "数学", "英语", "总分"};
// 表格所有行数据
Object[][] rowData = {
{"张三", 80, 80, 80, 240},
{"John", 70, 80, 90, 240},
{"Sue", 70, 70, 70, 210},
{"Jane", 80, 70, 60, 210},
{"Joe", 80, 70, 60, 210}
};
// 创建一个表格,指定 所有行数据 和 表头
JTable table = new JTable(rowData, columnNames);
// 把 表头 添加到容器顶部(使用普通的中间容器添加表格时,表头 和 内容 需要分开添加)
panel.add(table.getTableHeader(), BorderLayout.NORTH);
// 把 表格内容 添加到容器中心
panel.add(table, BorderLayout.CENTER);
jf.setContentPane(panel);
jf.pack();
jf.setLocationRelativeTo(null);
jf.setVisible(true);
}
}
结果展示:
表格组件和其他普通组件一样,需要添加到中间容器中才能显示,添加表格到容器中有两种方式:
添加到普通的中间容器中(如上面代码实例所示的添加到JPanel),此时添加的jTable只是表格的行内容,表头(jTable.getTableHeader())需要额外单独添加。此添加方式适合表格行数确定,数据量较小,能一次性显示完的表格;
添加到JScrollPane滚动容器中,此添加方式不需要额外添加表头,jTable添加到jScrollPane中后,表头自动添加到滚动容器的顶部,并支持行内容的滚动(滚动行内容时,表头会始终在顶部显示)。
3. JTable 常用的操作方法
JTable常用构造方法:
// 创建空表格,后续再添加相应数据
JTable()
// 创建指定行列数的空表格,表头名称默认使用大写字母(A, B, C …)依次表示
JTable(int numRows, int numColumns)
// 创建表格,指定 表格行数据 和 表头名称
JTable(Object[][] rowData, Object[] columnNames)
// 使用表格模型创建表格
JTable(TableModel dm)
JTable 字体 和 网格 颜色设置:
// 设置内容字体
void setFont(Font font)
// 设置字体颜色
void setForeground(Color fg)
// 设置被选中的行前景(被选中时字体的颜色)
void setSelectionForeground(Color selectionForeground)
// 设置被选中的行背景
void setSelectionBackground(Color selectionBackground)
// 设置网格颜色
void setGridColor(Color gridColor)
// 设置是否显示网格
void setShowGrid(boolean showGrid)
// 水平方向网格线是否显示
void setShowHorizontalLines(boolean showHorizontalLines)
// 竖直方向网格线是否显示
void setShowVerticalLines(boolean showVerticalLines)
JTable 表头 设置:
// 获取表头
JTableHeader jTableHeader = jTable.getTableHeader();
// 设置表头名称字体样式
jTableHeader.setFont(Font font);
// 设置表头名称字体颜色
jTableHeader.setForeground(Color fg);
// 设置用户是否可以通过在头间拖动来调整各列的大小。
jTableHeader.setResizingAllowed(boolean resizingAllowed);
// 设置用户是否可以拖动列头,以重新排序各列。
jTableHeader.setReorderingAllowed(boolean reorderingAllowed);
JTable 行列 相关设置:
// 设置所有行的行高
void setRowHeight(int rowHeight)
// 设置指定行的行高
void setRowHeight(int row, int rowHeight)
/**
- 设置当手动改变某列列宽时,其他列的列宽自动调整模式,可选值:
-
JTable.AUTO_RESIZE_ALL_COLUMNS 在所有的调整大小操作中,按比例调整所有的列。
-
JTable.AUTO_RESIZE_LAST_COLUMN 在所有的调整大小操作中,只对最后一列进行调整。
-
JTable.AUTO_RESIZE_NEXT_COLUMN 在 UI 中调整了一个列时,对其下一列进行相反方向的调整。
-
JTable.AUTO_RESIZE_OFF 不自动调整列的宽度;使用滚动条。
-
JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS 在 UI 调整中,更改后续列以保持总宽度不变;此为默认行为。
*/
void setAutoResizeMode(int mode)
/*
- 调整列宽
*/
// 先获取到某列
TableColumn tableColumn = jTable.getColumnModel().getColumn(int columnIndex);
// 设置列的宽度、首选宽度、最小宽度、最大宽度
tableColumn.setWidth(int width);
tableColumn.setPreferredWidth(int preferredWidth);
tableColumn.setMinWidth(int minWidth);
tableColumn.setMaxWidth(int maxWidth);
// 调整该列的列宽,以适合其标题单元格的宽度。
tableColumn.sizeWidthToFit();
// 是否允许手动改变该列的列宽
tableColumn.setResizable(boolean isResizable);
// 设置该列的表头名称
tableColumn.setHeaderValue(Object headerValue);
JTable 数据 相关操作:
/*
- 表格数据的简单设置和获取
*/
// 设置表格中指定单元格的数据
jTable.getModel().setValueAt(Object aValue, int rowIndex, int columnIndex);
// 获取表格中指定单元格的数据
Object value = jTable.getModel().getValueAt(int rowIndex, int columnIndex);
- 创建带滚动条的表格
创建带滚动条的表格基本步骤:
// 创建表格
JTable table = new JTable(…);
/* 设置表格相关数据 */
// 设置滚动面板视口大小(超过该大小的行数据,需要拖动滚动条才能看到)
table.setPreferredScrollableViewportSize(new Dimension(int width, int height));
// 创建滚动面板,把 表格 放到 滚动面板 中(表头将自动添加到滚动面板顶部)
JScrollPane scrollPane = new JScrollPane(table);
/* 再把滚动面板 scrollPane 添加到其他容器中显示 */
完整实例代码:
package com.xiets.swing;
import javax.swing.;
import java.awt.;
public class Main {
public static void main(String[] args) {
JFrame jf = new JFrame("测试窗口");
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 创建内容面板
JPanel panel = new JPanel();
// 表头(列名)
String[] columnNames = {"序号", "姓名", "语文", "数学", "英语", "总分"};
// 表格所有行数据
Object[][] rowData = {
{1, "张三", 80, 80, 80, 240},
{2, "John", 70, 80, 90, 240},
{3, "Sue", 70, 70, 70, 210},
{4, "Jane", 80, 70, 60, 210},
{5, "Joe_05", 80, 70, 60, 210},
{6, "Joe_06", 80, 70, 60, 210},
{7, "Joe_07", 80, 70, 60, 210},
{8, "Joe_08", 80, 70, 60, 210},
{9, "Joe_09", 80, 70, 60, 210},
{10, "Joe_10", 80, 70, 60, 210},
{11, "Joe_11", 80, 70, 60, 210},
{12, "Joe_12", 80, 70, 60, 210},
{13, "Joe_13", 80, 70, 60, 210},
{14, "Joe_14", 80, 70, 60, 210},
{15, "Joe_15", 80, 70, 60, 210},
{16, "Joe_16", 80, 70, 60, 210},
{17, "Joe_17", 80, 70, 60, 210},
{18, "Joe_18", 80, 70, 60, 210},
{19, "Joe_19", 80, 70, 60, 210},
{20, "Joe_20", 80, 70, 60, 210}
};
// 创建一个表格,指定 表头 和 所有行数据
JTable table = new JTable(rowData, columnNames);
// 设置表格内容颜色
table.setForeground(Color.BLACK); // 字体颜色
table.setFont(new Font(null, Font.PLAIN, 14)); // 字体样式
table.setSelectionForeground(Color.DARK_GRAY); // 选中后字体颜色
table.setSelectionBackground(Color.LIGHT_GRAY); // 选中后字体背景
table.setGridColor(Color.GRAY); // 网格颜色
// 设置表头
table.getTableHeader().setFont(new Font(null, Font.BOLD, 14)); // 设置表头名称字体样式
table.getTableHeader().setForeground(Color.RED); // 设置表头名称字体颜色
table.getTableHeader().setResizingAllowed(false); // 设置不允许手动改变列宽
table.getTableHeader().setReorderingAllowed(false); // 设置不允许拖动重新排序各列
// 设置行高
table.setRowHeight(30);
// 第一列列宽设置为40
table.getColumnModel().getColumn(0).setPreferredWidth(40);
// 设置滚动面板视口大小(超过该大小的行数据,需要拖动滚动条才能看到)
table.setPreferredScrollableViewportSize(new Dimension(400, 300));
// 把 表格 放到 滚动面板 中(表头将自动添加到滚动面板顶部)
JScrollPane scrollPane = new JScrollPane(table);
// 添加 滚动面板 到 内容面板
panel.add(scrollPane);
// 设置 内容面板 到 窗口
jf.setContentPane(panel);
jf.pack();
jf.setLocationRelativeTo(null);
jf.setVisible(true);
}
}
结果展示:
- 表格模型(TableModel)
TableModel 接口指定了 JTable 用于询问表格式数据模型的方法。TableModel 封装了表格中的各种数据,为表格显示提供数据。上面案例中直接使用行数据和表头创建表格,实际上JTable 内部自动将传入的行数据和表头封装成了 TableModel。
只要数据模型实现了 TableModel 接口,就可以通过以下两行代码设置 JTable 显示该模型:
TableModel myData = new MyTableModel();
JTable table = new JTable(myData);
TableModel 接口中的方法:
package javax.swing.table;
import javax.swing.;
import javax.swing.event.;
public interface TableModel {
/** 返回总行数 */
public int getRowCount();
/** 返回总列数 */
public int getColumnCount();
/** 返回指定列的名称(表头名称) */
public String getColumnName(int columnIndex);
/** 针对列中所有的单元格值,返回最具体的超类。JTable 使用此方法来设置列的默认渲染器和编辑器。 */
public Class<?> getColumnClass(int columnIndex);
/** 判断指定单元格是否可编辑 */
public boolean isCellEditable(int rowIndex, int columnIndex);
/** 获取指定单元格的值 */
public Object getValueAt(int rowIndex, int columnIndex);
/** 设置指定单元格的值 */
public void setValueAt(Object aValue, int rowIndex, int columnIndex);
/** 添加表格模型监听器 */
public void addTableModelListener(TableModelListener l);
/** 移除表格模型监听器 */
public void removeTableModelListener(TableModelListener l);
}
JRE 中常用的已实现 TableModel 接口的类有两个:
(1)javax.swing.table.AbstractTableModel
此抽象类为 TableModel 接口中的大多数方法提供默认实现。它负责管理侦听器,并为生成 TableModelEvents 以及将其调度到侦听器提供方便。要创建一个具体的 TableModel 作为 AbstractTableModel 的子类,只需提供对以下三个方法的实现:
public int getRowCount();
public int getColumnCount();
public Object getValueAt(int row, int column);
(2)javax.swing.table.DefaultTableModel
这是 TableModel 的一个实现,它使用一个 Vector 来存储单元格的值对象,该 Vector 由多个 Vector 组成。DefaultTableModel 还增加了许多方便操作表格数据的方法,例如 支持 添加 和 删除 行列 等操作。
下面使用 AbstractTableModel 创建一个表格:
package com.xiets.swing;
import javax.swing.;
import javax.swing.table.AbstractTableModel;
import java.awt.;
public class Main {
public static void main(String[] args) {
JFrame jf = new JFrame("测试窗口");
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
// 创建内容面板,使用边界布局
JPanel panel = new JPanel(new BorderLayout());
// 使用表格模型创建一个表格
JTable table = new JTable(new MyTableModel());
// 把 表头 添加到容器顶部(使用普通的中间容器添加表格时,表头 和 内容 需要分开添加)
panel.add(table.getTableHeader(), BorderLayout.NORTH);
// 把 表格内容 添加到容器中心
panel.add(table, BorderLayout.CENTER);
jf.setContentPane(panel);
jf.pack();
jf.setLocationRelativeTo(null);
jf.setVisible(true);
}
/**
* 表格模型实现,表格显示数据时将调用模型中的相应方法获取数据进行表格内容的显示
*/
public static class MyTableModel extends AbstractTableModel {
/**
* 表头(列名)
*/
private Object[] columnNames = {"姓名", "语文", "数学", "英语", "总分"};
/**
* 表格所有行数据
*/
private Object[][] rowData = {
{"张三", 80, 80, 80, 240},
{"John", 70, 80, 90, 240},
{"Sue", 70, 70, 70, 210},
{"Jane", 80, 70, 60, 210},
{"Joe", 80, 70, 60, 210}
};
/**
* 返回总行数
*/
@Override
public int getRowCount() {
return rowData.length;
}
/**
* 返回总列数
*/
@Override
public int getColumnCount() {
return columnNames.length;
}
/**
* 返回列名称(表头名称),AbstractTableModel 中对该方法的实现默认是以
* 大写字母 A 开始作为列名显示,所以这里需要重写该方法返回我们需要的列名。
*/
@Override
public String getColumnName(int column) {
return columnNames[column].toString();
}
/**
* 返回指定单元格的显示的值
*/
@Override
public Object getValueAt(int rowIndex, int columnIndex) {
return rowData[rowIndex][columnIndex];
}
}
}
结果展示:
用鼠标点击相应的单元格,会发现单元格不