例子
实现下图效果:
import javax.swing.*;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
import java.awt.*;
public class TableHeaderCenterExample extends JFrame {
protected DefaultTableModel tableModel;
public TableHeaderCenterExample() {
super("表头居中的JTable示例");
initUI();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(700, 400);
setLocationRelativeTo(null);
}
private void initUI() {
// JTable采用MVC设计模式,表头、数据封装在 DefaultTableModel 中
// 定义表格列名
String[] columnNames = {"文件名", "状态", "操作"};
// 创建表格模型(最后一个参数表示不可编辑)
tableModel = new DefaultTableModel(columnNames, 0) {
@Override
public boolean isCellEditable(int row, int column) {
// 只有删除按钮列可编辑(否则按钮无法处理事件)
return column == 2;
}
// 设置列数据类型,确保按钮能正确渲染
// @Override
// public Class<?> getColumnClass(int column) {
// return (column == 2) ? JButton.class : String.class;
// }
};
// 2. 创建表格
// JTable table = new JTable(model);
JTable table = new JTable();
table.setModel(tableModel);
//设置列宽度,必须调用 table.setModel(tableModel) 后才能执行
// 获取列模型
TableColumnModel columnModel = table.getColumnModel();
// 方式1:固定列宽(最常用)
columnModel.getColumn(0).setPreferredWidth(800); // 文件名:200像素
// columnModel.getColumn(1).setPreferredWidth(50); // 大小:80像素
TableColumn column2 = columnModel.getColumn(1);
column2.setPreferredWidth(220); // 首选宽度
column2.setMinWidth(120); // 最小宽度(不能再小)
column2.setMaxWidth(120); // 最大宽度(不能再大)
// columnModel.getColumn(2).setPreferredWidth(50); // 类型:120像素
// 方式2:设置最小/最大宽度(限制拉伸范围)
TableColumn column3 = columnModel.getColumn(2);
column3.setPreferredWidth(100); // 首选宽度
column3.setMinWidth(100); // 最小宽度(不能再小)
column3.setMaxWidth(100); // 最大宽度(不能再大)
// 设置单元格居中显示
// 创建居中渲染器
DefaultTableCellRenderer headerRenderer = new DefaultTableCellRenderer();
headerRenderer.setHorizontalAlignment(SwingConstants.CENTER); // 水平居中
headerRenderer.setVerticalAlignment(SwingConstants.CENTER); // 垂直居中
column2.setCellRenderer(headerRenderer);
// 为第三列设置按钮渲染器和编辑器
column3.setCellRenderer(new ButtonRenderer());
// 点击表格时,会触发表格的编辑事件,而要想触发渲染的按钮的事件,还需要通过修改表格的默认编辑器来实现
column3.setCellEditor(
new ButtonEditor(new JCheckBox())
);
// 添加示例数据
addTableRow("document.txt", "已处理");
addTableRow("image.png", "未处理");
addTableRow("data.csv", "处理中");
addTableRow("archive.zip", "已处理");
// 5. 添加到滚动面板
JScrollPane scrollPane = new JScrollPane(table);
getContentPane().add(scrollPane);
}
public void addTableRow(String file, String status) {
// 每行数据:文件名、状态、删除按钮(按钮文本会被渲染器忽略)
tableModel.addRow(new Object[]{
file,
status,
"移除"
});
}
// 按钮渲染器:负责在单元格中显示按钮
private class ButtonRenderer extends JButton implements TableCellRenderer {
public ButtonRenderer() {
setOpaque(true);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus,
int row, int column) {
// 设置按钮文本
setText((value == null) ? "删除" : value.toString());
// 选中行时高亮按钮背景
// setBackground(isSelected ? table.getSelectionBackground() : table.getBackground());
return this;
}
}
// 按钮编辑器:处理按钮点击事件
private class ButtonEditor extends DefaultCellEditor {
private JButton button;
private String label;
private boolean isPushed;
private int selectedRow;
public ButtonEditor(JCheckBox checkBox) {
super(checkBox);
button = new JButton();
button.setOpaque(true);
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
fireEditingStopped(); // 停止编辑状态
}
});
}
@Override
public Component getTableCellEditorComponent(JTable table, Object value,
boolean isSelected, int row, int column) {
label = (value == null) ? "删除" : value.toString();
button.setText(label);
isPushed = true;
selectedRow = row; // 记录当前行
return button;
}
@Override
public Object getCellEditorValue() {
if (isPushed) {
// 确认删除
int confirm = JOptionPane.showConfirmDialog(
table,
"确定要移除 " + tableModel.getValueAt(selectedRow, 0) + " 吗?",
"警告",
JOptionPane.YES_NO_OPTION
);
if (confirm == JOptionPane.YES_OPTION) {
// 从表格模型中移除行
tableModel.removeRow(selectedRow);
}
}
isPushed = false;
return label;
}
@Override
public boolean stopCellEditing() {
isPushed = false;
return super.stopCellEditing();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
new TableHeaderCenterExample().setVisible(true);
});
}
}
注意
JTable 必须放在 JScrollPanel 中,才能显示表头
遍历数据
方式1:通过TableModel遍历(推荐)
private void traverseByModel(ActionEvent e) {
StringBuilder sb = new StringBuilder();
sb.append("通过模型遍历结果:\n");
// 获取行数和列数
int rowCount = tableModel.getRowCount();
int colCount = tableModel.getColumnCount();
// 遍历所有行和列
for (int row = 0; row < rowCount; row++) {
sb.append("第").append(row + 1).append("行:");
for (int col = 0; col < colCount; col++) {
// 获取单元格数据
Object value = tableModel.getValueAt(row, col);
sb.append(value).append(" | ");
}
sb.append("\n");
}
JOptionPane.showMessageDialog(this, sb.toString());
}
方式2:通过JTable组件遍历(受UI状态影响)
private void traverseByTable(ActionEvent e) {
StringBuilder sb = new StringBuilder();
sb.append("通过表格组件遍历结果:\n");
// 获取行数和列数
int rowCount = dataTable.getRowCount();
int colCount = dataTable.getColumnCount();
// 遍历所有行和列
for (int row = 0; row < rowCount; row++) {
sb.append("第").append(row + 1).append("行:");
for (int col = 0; col < colCount; col++) {
// 获取单元格数据(注意:这里的row是视图行号,可能与模型行号不同)
Object value = dataTable.getValueAt(row, col);
sb.append(value).append(" | ");
}
sb.append("\n");
}
JOptionPane.showMessageDialog(this, sb.toString());
}
清空数据
tableModel.setRowCount(0);
修改值
将第1行第2列的单元格修改为 转换成功:
tableModel.setValueAt("转换成功",0, 1);
