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

Java 直接绘制到面板中的JButton不显示具有WindowsLookAndFeel的背景,java,swing,Java,Swing,因此,我正在使用Swing在Java中开发一个拖放式的可视化设计器 由于您在设计器上看到的组件不是实际的组件,只有一个可视的表示(例如,按钮不能单击,文本字段不能接受文本等),所以我直接在面板上绘制它们,覆盖方法getX(),getY(),getWidth()和getHeight() 除了WindowsLookAndFeel之外,它在任何外观和感觉上都工作得非常好。由于某种原因,JButtons的背景没有被绘制出来。我必须对设计器使用Windows LookAndFeel,因为我们的软件就是这样

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

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

除了WindowsLookAndFeel之外,它在任何外观和感觉上都工作得非常好。由于某种原因,JButtons的背景没有被绘制出来。我必须对设计器使用Windows LookAndFeel,因为我们的软件就是这样部署的,如果我使用不同的LookAndFeel,设计器的布局将与我们的软件不同

我花了几个小时试图解决这个问题,我怀疑这是因为没有在容器上添加JButton,它的本机对等点没有被实例化。我试图手动创建对等体,但没有成功

我在Windows7(带有Aero)和Windows8上注意到了这个问题。如果我在Windows7上使用经典主题,它就可以工作,所以我假设它在WindowsXP上也可以工作(但我还没有测试过)。我正在使用Java1.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的示例:

这里是MetalLookAndFeel:

作为一种潜在的解决方案。您可以使用类似的类来创建按钮的图像。然后,只需在JLabel上显示一个图标,您就可以使用一个真正的组件进行操作,您可以拖动它。

好的,我找到了,多亏了您的sugestion@camickr

我所要做的就是在绘制它之前调用
setSize(int-width,int-height)
。查看组件源代码,我在
resize
方法(由
setSize
调用)中发现了这一点:

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

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

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

还把它涂在我的JPanel上。

哦,好主意。以下是使用WindowsLookAndFeel:和使用MetalLookAndFeel:Done的示例。请注意,当我在Windows L&F上尝试您的代码时,它在Windows 7上运行良好。谢谢。这很有趣,我已经在我的工作场所在Windows7上进行了测试,明天我会再试一次。也许这与Java版本有关?您使用的是哪种版本?现在我使用的是具有Java 7的Eclipse,但出于某种原因(与您的程序无关),我只能在符合Java 6的情况下运行Windows 7上的“1.7.0_10。我和你有同样的问题。这看起来确实像是版本问题。多亏了这个ScreenImage类,我发现了这个问题。我所要做的就是在绘制按钮之前调用setSize()。我会将此作为一个答案,提供更多细节,但同样,声誉不够):
final JButton b = new JButton("Test");
b.setSize(70, 25);