直接绘制到面板中的JButton不会显示WindowsLookAndFeel的背景

时间:2014-03-07 22:03:59

标签: java swing

所以,我正在使用Swing在Java中开发一个拖放式的可视化设计器。

由于您在设计器上看到的组件不是实际组件,只有可视化表示(例如按钮无法单击,文本字段无法接受文本等)我直接在我的面板上绘制它们,覆盖方法getX()getY()getWidth()getHeight()

除了WindowsLookAndFeel之外,它在任何LookAndFeel上都能正常工作。在那里,由于某种原因,JButtons的背景没有被绘制。我必须为设计人员使用Windows LookAndFeel,因为这是我们软件的部署方式,如果我使用不同的LookAndFeel,设计师布局将与我们的软件不同。

我已经失去了几个小时试图解决这个问题,我怀疑它正在发生,因为没有在容器上添加JButton,它的本地对等体尚未实例化。我试图手动创建对等,但没有成功。

我在Windows 7(使用Aero)和Windows 8上注意到了这个问题。如果我在Windows 7上使用经典主题它可以工作,所以我认为它也适用于Windows XP(但我没有测试过这个)。我正在使用Java 1.7.0_25-b17对此进行测试。

以下是我为展示问题所做的一个示例:

package test;


import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestSwing {

    public static void main(String[] args) {
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { }

        JFrame f = new JFrame();
        f.setSize(300, 150);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        f.getContentPane().setLayout(new BoxLayout(f.getContentPane(), BoxLayout.X_AXIS));
        JPanel p1 = new JPanel();
        p1.setPreferredSize(new Dimension(150, 150));
        p1.setBorder(BorderFactory.createLineBorder(Color.yellow));
        p1.add(new JButton("Test"));
        f.add(p1);

        final MyButton b = new MyButton();
        b.addNotify();

        JPanel p2 = new JPanel() {
            @Override   
            public void paint(Graphics g) {
                super.paint(g);
                b.paint(g);
            }
        };
        p2.setPreferredSize(new Dimension(150, 150));
        p2.setBorder(BorderFactory.createLineBorder(Color.red));

        f.add(p2);
        f.setVisible(true);
    }

    private static class MyButton extends JButton {
        public MyButton() {
            super("Test");
        }

        @Override
        public int getWidth() {
            return 70;
        }
        @Override
        public int getHeight() {
            return 25;
        }

    }
}

以下是使用WindowsLookAndFeel的示例:
enter image description here

这里有MetalLookAndFeel:
enter image description here

2 个答案:

答案 0 :(得分:1)

作为一种潜在的解决方案。您可以使用类似Screen Image的类来创建按钮的图像。然后只需在JLabel上显示一个图标,你将拥有一个可以拖拽的真实组件。

答案 1 :(得分:0)

好的,我找到了它,感谢你的消化@camickr。

我所要做的就是在绘画之前打电话给setSize(int width, int height)。查看组件源代码,我在resize方法(由setSize调用)中找到了这个代码:

setBoundsOp(ComponentPeer.SET_SIZE);

我假设这个命令告诉本机组件它的大小已经改变,并且没有调用它实际上正在绘制背景,但是大小为0x0。

现在,我不是创建一个MyButton类并重写getWidth()getHeight()方法,而是我要做的就是:

final JButton b = new JButton("Test");
b.setSize(70, 25);

还在我的JPanel上画它。