Swing表格列渲染关联另一列值的优化实现方案问询
Swing表格跨列依赖渲染的优雅实现方案
针对Swing表格中某一列渲染(前景色、背景色)依赖另一列值的需求,我们可以通过枚举+策略模式+自定义数据模型的组合方案,规避过程式代码、强制类型转换与不合理依赖,实现更易维护、符合开闭原则的代码结构。
核心设计思路
- 用枚举替代硬编码的条件字符串,避免拼写错误与松散的字符串判断
- 为每种条件定义独立的渲染策略类,将颜色逻辑与业务数据解耦
- 自定义TableModel封装业务数据,提供安全的行数据访问方式,避免依赖列索引
代码实现步骤
1. 定义业务数据模型与枚举
首先封装业务数据,用枚举表示条件类型:
// 业务数据类,封装一行的所有信息 public class DataEntry { private Level level; private int value; public DataEntry(Level level, int value) { this.level = level; this.value = value; } public Level getLevel() { return level; } public int getValue() { return value; } } // 枚举替代硬编码的条件字符串,绑定对应的渲染策略 public enum Level { HIGH(new HighLevelStrategy()), LOW(new LowLevelStrategy()), MEDIUM(new MediumLevelStrategy()); private final RenderStrategy strategy; Level(RenderStrategy strategy) { this.strategy = strategy; } public RenderStrategy getRenderStrategy() { return strategy; } }
2. 定义渲染策略接口与实现
创建统一的渲染策略接口,每种条件对应一个实现类:
// 渲染策略接口,定义颜色获取方法 public interface RenderStrategy { Color getBackground(boolean isSelected); Color getForeground(boolean isSelected); } // High级别对应的渲染策略 public class HighLevelStrategy implements RenderStrategy { @Override public Color getBackground(boolean isSelected) { return isSelected ? Color.RED.darker() : Color.RED; } @Override public Color getForeground(boolean isSelected) { return Color.WHITE; } } // Low级别对应的渲染策略 public class LowLevelStrategy implements RenderStrategy { @Override public Color getBackground(boolean isSelected) { return isSelected ? Color.GREEN.darker() : Color.GREEN; } @Override public Color getForeground(boolean isSelected) { return Color.BLACK; } } // Medium级别对应的渲染策略 public class MediumLevelStrategy implements RenderStrategy { @Override public Color getBackground(boolean isSelected) { return isSelected ? Color.YELLOW.darker() : Color.YELLOW; } @Override public Color getForeground(boolean isSelected) { return Color.BLACK; } } // 默认策略,处理未定义的条件 public class DefaultStrategy implements RenderStrategy { @Override public Color getBackground(boolean isSelected) { return isSelected ? Color.GRAY : Color.WHITE; } @Override public Color getForeground(boolean isSelected) { return isSelected ? Color.WHITE : Color.BLACK; } }
3. 自定义TableModel
自定义模型封装数据,提供安全的行数据访问,避免渲染器直接依赖列索引:
public class CustomTableModel extends AbstractTableModel { private final List<DataEntry> data = new ArrayList<>(); private final String[] columnNames = {"Condition", "Value"}; @Override public int getRowCount() { return data.size(); } @Override public int getColumnCount() { return columnNames.length; } @Override public String getColumnName(int column) { return columnNames[column]; } @Override public Object getValueAt(int rowIndex, int columnIndex) { DataEntry entry = data.get(rowIndex); return switch (columnIndex) { case 0 -> entry.getLevel().name(); case 1 -> entry.getValue(); default -> null; }; } // 提供直接获取整行业务对象的方法 public DataEntry getEntryAt(int row) { return data.get(row); } public void addEntry(DataEntry entry) { data.add(entry); fireTableRowsInserted(data.size() - 1, data.size() - 1); } }
4. 实现自定义单元格渲染器
渲染器通过自定义模型获取业务对象,直接调用对应策略获取颜色,无需过程式判断:
public class ValueCellRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); // 从自定义模型获取业务对象,避免依赖列索引与强制类型转换 CustomTableModel model = (CustomTableModel) table.getModel(); DataEntry entry = model.getEntryAt(row); RenderStrategy strategy = entry.getLevel().getRenderStrategy(); this.setBackground(strategy.getBackground(isSelected)); this.setForeground(strategy.getForeground(isSelected)); return this; } }
5. 主程序使用示例
public class ElegantTableRendererExample { public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("优雅的表格渲染示例"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(600, 400); CustomTableModel model = new CustomTableModel(); model.addEntry(new DataEntry(Level.HIGH, 100)); model.addEntry(new DataEntry(Level.LOW, 20)); model.addEntry(new DataEntry(Level.MEDIUM, 50)); model.addEntry(new DataEntry(Level.HIGH, 80)); model.addEntry(new DataEntry(Level.LOW, 10)); JTable table = new JTable(model); table.getColumnModel().getColumn(1).setCellRenderer(new ValueCellRenderer()); frame.add(new JScrollPane(table)); frame.setVisible(true); }); } }
方案优势
- 无过程式判断:用枚举+策略模式替代if-else/switch,新增条件只需扩展枚举与策略类,符合开闭原则
- 避免强制类型转换:通过自定义模型直接获取业务对象,无需从表格单元格取数据后强制转换
- 减少不合理依赖:不再硬编码列索引,枚举替代字符串避免拼写错误,渲染逻辑与业务数据解耦
- 易维护扩展:修改颜色样式只需调整对应策略类,新增业务状态无需改动原有渲染逻辑
内容的提问来源于stack exchange,提问作者Heneh
相关产品推荐
相关产品推荐

