Making a GUI in Swing (NetBeans 15, Sun JDK 19.0.1), i'm trying to set custom background color for JTable rows and encountered issues with boolean cells, and i can't seem to be able to make the background uniform across all cells. Please note that the following code tries to paint the background for the whole table, but my target is to set the background for one line at a time; this code serves the only purpose of highlighting the weird interaction between Nimbus alternate row coloring and the custom renderers i have personally encountered.
The issue seems vastly documented already, here's what i tried:
First attempt using a custom renderer, like so:
class MyTableRenderer implements TableCellRenderer {
private final TableCellRenderer renderer;
public MyTableRenderer(TableCellRenderer renderer) {
this.renderer = renderer;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
//c.setOpaque(true);
c.setBackground(Color.red);
return c;
}
}
and got this result:
Uncommenting the c.setOpaque(true);
line yields the following:
Second attempt, by means of the method PrepareRenderer()
as documented here, and i made it this way:
tbl_Correction = new JTable() {
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
//((JComponent)c).setOpaque(true);
c.setBackground(Color.red);
return c;
}
};
got the exact same behavior as before, down to the detail of uncommenting the setOpaque
line.
Further reading revealed that the alternate table row coloring is handled by the Nimbus Look&Feel, which NetBeans IDE configured automagically upon creation of the project, so i tried adding this line after the Nimbus configuration:
UIManager.getLookAndFeelDefaults().put("Table.alternateRowColor", Color.GREEN);
which led to this
and to the conclusion that Nimbus might be interfering with the intended cell rendering.
Indeed, removing Nimbus altogether gives me the result i want, but sends the rest of the UI back to the middle ages...
Oddly enough, if i select a cell, the whole row gets the correct background, including the boolean cells:
The last relevant piece of info i found is this, in the javadoc for the setBackground() method: It is up to the look and feel to honor this property, some may choose to ignore it.
which made me dubious this can even work withoud swapping Nimbus for something else.
My conclusion: no matter where i put the rendering instructions, i can only manage to change the background of the booleans that are not on one of the alternating rows, unless the row is selected.
The question: did i miss some major obvious configuration step? Or perhaps is there a way to disable Nimbus's Table alternating row colors? Or again, is this some sort of known issue?
(more SO answers: this is not relevant; this does not work;)
Edit: added SSCCE, though being GUI code made from the IDE is far from short.
package tabletest;
import java.awt.Color;
import java.awt.Component;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
public class NewJFrame extends javax.swing.JFrame {
public NewJFrame() {
initComponents();
// attempt #1
/*
jTable1.setDefaultRenderer(Boolean.class, new MyTableRenderer(jTable1.getDefaultRenderer(Boolean.class)));;
jTable1.setDefaultRenderer(String.class, new MyTableRenderer(jTable1.getDefaultRenderer(String.class)));;
*/
}
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents() {
jScrollPane1 = new javax.swing.JScrollPane();
jTable1 = new javax.swing.JTable() {
//attempt #2
@Override
public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
Component c = super.prepareRenderer(renderer, row, column);
//((JComponent)c).setOpaque(true);
c.setBackground(Color.red);
return c;
}
}
;
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
jTable1.setModel(new javax.swing.table.DefaultTableModel(
new Object [][] {
{ new Boolean(true), new Integer(1), new Float(0.1), "asd"},
{ new Boolean(true), new Integer(2), new Float(0.2), "lol"},
{null, new Integer(3), new Float(0.3), "xd"},
{null, new Integer(4), new Float(0.4), "ftw"},
{null, new Integer(5), new Float(0.5), "wtf"}
},
new String [] {
"bool", "int", "float", "string"
}
) {
Class[] types = new Class [] {
java.lang.Boolean.class, java.lang.Integer.class, java.lang.Float.class, java.lang.String.class
};
public Class getColumnClass(int columnIndex) {
return types [columnIndex];
}
});
jScrollPane1.setViewportView(jTable1);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(59, 59, 59)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(174, Short.MAX_VALUE))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
.addGap(25, 25, 25)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(100, Short.MAX_VALUE))
);
pack();
}// </editor-fold>
public static void main(String args[]) {
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try {
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (ClassNotFoundException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (InstantiationException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
} catch (javax.swing.UnsupportedLookAndFeelException ex) {
java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
}
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable() {
public void run() {
new NewJFrame().setVisible(true);
}
});
}
//attempt #1
class MyTableRenderer implements TableCellRenderer {
private final TableCellRenderer renderer;
public MyTableRenderer(TableCellRenderer renderer) {
this.renderer = renderer;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
Component c = renderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
//c.setOpaque(true);
c.setBackground(Color.red);
return c;
}
}
// Variables declaration - do not modify
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JTable jTable1;
// End of variables declaration
}