JPopupMenu Behavior - java

I prepared a small test case below. My problem is when i right click on the window. JPopupMenu show up but if i click anywhere outside the JWindow menu does not disappear. I have to click somewhere on the window to get rid of it which is not the expected behavior.
EDIT:
after reading akf's answer i switched to JFrame, when frame is in focus and pop up menu is showing it disappears when you click on another window. but if the window does not have focus and you click somewhere menu does not disappear.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
class test {
static class window extends JWindow
implements MouseListener, MouseMotionListener{
JPopupMenu popMenu;
JPanel panel = new JPanel();
Point location;
MouseEvent pressed;
public window(){
addMouseListener( this );
addMouseMotionListener( this );
JLabel label = new JLabel("JWindow", JLabel.CENTER);
initPopMenu();
add(label);
setVisible(true);
setAlwaysOnTop(true);
setLocationRelativeTo(null);
pack();
}
public void initPopMenu(){
popMenu = new JPopupMenu();
JMenuItem item;
item = new JMenuItem( "Title" );
item.setEnabled(false);
popMenu.add(item);
popMenu.addSeparator();
item = new JMenuItem( "Item One" );
popMenu.add(item);
item = new JMenuItem( "Item 2" );
popMenu.add(item);
item = new JMenuItem( "Item 3" );
popMenu.add(item);
}
public void mousePressed(MouseEvent e)
{
pressed = e;
int nModifier = e.getModifiers();
if (((nModifier & InputEvent.BUTTON2_MASK) != 0)||
((nModifier & InputEvent.BUTTON3_MASK) != 0))
popMenu.show( this, e.getX(), e.getY() );
}
public void mouseClicked(MouseEvent e) {
}
public void mouseReleased(MouseEvent e) {}
public void mouseDragged(MouseEvent me){
}
public void mouseMoved(MouseEvent e) {}
public void mouseEntered(MouseEvent e) {}
public void mouseExited(MouseEvent e) {}
}
public static void main(String[] args) {
window dw = new window();
}
}

Take a look at the Java Doc for JWindow.isFocusableWindow
A JWindow cannot be the focused window unless it has an owner and the owner is visible.
You're using the default constructor, so your JWindow has the shared owner asn is not focusable. When it is not focusable, it cannot detect the loss of focus when you click somewhere else.
I changed JWindow to JFrame and added a call to setUndecorated(true); before the call to setVisible and it's working for me. If these changes do not make it work for you, please post the version of Java you are using: java -fullversion

In Java 6 on Windows, I cannot get the popup to even display with the code you have provided. On the other hand, if I change your superclass to JFrame, it works as desired, with the popup going away when I click outside of the window. Is there a reason why you are using JWindow as your superclass and not JFrame? If you wish to have a border-less/title-less window, you can call setUndecorated(true) on your JFrame (before you set visible and pack, of course.)

What about hiding the menu if it's visible from within the MouseExited method?

Related

AddMouseListener into another AddMouseListener

I had a problem while calling two mouse events, one into the other. I wanted to show a second frame (frame2) when the user clicks on a component (component1) from the first frame (frame1), then returns to the previous frame (frame1) if the component2 is clicked on. All this using one file.
This is what I wrote:
component1.addMouseListener(this on);
#Override
public void mouseClicked(MouseEvent e)
{
if(e.getSource() == component1)
{
frame1.dispose();
frame2.setVisible(true);
component2.addMouseListener(new MouseAdapter() {
public void mouseClicked() {
frame2.dispose();
frame1.setVisible(true);
}
});
}
}
The first event works, but not the second.
Thank you for answering.
Here is a fully functional example where there are 2 frames, each with a label that, when clicked, hides one frame and shows the other, done in Java 10. See if this works for you and explain how your code differs from this. Note that I only created 2 MouseListeners, one for each frame. I did not recreate the MouseListener in the other MouseListener's code. Also, I did not dispose the frame, which will likely cause problems. If I had disposed frame1, I would most likely have to create a new JFrame and assign it to the frame1 instance member.
Please note you have to click on the label itself, not somewhere else on the frame.
import javax.swing.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class TwoFrames {
public static void main(String[] args) {
TwoFrames twoFrames = new TwoFrames();
twoFrames.start();
}
private void start() {
setupFrames();
}
JFrame frame1 = new JFrame("Frame 1"),
frame2 = new JFrame("Frame 2");
JLabel component1 = new JLabel("Click me 1"),
component2 = new JLabel("Click me 2");
private void setupFrames() {
frame1.getContentPane().add(component1);
frame2.getContentPane().add(component2);
component1.setOpaque(true);
component2.setOpaque(true);
component1.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
frame1.setVisible(false);
frame2.setVisible(true);
}
});
component2.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
frame2.setVisible(false);
frame1.setVisible(true);
}
});
frame1.setSize(300, 300);
frame2.setSize(400, 400);
frame1.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame2.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
SwingUtilities.invokeLater(() -> frame1.setVisible(true));
}
}
The dispose() method actually destroys the window and so, frame1 should become null and you are most likely getting a null pointer exception.
Consider calling frame1.setVisible(false) and frame2.setVisible(false) instead of the dispose() method.
Also, you could consider using to separate mouse listener objects instead of adding a new mouse listener to component2 when component1 is clicked.

