
本教程旨在解决java swing `jtable`中选中行颜色无法持久化的问题。通过引入一个隐藏的布尔型数据模型列来存储行的“永久选中”状态,结合自定义 `tablecellrenderer` 实现基于该状态的条件着色,并利用 `mouselistener` 响应用户交互来更新状态,从而使选中的行即使在失去焦点后也能保持特定颜色。
在Java Swing应用程序开发中,JTable 是一个常用的组件,用于显示和编辑表格数据。然而,默认情况下,JTable 的行选中颜色是临时的,一旦用户点击其他行或表格失去焦点,前一个选中行的颜色就会恢复到默认状态。这在某些场景下可能不符合需求,例如需要标记多行作为“已选择”或“已处理”的状态。本教程将详细介绍如何实现 JTable 选中行的持久化着色效果。
要实现 JTable 选中行的持久化着色,我们需要突破 JTable 默认的临时选中状态管理机制。核心思路可以概括为以下三步:
首先,我们需要创建一个 DefaultTableModel,并在其中包含一个额外的布尔列。这个列在 JTable 的视图中应该是不可见的。
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumnModel;
import javax.swing.JTable;
// ... 在 ChangeRowColorPanel 类中 ...
private static final String[] COLUMN_NAMES = { "One", "Two", "Three", "Selected" };
private DefaultTableModel model = new DefaultTableModel(COLUMN_NAMES, 0);
private JTable table = new JTable(model);
public ChangeRowColorPanel() {
// ... 其他初始化代码 ...
// 移除最后一列("Selected"列)的视图,使其不可见
TableColumnModel columnModel = table.getColumnModel();
columnModel.removeColumn(columnModel.getColumn(columnModel.getColumnCount() - 1));
// 填充初始数据
int max = 5;
for (int i = 0; i < max; i++) {
Object[] row = new Object[COLUMN_NAMES.length];
for (int j = 0; j < COLUMN_NAMES.length - 1; j++) {
row[j] = (int) (100 * Math.random());
}
row[COLUMN_NAMES.length - 1] = false; // 初始时,所有行都未被“永久选中”
model.addRow(row);
}
// ... 其他布局代码 ...
}在上述代码中,COLUMN_NAMES 数组的最后一个元素 "Selected" 对应着我们将要隐藏的布尔列。通过 table.getColumnModel().removeColumn(...) 方法,我们将其从表格的视图中移除,但它仍然存在于 DefaultTableModel 中,可以用于存储状态。
接下来,创建一个继承自 DefaultTableCellRenderer 的自定义渲染器。在这个渲染器中,我们将重写 getTableCellRendererComponent 方法,根据隐藏列的值来设置行的背景颜色。
import java.awt.Color;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableModel;
@SuppressWarnings("serial")
class RowColorRenderer extends DefaultTableCellRenderer {
private static final Color SELECTED_COLOR = Color.PINK; // 定义持久化选中时的颜色
public RowColorRenderer() {
setOpaque(true); // 确保渲染器是不透明的,以便背景颜色能够显示
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
// 调用父类方法获取默认的渲染组件,以保留默认的文本、字体等样式
Component renderer = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
TableModel model = table.getModel();
// 获取隐藏的“Selected”列的索引
int selectedColumnIndex = model.getColumnCount() - 1;
// 从模型中获取当前行的“永久选中”状态
boolean permanentlySelected = (boolean) model.getValueAt(row, selectedColumnIndex);
// 根据状态设置背景颜色
if (permanentlySelected) {
renderer.setBackground(SELECTED_COLOR);
} else {
renderer.setBackground(null); // 使用默认背景色(通常是白色或JTable的默认色)
}
// 如果当前行是JTable的临时选中行,或者具有焦点,也可以在这里额外处理
// 例如:if (isSelected) { renderer.setBackground(table.getSelectionBackground()); }
// 但为了持久化效果,我们主要依赖permanentlySelected
return renderer; // 返回配置好的渲染组件
}
}在 ChangeRowColorPanel 的构造函数中,将这个自定义渲染器应用到表格:
// ... 在 ChangeRowColorPanel 构造函数中 ... table.setDefaultRenderer(Object.class, new RowColorRenderer()); // ...
为了让用户能够通过点击来切换行的“永久选中”状态,我们需要为 JTable 添加一个 MouseListener。
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JTable;
import javax.swing.table.TableModel;
class MyMouse extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
JTable table = (JTable) e.getSource();
int selectedRow = table.getSelectedRow(); // 获取当前点击的行索引
if (selectedRow >= 0) { // 确保有行被选中
TableModel model = table.getModel();
int selectedColumnIndex = model.getColumnCount() - 1; // 隐藏列的索引
// 获取当前行的“永久选中”状态并进行反转
boolean currentSelectedState = (boolean) model.getValueAt(selectedRow, selectedColumnIndex);
model.setValueAt(!currentSelectedState, selectedRow, selectedColumnIndex);
// 通知表格重新绘制,以便渲染器能更新颜色
table.repaint();
}
}
}在 ChangeRowColorPanel 的构造函数中,将这个监听器添加到表格:
// ... 在 ChangeRowColorPanel 构造函数中 ... table.addMouseListener(new MyMouse()); // ...
为了方便测试,我们将上述组件整合到一个完整的Swing应用程序中:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.*;
import javax.swing.table.*;
public class TestTableRowColor {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
ChangeRowColorPanel mainPanel = new ChangeRowColorPanel();
JFrame frame = new JFrame("JTable行持久化着色示例");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
@SuppressWarnings("serial")
class ChangeRowColorPanel extends JPanel {
private static final String[] COLUMN_NAMES = { "数据一", "数据二", "数据三", "Selected" };
private DefaultTableModel model = new DefaultTableModel(COLUMN_NAMES, 0);
private JTable table = new JTable(model);
public ChangeRowColorPanel() {
// 1. 隐藏“Selected”列
TableColumnModel columnModel = table.getColumnModel();
columnModel.removeColumn(columnModel.getColumn(columnModel.getColumnCount() - 1));
// 2. 设置自定义渲染器
table.setDefaultRenderer(Object.class, new RowColorRenderer());
// 3. 添加鼠标监听器
table.addMouseListener(new MyMouse());
// 填充示例数据
int maxRows = 10;
for (int i = 0; i < maxRows; i++) {
Object[] row = new Object[COLUMN_NAMES.length];
for (int j = 0; j < COLUMN_NAMES.length - 1; j++) {
row[j] = (int) (100 * Math.random());
}
row[COLUMN_NAMES.length - 1] = false; // 初始状态为未选中
model.addRow(row);
}
setLayout(new BorderLayout());
add(new JScrollPane(table));
}
}
class MyMouse extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
JTable table = (JTable) e.getSource();
int selectedRow = table.getSelectedRow();
if (selectedRow >= 0) {
TableModel model = table.getModel();
int selectedColumnIndex = model.getColumnCount() - 1; // 隐藏列索引
// 切换选中状态
boolean currentState = (boolean) model.getValueAt(selectedRow, selectedColumnIndex);
model.setValueAt(!currentState, selectedRow, selectedColumnIndex);
// 重新绘制表格以应用新的颜色
table.repaint();
}
}
}
@SuppressWarnings("serial")
class RowColorRenderer extends DefaultTableCellRenderer {
private static final Color SELECTED_COLOR = new Color(255, 220, 230); // 淡粉色作为选中颜色
public RowColorRenderer() {
setOpaque(true);
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
Component renderer = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
TableModel model = table.getModel();
int selectedColumnIndex = model.getColumnCount() - 1;
// 获取行的持久化选中状态
boolean permanentlySelected = (boolean) model.getValueAt(row, selectedColumnIndex);
// 根据持久化状态设置背景色
if (permanentlySelected) {
renderer.setBackground(SELECTED_COLOR);
} else {
// 如果JTable当前选中了该行(临时选中),且未被持久化选中,则使用JTable的默认选中背景色
// 否则,使用默认背景色(null表示JTable的背景色)
renderer.setBackground(isSelected ? table.getSelectionBackground() : null);
}
// 设置前景颜色以保持文本可见性
renderer.setForeground(isSelected ? table.getSelectionForeground() : table.getForeground());
return renderer;
}
}通过在 JTable 的数据模型中引入一个隐藏的布尔列来存储行的“永久选中”状态,并结合自定义 TableCellRenderer 和 MouseListener,我们成功地实现了 JTable 选中行的持久化着色效果。这种方法将行的选中状态与视图分离,使得状态管理更加灵活和可控,为用户提供了更丰富的交互体验。这种技术不仅限于颜色,也可以扩展到自定义字体、图标或其他视觉效果,以满足更复杂的业务需求。
以上就是JTable选中行持久化着色教程的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号