Search code examples
javaswingawtjpopupmenutranslucency

Setting the JFrame background transparent making PopupMenu blank


My question is similar to this, but I think has a simpler example.

Basically by calling AWTUtilities.setWindowOpaque(window, false) to make the background of the JFrame transparent, my JPopupMenu sometimes show up as blank.

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

}

Here's an image of what's happening:

enter image description here enter image description here

What's interesting is that this happens whenever I click on the right side of the JFrame. Not sure why. Keep in mind I'm not 100% sure that AWTUtilities.setWindowOpaque(window, false) is indeed the cause of this problem, however whenever I delete that line everything seems to be going fine.

EDIT: As stated by camickr, looks like this happens when the popup menu is not fully contained in the bounds of the parent window.


Solution

  • Background: I'm not sure why using transparent / semi-transparent backgrounds causes problems with heavyweight popups and how they paint, but it does -- regarless of whether or not you use AWTUtilities.setWindowOpaque(window, false) or frame.setBackground(new Color(0, 0, 0, 0)).

    The HeavyWeightPopups get created when a popup can't fit all the way inside the target Window. So +User2280704 your problem also presents if you click at the very bottom of your window. LightWeightPopups do not have this problem -- hence, menus work in the middle of your window.

    Also, interesting to note, typically the menu will render fine the first time, just not the following times.

    Answer: I've come up with a workaround that invokes a repaint after any popups display. Simply invoke the following code when you launch your application.

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