java – Nimbus – 覆盖TableHeader的颜色

我想在使用Nimbus L& F时覆盖JTables中标题的背景颜色.我实际上是在“点击”Nimbus L& F,即对它进行小幅调整.

无论我尝试什么,似乎都没有效果.

这是一个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));
        }

    }

}

这是结果:

我很清楚Nimbus是一个Synth L& F所以它几乎可以使用Painter.我打赌我可以覆盖UIManager中的一些Painter,但我不想从头开始重做一个Painter. Nimbus的画家非常先进,他们使用渐变和你有什么.我想利用这一点.这只是我想改变的颜色.

最佳答案 这是一个可能 – 但相当丑陋 – 的解决方案.

Nimbus严重依赖画家. Nimbus看起来很好的原因是因为它使用了渐变,阴影和不是.这是画家的工作.我们真的,真的不想做我们自己的画家. Nimbus Painters相当复杂,产生了美丽的效果.所以我们想要利用它们.不要自己做!

Nimbus有很多自动生成的源代码.所有源代码都是从skin.laf XML文件(在JDK源中)生成的,但XML文件不在运行时使用.大多数自动生成的源文件实际上是特定于类型的Painters.例如,有一个用于TableHeaderRendererPainter(一个负责绘制表头的画家)的画家类,依此类推.问题是所有自动生成的源代码都是包私有的.

初始化NimbusLookAndFeel实例时设置画家.在此之后他们不会改变.

从skin.laf文件中我们可以看到用于什么颜色.在我们的例子中,我们可以看到它实际上是nimbusBlueGrey颜色,它控制着表头的背景颜色.我们不能只改变nimbusBlueGrey的值,因为这会影响使用这种颜色的Nimbus中的所有内容.所以我们需要提出一些其他的东西.这就是丑陋的地方.

在特定情况下,我们对表标题感兴趣,因为它们默认看起来(即当鼠标不在它们上面时,表没有被禁用,列标题没有按下,等等).所以这就是我们将在下面集中讨论的内容.但是对于任何其他类型的特殊装饰,这种技术都是相同的.

该技术首先启动NimbusLookAndFeel的临时实例.我们这样做只是为了“偷”它生成的一个画家.我们比安全保持这个画家,然后启动NimbusLookAndFeel真实.现在我们可以替换我们特定的Painter,以便我们交换之前保存的那个.

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

    }

}

不为此感到自豪,但它确实有效.谁有更好的想法?

点赞