简体   繁体   English

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

[英]JButton directly painted into panel does not show background with WindowsLookAndFeel

So, I'm developing a drag-and-drop style visual designer in Java using Swing. 因此,我正在使用Swing开发Java中的拖放式视觉设计器。

Since the components that you see on the designer aren't actual components, only a visual representation (eg buttons can't be clicked, text fields can't accept text, etc) I'm painting them directly on my panel, overriding the methods getX() , getY() , getWidth() and getHeight() . 由于您在设计器上看到的组件不是实际组件,因此仅是视觉表示(例如,无法单击按钮,文本字段不能接受文本等),我直接在面板上绘画它们,覆盖方法getX()getY()getWidth()getHeight()

It works perfectly fine on any LookAndFeel except for WindowsLookAndFeel. 除了WindowsLookAndFeel,它在任何LookAndFeel上都可以正常工作。 There, for some reason, the backgrounds of JButtons are not being painted. 出于某种原因,JButton的背景没有被绘制。 I have to use Windows LookAndFeel for the designer because that's how our software is deployed, and if I use a different LookAndFeel the designer layout will not be the same as our software. 我必须为设计人员使用Windows LookAndFeel,因为这是我们软件的部署方式,如果我使用其他LookAndFeel,则设计人员布局将与我们的软件不同。

I've lost a few hours trying to solve this problem, and I suspect that it's happening because by not adding the JButton on a container, it's native peer has not been instantiated. 我已经花了几个小时试图解决这个问题,并且我怀疑它的发生是因为没有在容器上添加JButton,所以它的本地对等体尚未实例化。 I've tried to create the peer manually, but without success. 我尝试手动创建对等节点,但没有成功。

I have noticed this problem on Windows 7 (With Aero) and Windows 8. If I use the classic theme on Windows 7 it works, so I assume it also works on Windows XP (But I haven't tested this). 我已经在Windows 7(使用Aero)和Windows 8上注意到了这个问题。如果我在Windows 7上使用经典主题,它可以工作,因此我认为它在Windows XP上也可以工作(但我尚未对此进行测试)。 I'm using Java 1.7.0_25-b17 to test this. 我正在使用Java 1.7.0_25-b17对此进行测试。

Here's a sample I've made to show the problem: 这是我用来说明问题的示例:

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

    }
}

Here's the sample using WindowsLookAndFeel: 这是使用WindowsLookAndFeel的示例:
在此处输入图片说明

And here with MetalLookAndFeel: 这里是MetalLookAndFeel:
在此处输入图片说明

As a potential solution. 作为一种潜在的解决方案。 You could use a class like Screen Image to create an image of the button. 您可以使用类似Screen Image的类来创建按钮的图像。 Then just display the image an an Icon on a JLabel an you will have a real component to work with that you can drag around. 然后,只需在JLabel上显示一个图标的图像,您便​​可以使用一个真正的组件来拖动它。

Ok, I found it, thanks to your sugestion @camickr. 好的,我发现了,这要感谢您的推荐@camickr。

All I had to do was call setSize(int width, int height) before painting it. 我要做的就是在绘制它之前调用setSize(int width, int height) Looking at the Component source code, I've found this on the resize method (Called by setSize ): 查看Component源代码,我在resize方法(由setSize调用)上找到了它:

setBoundsOp(ComponentPeer.SET_SIZE);

I assume that this command tells the native component that it's size has changed, and without calling it the background is actually being painted, but with size 0x0. 我假设此命令告诉本地组件它的大小已更改,并且没有调用它实际上是在绘制背景,但是大小为0x0。

So now, instead of creating a class MyButton and overriding the getWidth() and getHeight() methods, all I have to do is the following: 因此,现在,我要做的不是代替创建类MyButton并覆盖getWidth()getHeight()方法,而是:

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

And still paint it on my JPanel. 并仍将其绘制在我的JPanel上。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM