JTable使用setDefaultRenderer动态修改多行背景色问题求解
我几乎搜遍了全网也没能找到适配我需求的可行方案。我现有一个JTable组件,需要动态修改选中的多行的背景色,同时不能影响其他已经被修改过背景色的行。
颜色修改的触发逻辑绑定在右键ContextMenu的JMenuItem的actionListener上,如下方截图所示:
目前我尝试过的代码如下:
JMenu highlightMenu = new JMenu("Highlight"); // Add null for (Color color : Arrays.asList(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA, Color.PINK, Color.GRAY)) { JMenuItem x = new JMenuItem(); x.setOpaque(true); x.setBackground(color); highlightMenu.add(x); x.addHierarchyListener(e -> x.setText(tab.getTable() .getValueAt(tab.getTable().getSelectedRow(), tab.getTable().getColumn("Server").getModelIndex()).toString())); x.addActionListener(e -> IntStream.of(tab.getTable().getSelectedRows()) .forEach(row -> ((Component) tab.getTable().getModel().getValueAt(row, 0)).setBackground(color))); // x.addActionListener(e -> { // IntStream.of(tab.getTable().getSelectedRows()) // .forEach(r -> tab.getTable().setDefaultRenderer(Object.class, new // DefaultTableCellRenderer() { // @Override // public Component getTableCellRendererComponent(JTable table, Object value, // boolean isSelected, // boolean hasFocus, int row, int column) { // Component comp = super.getTableCellRendererComponent(table, value, // isSelected, hasFocus, row, column); // if (r == row) { // comp.setBackground(color); // } else { // comp.setBackground(null); // } // return comp; // } // })); // tab.getTable().repaint(); // }); }
如果大家有可行的解决方案,恳请分享,万分感谢!😁
编辑0
我清理了过多的历史编辑内容,添加调试日志后发现表格运行表现完全不符合预期,调试输出截图如下:
说明:我暂未找到表格被重复迭代5次的原因,理论上每个JMenuItem都绑定了独立的事件监听器,选中对应颜色的菜单项时应该仅触发一次事件。
修改后的表格效果截图如下:
对应实现代码如下:
for (Color color : Arrays.asList(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA, Color.PINK, Color.GRAY)) { JMenuItem x = new JMenuItem(); x.setOpaque(true); x.setBackground(color); x.setForeground(Color.BLACK); highlightMenu.add(x); x.addHierarchyListener(e -> x.setText(tab.getTable() .getValueAt(tab.getTable().getSelectedRow(), tab.getTable().getColumn("Server").getModelIndex()).toString())); x.addActionListener(e -> { IntStream.of(tab.getTable().getSelectedRows()).forEach(row -> this.highlightedRows.put(row, color) // this.highlightedRows.put(row, Arrays.asList(Color.BLACK, color) ); tab.getTable().setDefaultRenderer(Object.class, new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); stdOut.println(String.format("%s -> %s", row, highlightedRows.get(row))); if (highlightedRows.get(row) != null) { stdOut.println("XXXXXXX"); component.setBackground(highlightedRows.get(row)); } // if (!isSelected && highlightedRows.containsKey(row)) { // component.setForeground(highlightedRows.get(row).get(0)); // component.setBackground(highlightedRows.get(row).get(1)); // } return component; } }); }); }
显然该实现存在问题。
第N次编辑
我通过以下代码几乎解决了该问题:
for (Color color : Arrays.asList(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA, Color.PINK, Color.GRAY)) { final JMenuItem x = new JMenuItem(); x.setOpaque(true); x.setBackground(color); x.setForeground(Color.BLACK); highlightMenu.add(x); x.addHierarchyListener(e -> x.setText(tab.getTable() .getValueAt(tab.getTable().getSelectedRow(), tab.getTable().getColumn("Server").getModelIndex()).toString())); x.addActionListener(e -> { IntStream.of(tab.getTable().getSelectedRows()) .forEach(row -> this.highlightedRows.put(row, Arrays.asList(Color.BLACK, color))); // row -> this.highlightedRows.put(row, color) tab.getTable().setDefaultRenderer(Object.class, new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { final Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); stdOut.println(String.format("%s -> %s", row, highlightedRows.get(row))); if (highlightedRows.containsKey(row)) { component.setForeground(highlightedRows.get(row).get(0)); component.setBackground(highlightedRows.get(row).get(1)); } else { if (row % 2 == 0) { component.setBackground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.background")); } else { component .setBackground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.alternateRowColor")); } component.setForeground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.foreground")); } if (isSelected) { component .setForeground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.selectionForeground")); component .setBackground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.selectionBackground")); } return component; } }); }); }
目前仅存的问题是事件监听器会被多次触发,解决该问题就能完全实现需求,感谢大家的帮助!😁
内容的提问来源于stack exchange,提问作者aress31
相关产品推荐
相关产品推荐

