Come faccio a utilizzare correttamente i renderer personalizzati per dipingere celle specifiche in una tabella J?

Ho un componente JTable nella mia GUI che visualizza psuedocode di un algoritmo. Voglio evidenziare la linea di esecuzione corrente cambiando lo sfondo di una cella particolare e quindi cambiando la cella sottostante e così via.

In questo momento il mio codice cambia gli sfondi su tutte le celle nella mia tabella di testo come mostrato di seguito:

JTable

Il codice che sto usando per archiviare questo stato attuale è il seguente:

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

Quindi chiamo jTable2.setDefaultRenderer(String.class, new CustomRenderer()); nel mio costruttore.

Presumo che:

  • Questo metodo viene chiamato su ogni cella della tabella del tipo String.
  • Che questo cambierebbe solo il colore della cella in posizione (0,0)

Come posso correggere il mio codice in modo che solo la cella (0,0) sia colorata?

Aggiungi un’altra clausola al tuo if :

 if ((row == 0) && (column == 0)) { d.setBackground(new java.awt.Color(255, 72, 72)); } else { d.setBackground(Color.WHITE); } 

Ricorda che la stessa istanza di rendering è usata per dipingere tutte le celle.

Questa non è una risposta (*), troppo lunga per un commento su entrambe le risposte: entrambe sono corrette in quanto il blocco else è l’elemento importante per garantire che il colore predefinito venga usato per le celle che non dovrebbero essere evidenziate. Si sbagliano leggermente nel modo in cui raggiungerlo, entrambi con lo stesso effetto generale: mancano tutti i colors speciali, come fi dovuti alla selezione, messa a fuoco, modificabile, dnd …

Raggiungono quella “miss” con mezzi diversi con effetti leggermente diversi

 setBackground(Color.WHITE); 

set è un colore fisso che può essere o non essere lo sfondo della tabella “normale” di default

 setBackground(null); 

set non ha colore che porta a mostrare il “normale” colore di sfondo – a causa di trucchi interni di DefaultTableCellRenderer implementazione isOpaque 🙂

La ragione di base del problema (noto anche come infame memoria dei colors, TM) è un’implementazione insolitamente ctriggers del renderer di default che lo rende essenzialmente non estendibile:

  /** * 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); 

Vedendo questo, la via d’uscita (oltre all’utilizzo di SwingX e del suo supporto flessibile, pulito, potente, coerente .. 🙂 è @ Hovercraft ma inverso: prima esegui la colorazione personalizzata (o null se non lo vuoi) quindi chiama 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; } 

(*) Dopo tutto, questo commento ha portato ad una risposta, ha dimenticato che è riparabile a livello di renderizzatore personalizzato 🙂

BTW: Catturare la “prima” chiamata al renderer è estremamente fragile, non c’è garanzia su quale cella possa accadere, potrebbe essere l’ultima riga dell’ultima colonna.

Hai dimenticato la tua altra parte del tuo if block, il codice che dipinge lo sfondo al valore predefinito se non è la riga importante:

  if (row == 0 && column == 0) { d.setBackground(new java.awt.Color(255, 72, 72)); } else { d.setBackground(null); } 

Il mio 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 actionPerformsd(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(); } }); } }