Reputation: 11
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
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
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