JPopupMenu closes when child popup opens

I have a JComboBox (among other components) inside a JPopupMenu. It turns out that whenever I open the combo box's popup (to select an item), the parent JPopupMenu closes. I've been trying to find a way to override this feature, to no avail.
Does anyone have any suggestions to prevent closing the parent JPopupMenu? Thanks!
that not possible directly, its very hard to override known bug, in other hands Swing doesn't allows two lightwieght popup components in same time
import javax.swing.*;
import java.awt.event.*;
public class Test {
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setSize(400, 400);
frame.setVisible(true);
String[] list = {"1", "2", "3", "4",};
JComboBox comb = new JComboBox(list);
final JPopupMenu pop = new JPopupMenu();
pop.add(comb);
frame.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
System.out.println("mousePressed");
pop.show(e.getComponent(), e.getX(), e.getY());
}
});
}
}
but workaround is very simple use JWindows or un-decorated JDialog with JComboBox instead of JPopup

why the key pressed does not trigger any event?

Following is a program that displays a black screen with a messgage ALARM ! :
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class displayFullScreen extends Window {
private JLabel alarmMessage = new JLabel("Alarm !");
public displayFullScreen() {
super(new JFrame());
setLayout(new FlowLayout(FlowLayout.CENTER));
alarmMessage.setFont(new Font("Cambria",Font.BOLD,100));
alarmMessage.setForeground(Color.CYAN);
add(alarmMessage);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(0,0,screenSize.width,screenSize.height);
setBackground(Color.black);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent ke) {
escapeHandler(ke);
}
});
}
public void escapeHandler(KeyEvent ke) {
if(ke.getKeyCode() == ke.VK_ESCAPE) {
System.out.println("escaped !");
} else {
System.out.println("Not escaped !");
}
}
public static void main(String args[]) {
new displayFullScreen().setVisible(true);
}
}
I have set a key handler in this program . The handler catches the keys pressed when the focus is on window.
When the escape key will be pressed escaped ! should be displayed otherwise !escaped.
But nothing gets displayed,when i press a key. What is the problem ?
Maybe you want a window but you have two problems:
You should extend JWindow, not Window when using a Swing application
Even extending JWindow won't work because a JWindow won't receive KeyEvent unless it is parent JFrame is visible.
So you should be using a JFrame. If you don't want the title bar and borders, then you can use an undecorated JFrame.
Also, you should NOT be using a KeyListener because even on a JFrame key events are only dispatched to the focused component. Instead you should be using Key Bindings. In this case it seems you should be adding the binding to the root pane of the frame.
Extend JFrame instead and get rid of the super call.

Detect mouse click anywhere on window

I've written a JWindow that acts a bit like a fancy menu in my application, popping up when a button is pressed. However, I'd like it to disappear if the user clicks anywhere in the main window. I can of course add a mouse listener to the main window, but that doesn't add it to all the components on the window itself, and looping over all the components seems like a bit of a brute force solution (and can't be guaranteed to work if the components on the window change.)
What's the best way of going about doing something like this?
Try to use Toolkit.getDefaultToolkit().addAWTEventListener(listener, eventMask). Find eventMask that filters only mouse clicks. This AWT listener is global for whole application, so you can see all events that happen.
I'd like it to disappear if the user clicks anywhere in the main window
Add a WindowListener to the child window and then handle the windowDeactiveated() event and invoke setVisible(false) on the child window.
Working example:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class DialogDeactivated
{
public static void main(String[] args)
{
final WindowListener wl = new WindowAdapter()
{
public void windowDeactivated(WindowEvent e)
{
e.getWindow().setVisible(false);
}
};
JButton button = new JButton("Show Popup");
button.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton)e.getSource();
JFrame frame = (JFrame) SwingUtilities.windowForComponent(button);
JDialog dialog = new JDialog(frame, false);
dialog.setUndecorated(true);
dialog.add( new JButton("Dummy Button") );
dialog.pack();
dialog.setLocationRelativeTo( frame );
dialog.setVisible( true );
dialog.addWindowListener( wl );
}
});
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(button, BorderLayout.NORTH);
frame.setSize(400, 400);
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
}

How to prevent a disabled JMenuItem from hiding the menu when being clicked?

