I would like to override the background color of headers in JTable
s when using the Nimbus L&F. I'm effectively "theming" the Nimbus L&F, i.e. making small adjustments to it.
Whatever I try it doesn't seem to have effect.
Here's an SSCCS :
public class MyTest {
public static void main(String[] args) {
new MyTest();
}
public MyTest() {
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
Logger.getLogger(MyTest.class.getName()).log(Level.SEVERE, null, ex);
}
UIManager.put("TableHeader.background", Color.RED);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
DefaultTableModel model = new DefaultTableModel(
new Object[][]{
{"hhvt ", "er sdf", "sfdg"},
{"hyshg ", "dh sdf", "jer"}
},
new Object[]{"Col A", "Col B", "Col C"}
);
JTable table = new JTable(model);
setLayout(new BorderLayout());
add(new JScrollPane(table));
}
}
}
Here's the result:
I'm well aware that Nimbus is a Synth L&F so it uses Painters for just about anything. I bet I could override some Painter
in UIManager
but I don't want to redo a Painter from scratch. The Painters in Nimbus are quite advanced, they use gradients and what have you. I would like to take advantage of that. It's just the color I would like to change.
Here's a possible - but quite ugly - solution.
Nimbus relies heavily on Painter
s. The reason why Nimbus looks good is because it uses gradients, shadows and what not. That's the job of the Painter
. We really, really don't want to do our own Painters. The Nimbus Painters are quite complex and produce beautiful results. So we want to leverage them. Not do them ourselves!
Nimbus has a lot of auto-generated source code. All source code is generated off the skin.laf
XML file (which is in the JDK source) but the XML file is not used at runtime. Most of the auto-generated source files are in fact type-specific Painter
s. For example there's a painter class for TableHeaderRendererPainter
(a painter responsible for painting table headers) and so on. The problem is that all auto-generated source code is package-private.
Painters are set when an instance of NimbusLookAndFeel is initialized. They don't change after this.
From skin.laf
file we can see what colors are used for what. In our case we can see it's really the nimbusBlueGrey
color that governs the background color of the table headers. We can't just change the value of nimbusBlueGrey
as that would affect everything in Nimbus that uses this color. So we need to come up with something else. And this is where it gets ugly.
In the specific case we're interested in table headers as they look by default (i.e. when the mouse is not over them, the table is not disabled, the column header is not pressed, etc). So this is what we'll concentrate on below. But the technique would be the same for any other type of special decoration that somebody would want to do.
The technique is to first start up a temporary instance of the NimbusLookAndFeel
. We do this only so we can 'steal' one of the Painters it has generated. We than safe keep this Painter and then start the NimbusLookAndFeel
for real. Now we can replace our specific Painter so that we swap in the one we saved previously.
public class MyTest {
public static void main(String[] args) throws UnsupportedLookAndFeelException {
new MyTest();
}
public MyTest() throws UnsupportedLookAndFeelException {
// Start dummy instance of L&F
NimbusLookAndFeel nimbusTmp = new NimbusLookAndFeel();
Object nimbusBlueGreyOrg = UIManager.get("nimbusBlueGrey"); // original value
UIManager.put("nimbusBlueGrey", Color.RED); // the color we want
try {
UIManager.setLookAndFeel(nimbusTmp);
} catch (UnsupportedLookAndFeelException ex) {
Logger.getLogger(MyTest.class.getName()).log(Level.SEVERE, null, ex);
}
Object painter = UIManager.get("TableHeader:\"TableHeader.renderer\"[Enabled].backgroundPainter");
// We've got what we came for. Now unload the dummy.
UIManager.getLookAndFeel().uninitialize(); // important to avoid UIDefaults change listeners firing
UIManager.put("nimbusBlueGrey", nimbusBlueGreyOrg); // revert
// Load the L&F for real.
UIManager.setLookAndFeel(new NimbusLookAndFeel());
// Swap in the value we saved previously
UIManager.put("TableHeader:\"TableHeader.renderer\"[Enabled].backgroundPainter", painter);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
DefaultTableModel model = new DefaultTableModel(
new Object[][]{
{"hhvt ", "er sdf", "sfdg"},
{"hyshg ", "dh sdf", "jer"}},
new Object[]{"Col A", "Col B", "Col C"}
);
JTable table = new JTable(model);
setLayout(new BorderLayout());
add(new JScrollPane(table));
}
}
}
Not proud of this, but it works. Anyone with better ideas ?
来源:https://stackoverflow.com/questions/26840096/nimbus-override-color-for-tableheader