设置JFrame背景透明使PopupMenu变为空白

3
我的问题类似于这个问题,但我认为有一个更简单的例子。
基本上,通过调用 AWTUtilities.setWindowOpaque(window, false) 使JFrame的背景透明,我的JPopupMenu有时会显示为空白。
public class JavaApplication8 {

    JPopupMenu popup;
    JMenuItem open;
    JLabel bgLabel = new JLabel("testing");

    public static void main(String[] args) {
        // TODO code application logic here

        JFrame window = new JFrame("test");

        URL bgURL = JavaApplication8.class.getResource("images/bg.jpg");
        ImageIcon bg = new ImageIcon(bgURL);

        JavaApplication8 test = new JavaApplication8();
        test.setPopupMenu();
        test.bgLabel.setIcon(bg);

        window.add(test.bgLabel, BorderLayout.CENTER);

        window.setUndecorated(true);
        AWTUtilities.setWindowOpaque(window, false);        
        //window.pack();
        window.setSize(200, 200);
        window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        window.setLocationRelativeTo(null);
        window.setVisible(true);

    }

    public void setPopupMenu(){
        popup = new JPopupMenu();
        open = new JMenuItem("Test");

        popup.add(open);
        this.bgLabel.setComponentPopupMenu(popup);     
    }

}

这里有一个正在发生的情况的图片: enter image description here enter image description here 有趣的是,每当我点击JFrame的右侧时就会出现这种情况。不确定为什么。 请注意,我不确定AWTUtilities.setWindowOpaque(window, false)是否是此问题的原因,但是每当我删除该行代码时,一切似乎都正常。
编辑:如camickr所述,“看起来这是由于弹出菜单没有完全包含在父窗口的边界内。”

奇怪的是...Java 6和Windows 7没有问题,Java 7和Windows 7也没有问题... - MadProgrammer
@MadProgrammer:真的吗?我用的是Java 7和Windows 7,嗯。 - kir
JPopupMenus默认情况下是轻量级的,当它们完全包含在窗口内时。问题出现在弹出菜单的任何部分需要出现在窗口外时 - 它会为弹出菜单创建一个新的重型窗口。这个问题只存在于那个重型窗口中。 - Lunchbox
2个回答

2
每当我点击JFrame的右侧时就会发生这种情况。
看起来是由于弹出菜单没有完全包含在父窗口的边界内导致的。不知道如何解决。
在Java 7中,您可以使用:
frame.setBackground(new Color(0, 0, 0, 0));

为了透明度。


frame.setBackground(new Color(0, 0, 0, 0));AWTUtilities.setWindowOpaque(window, false);有什么区别?不幸的是,这也没有解决问题。 - kir
是的,我刚刚测试了一下。我发现弹出窗口在右侧显示为空白,但如果你将鼠标移动到白色区域,文本就会出现。仍然不知道为什么。不同之处在于,在JDK7中透明度是API的一部分,您不需要使用不受支持的实用程序类。因此,代码可能更好地实现了(尽管这个问题表明相反)。 - camickr
有重要的更改,所有东西都会转到***,容器必须是未装饰的,L&F必须是SystemL&F,重要的是代码排序,此时我建议不要在没有特殊原因或接受白痴限制的情况下使用Java7中的AWTUtilities,有趣的是你可以为第二个容器更改一切,在保持第一个容器不变的情况下。 - mKorbel

2

背景: 我不确定为什么使用透明/半透明背景会导致重量级弹出窗口和它们的绘制出现问题,但事实证明是这样的,无论您是否使用AWTUtilities.setWindowOpaque(window, false)frame.setBackground(new Color(0, 0, 0, 0))

当弹出窗口无法完全适合目标窗口时,将创建HeavyWeightPopup。因此,如果您在窗口底部单击,则也会出现+User2280704您的问题。 LightWeightPopup 没有此问题-因此,菜单可以在您的窗口中间工作。

另外,有趣的是,通常菜单第一次呈现正常,但以下次数不正常。

回答: 我想出了一种解决方法,在任何弹出窗口显示后调用重新绘制即可。只需在启动应用程序时调用以下代码即可。

PopupFactory.setSharedInstance(new PopupFactory() 
{
    @Override
    public Popup getPopup(Component owner, final Component contents, int x, int y) throws IllegalArgumentException
    {
        Popup popup = super.getPopup(owner, contents, x, y);
        SwingUtilities.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                contents.repaint();
            }
        });
        return popup;
    }
});

我还是Java新手,所以我不太明白你的"在启动应用程序时调用以下代码"的意思。能否再详细解释一下?对造成的麻烦感到抱歉。 - kir
没问题,只需将该代码粘贴到某个位置,并确保在第一个弹出窗口出现之前执行它。您只需要调用它一次。因此,在最简单的情况下,您可以将其放在主方法中的任何位置。 - Lunchbox

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接