In my Java swing application i have noticed that when i click on a disabled JMenuItem in a JPopupMenu it hides the menu, but i i do not want to hide it, as if nothing is clicked. Is there a way to prevent this ?
-----------------------------------> Update: Added Code sample :
JMenuItem saveMenuItem = new JMenuItem();
saveMenuItem.setEnabled(false);
saveMenuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
saveMenuItemActionPerformed();
}
});
add(saveMenuItem);
private void saveMenuItemActionPerformed() {
System.out.println( "Save clicked." );
}
This has been tested and works.
The Look & Feel decides how to handle the mouse events on disabled menu items. Anyway, you can intercept the undesired events by using a custom MenuItem. Simply use that code (copy/paste):
public class CustomMenuItem extends JMenuItem {
public CustomMenuItem(String text) {
super(text);
}
public CustomMenuItem() {
super();
}
protected void processMouseEvent(MouseEvent e) {
if (isEnabled()) super.processMouseEvent(e);
}
}
First, adapt the code to suit your needs (optional).
Finally, replace any JMenuItem with a CustomMenuItem.
That's it!
not sure how to prevent. but you can setVisible(false) to prevent it being displayed. Also if a user clicks on the disable menu no action will take place.
When you are disabling JMenuItem, you should remove the ActionListener associated with that JMenuItem by using
jMenuItem.removeActionListener() method.
If u remove that that action will not call the listener and popup will not be disappeared.
I hope this will help to achieve your target.
did you gave a try at this method:
http://download.oracle.com/javase/6/docs/api/javax/swing/JMenuItem.html#setArmed%28boolean%29
"arm the menu item so it can be selected", which I guess would do the trick if set to false.
In short, you can do this, but you will have to write your own mouse listener, which may require a lot of copy&paste from the jdk source code, which is not a very good idea, and I'm not sure about what license restrictions it will put on your code.
I would start digging from this method:
javax.swing.plaf.basic.BasicMenuItemUI.Handler#mouseReleased
which seems to be the entry point from where the menu handling mechanism hides the popup. I would take a closer look at
javax.swing.plaf.basic.BasicPopupMenuUI.MouseGrabber#stateChanged
EDIT Developing answer by #Burhan Valikarimwala, try this apporach: remove all action listeners from the disabled JMenuItem and store them in some static temp structure (let's say a Map<WeakReference<JMenuItem>, List<MouseListener>>), this way it will not hide the popup. When you make the menu item enabled again, add all the listeners back. Make it into some util method and it will be seamless.
The only solution I could come up with, for your problem of a click on disable JMenuItem causing it to hide is below:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
public class PopupMenuDisableNoCloseTest extends JPanel implements ActionListener
{
public static void main(String[] args)
{
PopupMenuDisableNoCloseTest p = new PopupMenuDisableNoCloseTest();
p.setPreferredSize(new Dimension(200, 300));
p.setBackground(Color.GREEN);
JPanel contentPane = new JPanel();
contentPane.add(p);
final JFrame f = new JFrame();
final JPopupMenu popup = new JPopupMenu();
final JMenuItem menuItem1 = new JMenuItem("A popup menu item");
menuItem1.addActionListener(p);
menuItem1.addMouseListener(new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e)
{
System.out.println(" menuItem1 mousePressed e.getPoint()=" + e.getPoint());
}
#Override
public void mouseReleased(MouseEvent e)
{
System.out.println(" menuItem1 mouseReleased e.getPoint()=" + e.getPoint());
if(!menuItem1.isEnabled())
popup.setVisible(true);
}
});
menuItem1.setEnabled(false);
popup.add(menuItem1);
JMenuItem menuItem2 = new JMenuItem("Another popup menu item");
menuItem2.addActionListener(p);
popup.add(menuItem2);
MouseListener popupListener = new PopupListener(popup);
f.addMouseListener(popupListener);
f.setContentPane(contentPane);
f.setSize(800, 600);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
#Override
public void actionPerformed(ActionEvent e)
{
JMenuItem source = (JMenuItem) (e.getSource());
String s = "Action event detected. Event source: " + source.getText();
System.out.println("s=" + s);
}
static class PopupListener extends MouseAdapter
{
JPopupMenu popup;
PopupListener(JPopupMenu popupMenu)
{
popup = popupMenu;
}
#Override
public void mousePressed(MouseEvent e)
{
maybeShowPopup(e);
}
#Override
public void mouseReleased(MouseEvent e)
{
maybeShowPopup(e);
}
private void maybeShowPopup(MouseEvent e)
{
if(e.isPopupTrigger())
{
popup.show(e.getComponent(),
e.getX(), e.getY());
}
}
}
}
Basically the hiding happens when your release is inside the bounds of the JMenuItem, therefore we are checking if it is disabled then we show popup again. As by this time it is already decided that it will be hidden. I was trying calling super.mouseRelease with a different MouseEvent pointing outside component and consuming the previous one but it helps nothing.
Anyway this solution works.
Enjoy, Boro
I think in Java7 this has been fixed.

Categories

Resources