TableCellRenderer e como atualizar o plano de fundo da célula sem usar JTable.repaint ()

  • é possível atualizar o fundo baseado em valor de fora corretamente, sem forçar para repintar table.repaint();

  • Baseado, usado e testado com grande código feito por kleopatra e Hovercraft Full Of Eels

  • válido para Java6 / 7, porque não houve alterações nas APIs

insira a descrição da imagem aquiinsira a descrição da imagem aquiinsira a descrição da imagem aqui

meu SSCCE funciona corretamente, repintado por 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(); } }); } } 

EDITAR

@Devolus escreveu Você testou o que eu postei? Eu peguei esse trecho do meu próprio código de trabalho, acabei de remover o material entre eles, pois não é relevante para a resposta. Estou usando o Java 6 aqui e isso funciona para mim.

 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); } 
  • causado

insira a descrição da imagem aqui

  • não importa Java6 / 7

do código (razão para postar um 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

  • de WinXp (para todos Win OS não use Nimbus, Renderer é muito engraçado, nunca vi isso, ótimo !!! como isso é possível)

insira a descrição da imagem aqui

EDIT3:

note que estou simplificado código como é possível, testado antes da minha pergunta aqui, em seguida, lançando Componente de renderização para JComponent / JLabel não funciona também (com JLabel.repaint () / setOpaque ())

O problema ocorre quando você altera o item selecionado. Você tem alguma interação implícita entre sua checkbox de combinação e sua tabela (o item selecionado da checkbox de combinação influencia a maneira como a tabela é pintada).

Quando o comboboxpopup está oculto, ele aciona automaticamente uma repintura da área flutuante (o RepaintManager só repintará a área flutuante, não a tabela completa). Mas nesse meio tempo, você mudou a forma como as células da mesa são pintadas (as primeiras células não são mais pintadas de vermelho porque não correspondem mais à seleção). No entanto, o gerente de repintura força a repintar apenas uma pequena área da mesa que não cobre completamente os glóbulos vermelhos, daí você vê essas falhas visuais.

Aqui estão duas soluções que posso propor:

  • Adicione um ActionListener à checkbox de combinação e invoque table.repaint() (fácil de fazer)
  • Altere seu modelo de tabela e chame fireTableCellUpdated(row, column) para as células relevantes.

SSCCE para a segunda solução:

 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 updatedCells = new ArrayList(); 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(); } }); } } 

Para corrigir seu problema específico, você pode adicionar table.repaint () como mostrado.

No entanto, para redesenhar a tabela corretamente, você deve atualizá-la do lado de fora. Neste exemplo, você deve adicionar um ouvinte de evento na checkbox de combinação e atualizá-lo de lá.

 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; }