如何正确使用自定义渲染器绘制JTable中的特定单元格?
我的GUI中有一个JTable组件,它显示算法的psuedocode
。 我想通过更改特定单元格的背景然后更改下面的单元格等来强调当前的执行行。
现在我的代码改变了JTable中所有单元格的背景,如下图所示:
我用来存档这个当前状态的代码如下:
class CustomRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { JLabel d = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if((row == 0) && (column == 0)) d.setBackground(new java.awt.Color(255, 72, 72)); return d; } }
然后我调用jTable2.setDefaultRenderer(String.class, new CustomRenderer());
在我的构造函数中。
我认为:
- 在每个String类型的表格单元格上调用此方法。
- 这只会改变位置(0,0)处单元格的颜色
如何修复代码以便只有单元格(0,0)被着色?
在if中添加else子句:
if ((row == 0) && (column == 0)) { d.setBackground(new java.awt.Color(255, 72, 72)); } else { d.setBackground(Color.WHITE); }
请记住,相同的渲染器实例用于绘制所有单元格。
这不是答案(*),对于两个答案的评论都太长了:两者都是正确的,因为else块是确保默认颜色用于不应该突出显示的单元格的重要事项。 他们在如何达到这个目标方面略有不同,两者都具有相同的整体效果:他们错过了任何特殊的颜色,比如选择,焦点,可编辑,d …
他们通过不同的方式达到“未命中”,效果略有不同
setBackground(Color.WHITE);
设置为固定颜色,可能是也可能不是默认的“普通”表格背景
setBackground(null);
设置没有颜色导致显示“正常”背景颜色 – 由于DefaultTableCellRenderer的内部技巧是不透明的实现:-)
问题的基本原因(也称为臭名昭着的颜色内存,TM)是默认渲染器的exception糟糕的实现,使其基本上不可扩展:
/** * Overrides
JComponent.setBackground
to assign * the unselected-background color to the specified color. * * JW: The side-effect is documented and looks innocent enough :-) */ public void setBackground(Color c) { super.setBackground(c); unselectedBackground = c; } // using that side-effect when configuring the colors in getTableCellRendererComp // is what leads to the horrendeous problems // in the following lines of the else (not selected, that is normal background color) Color background = unselectedBackground != null ? unselectedBackground : table.getBackground(); super.setBackground(background);
看到这个,出路(除了使用SwingX及其灵活,干净,强大,一致的.. :-)渲染器支持是@ Hovercraft的反过来:首先进行自定义着色(如果没有预期,则为null)然后调用super:
@Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { if (myHighlightCondition) { setBackground(Color.RED); } else { setBackground(null); } super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); return this; }
(*)毕竟,这个评论导致了答案,忘记了它可以在自定义渲染器级别上修复:-)
顺便说一句:抓住对渲染器的“第一次”调用是非常脆弱的,没有关于哪个单元格会发生的保证,可能是最后一列的最后一行。
您忘记了if块的其他部分,如果不是重要的行,则将背景绘制为默认值的代码:
if (row == 0 && column == 0) { d.setBackground(new java.awt.Color(255, 72, 72)); } else { d.setBackground(null); }
我的SSCCE
import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.*; import javax.swing.table.DefaultTableCellRenderer; public class TestJTable { private static int highlightedRow = 0; private static void createAndShowGui() { String[] columnNames = {"Program"}; Object[][] rowData = {{"Row 1"}, {"Row 2"}, {"Row 3"}, {"Row 4"}, {"Row 1"}, {"Row 2"}, {"Row 3"}, {"Row 4"}, {"Row 1"}, {"Row 2"}, {"Row 3"}, {"Row 4"}}; final JTable myTable = new JTable(rowData , columnNames ); myTable.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); if (row == highlightedRow && column == 0) { c.setBackground(new java.awt.Color(255, 72, 72)); } else { c.setBackground(null); } return c; } }); JFrame frame = new JFrame("TestJTable"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new JScrollPane(myTable)); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent arg0) { highlightedRow++; int rowCount = myTable.getRowCount(); highlightedRow %= rowCount; myTable.repaint(); } }).start(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { public void run() { createAndShowGui(); } }); } }