TableCellRenderer以及如何刷新单元格背景而不使用JTable.repaint()
-
可以正确地刷新基于外部值的背景,而不必强制重绘
table.repaint();
-
基于,使用和由kleopatra和气垫船充分的鳗鱼做的伟大的代码testing
-
对于Java6 / 7是有效的,因为API没有任何变化
我的SSCCE工作正常,通过JTable.repaint()
重新绘制
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.GridLayout; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; public class MyTableAndRenderer { private JFrame frame = new JFrame(); private JPanel panel = new JPanel(); private String[] items = {"Item 1", "Item 2", "Item 3", "Item 4"}; private DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel(items); private JComboBox combo = new JComboBox(comboBoxModel); private JPanel panel1 = new JPanel(); private String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"}; private Object[][] data = { {"Kathy", "Smith", "Item 1", new Integer(5), (false)}, {"John", "Doe", "Item 1", new Integer(3), (true)}, {"Sue", "Black", "Item 3", new Integer(2), (false)}, {"Jane", "White", "Item 3", new Integer(20), (true)}, {"Joe", "Brown", "Item 3", new Integer(10), (false)} }; private DefaultTableModel model = new DefaultTableModel(data, columnNames) { private static final long serialVersionUID = 1L; @Override public Class getColumnClass(int column) { return getValueAt(0, column).getClass(); } }; private JTable table = new JTable(model); public MyTableAndRenderer() { panel.setBorder(new EmptyBorder(10, 0, 2, 0)); panel.add(combo); //@HFOE /*table.setDefaultRenderer(Object.class, new 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); String str = combo.getSelectedItem().toString(); if (value.toString().equalsIgnoreCase(str)) { setBackground(Color.RED); } else { setBackground(null); } return this; } });*/ //@kleopatra /*table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { String str = combo.getSelectedItem().toString(); if (value.toString().equalsIgnoreCase(str)) { setBackground(Color.RED); } else { setBackground(null); } super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); return this; } });*/ table.setDefaultRenderer(Object.class, new 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); String str = combo.getSelectedItem().toString(); if (value.toString().equalsIgnoreCase(str)) { setBackground(Color.RED); table.repaint(); } else { setBackground(null); table.repaint(); } return this; } }); table.getTableHeader().setReorderingAllowed(false); table.setAutoCreateRowSorter(true); table.setPreferredScrollableViewportSize(table.getPreferredSize()); panel1.setLayout(new GridLayout(1, 1, 10, 10)); panel1.add(new JScrollPane(table)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(panel, BorderLayout.NORTH); frame.add(panel1); frame.pack(); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { MyTableAndRenderer fs = new MyTableAndRenderer(); } }); } }
编辑
@Devolus写道你testing了我发布的内容吗? 我从我自己的工作代码中拿出了这个片段,我只是删除了这些内容,因为它与答案无关。 我在这里使用Java 6,这对我有用。
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); ... determine the color value ... cell.setBackground(back); cell.setForeground(fore); }
- 造成
- Java6 / 7并不重要
从代码(理由发布SSCCE)
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.GridLayout; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; public class MyTableAndRenderer { private JFrame frame = new JFrame(); private JPanel panel = new JPanel(); private String[] items = {"Item 1", "Item 2", "Item 3", "Item 4"}; private DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel(items); private JComboBox combo = new JComboBox(comboBoxModel); private JPanel panel1 = new JPanel(); private String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"}; private Object[][] data = { {"Kathy", "Smith", "Item 1", new Integer(5), (false)}, {"John", "Doe", "Item 1", new Integer(3), (true)}, {"Sue", "Black", "Item 3", new Integer(2), (false)}, {"Jane", "White", "Item 3", new Integer(20), (true)}, {"Joe", "Brown", "Item 3", new Integer(10), (false)} }; private DefaultTableModel model = new DefaultTableModel(data, columnNames) { private static final long serialVersionUID = 1L; @Override public Class getColumnClass(int column) { return getValueAt(0, column).getClass(); } }; private JTable table = new JTable(model); public MyTableAndRenderer() { panel.setBorder(new EmptyBorder(10, 0, 2, 0)); panel.add(combo); table.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); String str = combo.getSelectedItem().toString(); if (value.toString().equalsIgnoreCase(str)) { c.setBackground(Color.RED); } else { c.setBackground(null); } return this; } }); table.getTableHeader().setReorderingAllowed(false); table.setAutoCreateRowSorter(true); table.setPreferredScrollableViewportSize(table.getPreferredSize()); panel1.setLayout(new GridLayout(1, 1, 10, 10)); panel1.add(new JScrollPane(table)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(panel, BorderLayout.NORTH); frame.add(panel1); frame.pack(); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { MyTableAndRenderer fs = new MyTableAndRenderer(); } }); } }
EDIT2
- 从WinXp(对于所有的操作系统不要使用Nimbus,Renderer是非常有趣的,从来没有见过,伟大的!!!这怎么可能)
EDIT3:
注意我是尽可能简化代码,在我的问题之前进行testing,然后将渲染组件转换为JComponent / JLabel也不起作用(使用JLabel.repaint()/ setOpaque())
当您更改所选项目时,会发生该问题。 你的combobox和你的表格之间有一些隐式的相互作用(combobox的选定项目会影响表格的绘制方式)。
当comboboxpopup被隐藏时,它会自动触发重新绘制hover区域(RepaintManager只会重新绘制hover区域,而不是整个表格)。 但在此期间,您已经改变了桌子的单元格的绘制方式(第一个单元格不再被涂成红色,因为它们不再与select相匹配)。 然而,重绘pipe理员强制重绘只有一小部分没有完全覆盖红细胞的区域,因此您会看到这些视觉故障。
这里有两个解决scheme,我可以想出:
- 添加一个
ActionListener
到combobox并调用table.repaint()
(容易) - 更改您的表模型,并调用相关单元格的
fireTableCellUpdated(row, column)
。
SSCCE的第二个解决scheme:
import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.List; import javax.swing.DefaultComboBoxModel; import javax.swing.JComboBox; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.SwingUtilities; import javax.swing.border.EmptyBorder; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.DefaultTableModel; public class MyTableAndRenderer { private final class DefaultTableModelExtension extends DefaultTableModel { private static final long serialVersionUID = 1L; private String selected; private DefaultTableModelExtension(Object[][] data, Object[] columnNames) { super(data, columnNames); } @Override public Class getColumnClass(int column) { return getValueAt(0, column).getClass(); } public String getSelected() { return selected; } public void setSelected(String selected) { if (this.selected == null && selected == null || this.selected != null && this.selected.equalsIgnoreCase(selected)) { return; } class Cell { public final int row; public final int column; public Cell(int row, int column) { super(); this.row = row; this.column = column; } } List<Cell> updatedCells = new ArrayList<Cell>(); if (this.selected != null) { for (int i = 0; i < data.length; i++) { Object[] o = data[i]; for (int j = 0; j < o.length; j++) { Object object = o[j]; if (this.selected.toString().equalsIgnoreCase(object.toString())) { updatedCells.add(new Cell(i, j)); } } } } this.selected = selected; if (this.selected != null) { for (int i = 0; i < data.length; i++) { Object[] o = data[i]; for (int j = 0; j < o.length; j++) { Object object = o[j]; if (this.selected.toString().equalsIgnoreCase(object.toString())) { updatedCells.add(new Cell(i, j)); } } } } for (Cell pair : updatedCells) { fireTableCellUpdated(pair.row, pair.column); } } } private JFrame frame = new JFrame(); private JPanel panel = new JPanel(); private String[] items = { "Item 1", "Item 2", "Item 3", "Item 4" }; private DefaultComboBoxModel comboBoxModel = new DefaultComboBoxModel(items); private JComboBox combo = new JComboBox(comboBoxModel); private JPanel panel1 = new JPanel(); private String[] columnNames = { "First Name", "Last Name", "Sport", "# of Years", "Vegetarian" }; private Object[][] data = { { "Kathy", "Smith", "Item 1", new Integer(5), false }, { "John", "Doe", "Item 1", new Integer(3), true }, { "Sue", "Black", "Item 3", new Integer(2), false }, { "Jane", "White", "Item 3", new Integer(20), true }, { "Joe", "Brown", "Item 3", new Integer(10), false } }; private DefaultTableModelExtension model = new DefaultTableModelExtension(data, columnNames); private JTable table = new JTable(model); public MyTableAndRenderer() { panel.setBorder(new EmptyBorder(10, 0, 2, 0)); panel.add(combo); combo.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { updateSelected(); } }); // Need first synch updateSelected(); table.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); String str = combo.getSelectedItem().toString(); if (value.toString().equalsIgnoreCase(str)) { c.setBackground(Color.RED); } else { c.setBackground(null); } return this; } }); table.getTableHeader().setReorderingAllowed(false); table.setAutoCreateRowSorter(true); table.setPreferredScrollableViewportSize(table.getPreferredSize()); panel1.setLayout(new GridLayout(1, 1, 10, 10)); panel1.add(new JScrollPane(table)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.add(panel, BorderLayout.NORTH); frame.add(panel1); frame.pack(); frame.setVisible(true); } private void updateSelected() { model.setSelected((String) combo.getSelectedItem()); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { MyTableAndRenderer fs = new MyTableAndRenderer(); } }); } }
要解决您的特定问题,您可以添加table.repaint(),如图所示。
但是,要正确重绘表格,您应该从外部刷新它。 在这个例子中,你应该在combobox上添加一个事件监听器,然后从那里刷新它。
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { Component cell = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); String str = combo.getSelectedItem().toString(); if (value.toString().equalsIgnoreCase(str)) { cell.setBackground(Color.RED); } else { cell.setBackground(null); } return cell; }