Nimbus - override color for TableHeader

喜夏-厌秋 提交于 2019-12-07 07:43:19

问题


I would like to override the background color of headers in JTables 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.


回答1:


Here's a possible - but quite ugly - solution.

Nimbus relies heavily on Painters. 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 Painters. 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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!