Teena Jain
Teena Jain

Reputation: 11

Issue while closing JPopupMenu with the parent JFrame in maximized state

I have JFrame and a button which opens a JPopupMenu on click event. This JPopupMenu has a JPanel with a button in it. This button is supposed to dispose the JPopupMenu. Which it does as long as the JFrame is not maximized. However when the JFrame is maximized, it closes the Jframe itself.

Any help or pointers towards solving this issue would be appreciated.

(I am using netbeans to develop this.)

//Demo.Java

public class Demo extends javax.swing.JFrame {
    public JPopupMenu menu1;

    public Demo() {
        initComponents();
        menu1 = new JPopupMenu();
        menu1.add(new MyJPanel());    
    }

    @SuppressWarnings("unchecked")
    private void initComponents() {
        jButton1 = new javax.swing.JButton();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);

        jButton1.setText("Open JPopupMenu");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(53, 53, 53)
                .addComponent(jButton1)
                .addContainerGap(224, Short.MAX_VALUE))
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addGap(85, 85, 85)
                .addComponent(jButton1)
                .addContainerGap(192, Short.MAX_VALUE))
        );

        pack();
    }

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        menu1.show(jButton1,0,0);
    }                                        

    public static void main(String args[]) {
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new Demo().setVisible(true);
            }
        });
    }

    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    // End of variables declaration                   
}

Below is the code for MyJpanel.

// MyJPanel.java
package demo;

import java.awt.Window;
import javax.swing.SwingUtilities;

public class MyJPanel extends javax.swing.JPanel {
    public MyJPanel() {
        initComponents();
    }
    @SuppressWarnings("unchecked")
    private void initComponents() {

        jTabbedPane1 = new javax.swing.JTabbedPane();
        jPanel1 = new javax.swing.JPanel();
        jButton1 = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();

        jButton1.setText("Close jPopupMenu");
        jButton1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jButton1ActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(82, 82, 82)
                .addComponent(jButton1)
                .addContainerGap(192, Short.MAX_VALUE))
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addGap(122, 122, 122)
                .addComponent(jButton1)
                .addContainerGap(127, Short.MAX_VALUE))
        );

        jButton1.getAccessibleContext().setAccessibleName("closeParent");

        jTabbedPane1.addTab("tab1", jPanel1);

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 395, Short.MAX_VALUE)
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 272, Short.MAX_VALUE)
        );

        jTabbedPane1.addTab("tab2", jPanel2);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 400, Short.MAX_VALUE)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTabbedPane1)
        );
    }

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        Window w = SwingUtilities.getWindowAncestor(MyJPanel.this);
        w.dispose();
    }                                        

    // Variables declaration - do not modify                     
    private javax.swing.JButton jButton1;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JTabbedPane jTabbedPane1;
    // End of variables declaration                   


}

Upvotes: 1

Views: 565

Answers (2)

Sam
Sam

Reputation: 7868

I assume, you meant:

when the JFrame is maximized, it closes the JPopupMenu itself

The state of the JPopupMenu menu is tightly bound to its ancestor (JFrame), or to the whole windowing system, respectively. It will be hidden on focus loss, mouse/key press... virtually on any state change or input event in any window, just as one would expect it from an ordinary popup menu. Working around this would force you to reopen the menu (trapping the events is hard to impossible). However, this will cause flickering. Note, that a JPopupMenu could rely on fixed basic mechanisms of the unterlying platform windowing system, so one cannot change its behavior through AWT/Swing.

I wanted something similar recently; toggling the visibility of multiple columns of a JTable using the JPopupMenu. But then, as the hacks went overboard, I decided to use a modal JDialog with a JList, containing the entries. Adding a hover effect to a JList (or a JTable) is a portable and reusable effect, which is way less problematic than any hack mentioned above: Change JList item background color on hover

Edit:

SwingUtilities.getWindowAncestor(MyJPanel.this)

Since JPopupMenu is not a Window, getWindowAncestor() cannot find the JpopupMenu which should be closed completely, like this:

public class MyJPanel extends javax.swing.JPanel {
    //...

    /**
     * Try to find and hide the first enclosing JPopupMenu by traversing the
     * parent components
     */
    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
        for (Component parent = this.getParent(); parent != null; parent = parent.getParent())
            if (parent instanceof JPopupMenu) {
                ((JPopupMenu) parent).setVisible(false);
                break;
            }
    }

    //...
}

Upvotes: 2

camickr
camickr

Reputation: 324147

This button is supposed to dispose the JPopupMenu. Which it does as long as the JFrame is not maximized. However when the JFrame is maximized, it closes the Jframe itself.

When you use a popup and the popup extends outside the bounds of the frame the popup is placed in a JWindow because Swing components must be painted in a window. This is why the it works when using your default frame size.

However, if the popup is fully contained in the bounds of the frame then the popup can just be added to the frame and painted. You can easily demonstrate this by just making your frame a little larger (it doesn't need to be maximized) and you will see the difference.

The solution is basically what Sam has already suggested except you don't need to write your own code. Just use:

JPopupMenu popup = (JPopupMenu)SwingUtilities.getAncestorOfClass(JPopupMenu.class, (Component)e.getSource();

if (popup != null)
    popup.setVisible(false);

Upvotes: 1

Related Questions