TableCellRenderer y cómo actualizar el fondo de la celda sin usar JTable.repaint ()

  • es posible actualizar el fondo basado en el valor desde el exterior correctamente, sin forzar para table.repaint(); pintar table.repaint();

  • Basado, usado y probado con un gran código hecho por Kleopatra y Hovercraft Full Of Eels

  • válido para Java6 / 7, porque no hubo ningún cambio en las API

enter image description hereenter image description hereenter image description here

mi SSCCE funciona correctamente, 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 escribió ¿Has probado lo que publiqué? Tomé este fragmento de mi propio código de trabajo, simplemente eliminé el material entremedio ya que no es relevante para la respuesta. Estoy usando Java 6 aquí y esto funciona para mí.

 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

enter image description here

  • no importa Java6 / 7

del código (razón para publicar un 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

  • desde WinXp (para todos los Win OS no utilizo Nimbus, Renderer está ahí muy divertido, nunca lo había visto, ¡¡¡qué bien es esto posible)

enter image description here

EDIT3:

note que el código simplificado es posible, probado antes de mi pregunta aquí, y luego fundir Componente de representación en JComponent / JLabel no funciona también (con JLabel.repaint () / setOpaque ())

El problema ocurre cuando cambias el elemento seleccionado. Tiene alguna interacción implícita entre su cuadro combinado y su tabla (el elemento seleccionado del cuadro combinado influye en la forma en que se pinta la tabla).

Cuando se oculta el comboboxpopup, se desencadena automáticamente el repintado de la zona suspendida (el RepaintManager solo volverá a pintar el área suspendida, no la tabla completa). Pero, mientras tanto, ha cambiado la forma en que se pintan las celdas de la mesa (las primeras celdas ya no se pintan en rojo porque ya no coinciden con la selección). Sin embargo, el gerente de repintado obliga a volver a pintar solo una pequeña área de la tabla que no cubre por completo los glóbulos rojos, por lo que puede ver esos fallos visuales.

Aquí hay 2 soluciones que puedo encontrar:

  • Agregue un ActionListener al cuadro combinado e invoque table.repaint() (fácil de hacer)
  • Cambie su modelo de tabla y llame a fireTableCellUpdated(row, column) para las celdas relevantes.

SSCCE para la segunda solución:

 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 solucionar su problema en particular, puede agregar table.repaint () como se muestra.

Sin embargo, para volver a dibujar correctamente la tabla, debe actualizarla desde el exterior. En este ejemplo, debe agregar un detector de eventos en el cuadro combinado y luego actualizarlo desde allí.

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