I am trying to add a universal right click to textfields in my application. I came across a solution where I could add a glass pane on top my frame, make it invisible and register that as a universal mouse listener. If the component is a text field I show the pop up menu, otherwise I redispatch the event. I have pasted the code below...
This example works fine. But when I use this with my application though, I get a stackoverflow error at
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at apple.awt.CWindow._getLocationOnScreen(Native Method)
at apple.awt.CWindow.getLocationOnScreen(CWindow.java:878)
at java.awt.Component.getLocationOnScreen_NoTreeLock(Component.java:1960)
at java.awt.Component.getLocationOnScreen(Component.java:1938)
at javax.swing.SwingUtilities.convertPointToScreen(SwingUtilities.java:364)
at javax.swing.SwingUtilities.convertPoint(SwingUtilities.java:165)
at com.aesthete.csmart.ui.common.components.RightClickGlassPane.redispatchMouseEvent(RightClickGlassPane.java:79)
at com.aesthete.csmart.ui.common.components.RightClickGlassPane.mouseEntered(RightClickGlassPane.java:61)
I understand that every time the mouse is entered on a component the glass pane receives the event and then redispatches. But why is it getting converted into a recursive call?
EDIT:
Just wanted to show everyone how I solved it with Camickr suggestion:
SwingUtilities.invokeLater(new Runnable() {
public void run() {
final JPopupMenu popup = new JPopupMenu();
JMenuItem mnItemCopy = new JMenuItem("Copy", CommonUI.getScaledImage(13, 13, "/images/copy.png"));
JMenuItem mnItemCut = new JMenuItem("Cut", CommonUI.getScaledImage(13, 13, "/images/cut.png"));
JMenuItem mnItemPaste = new JMenuItem("Paste", CommonUI.getScaledImage(13, 13, "/images/paste.png"));
popup.add(mnItemCopy);
popup.add(mnItemCut);
popup.add(mnItemPaste);
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
if(event instanceof MouseEvent) {
MouseEvent mouseevent=(MouseEvent)event;
if(mouseevent.isPopupTrigger()) {
if (mouseevent.getComponent() instanceof JTextField) {
popup.show(mouseevent.getComponent(), mouseevent.getX(), mouseevent.getY());
}
}
}
}
}, AWTEvent.MOUSE_EVENT_MASK);
}
});
I am trying to add a universal right click to textfields in my application.
Check out Global Event LIsteners. Just check the source of the event and do processing as required. No need to redispatch events.
Note, you should NOT assume a right click is the LAF way to display a popup. Read the section from the Swing tutorial on Bringing Up a Popup Menu for a better solution.
Related
I have a simple MouseAdapter that I add to a JMenu. I want the menu to show its contents when moused over, react when clicked on, and hide its contents when the mouse leaves it. Here's where I add the listener:
public final void addGuiReaction(Runnable clickReaction) {
JMenu THIS = this;
this.addMouseListener(new MouseAdapter() {
final Runnable reaction = clickReaction;
final JMenu source = THIS;
#Override
public void mouseClicked(MouseEvent arg0) {reaction.run();}
#Override
public void mouseEntered(MouseEvent arg0) {source.doClick();} // Opens the menu
#Override
public void mouseExited(MouseEvent arg0) {/* Need to "close" the menu */}
});
}
This works just fine for both the reaction and the open when moused over functionality, but I can't figure out how to close it. Tried both setSelected(false) and setPopupMenuVisible(false) but the issue with both is that the menu doesn't open again the next time I mouse over it.
Anyone knows a nice way of closing the menu?
Answering to "How to close the JMenu..."
In place of this:
/* Need to "close" the menu */
You can put this:
source.dispatchEvent(new KeyEvent(source, KeyEvent.KEY_PRESSED, 0, 0, KeyEvent.VK_ESCAPE));
Hence simulate the ESC key press which will trigger the respective Action from the ActionMap of the JMenuBar.
However this will not fully solve your problem as while the keyboard arrow keys will work, you will not be able to use the mouse to select any of the items of the JMenu as trying to enter any of them will trigger the JMenu mouseExited event. You may need to attach a proper mouse event listener to the menu items as well.
I am using NetBeans and am wanting to use one MouseClick event for 3 JLabels. My issue is that in the Designer when I click on Properties - Events, NetBeans wants to add a custom event handler to my code like this
private void jLabel4MouseClicked(java.awt.event.MouseEvent evt) {
// TODO add your handling code here:
}
But all I want is for the Designer to let me use this custom event as my OnClick event for all labels.
public void mousePressed(MouseEvent mEvt) {
JLabel label = (JLabel) mEvt.getSource();
Icon icon = label.getIcon();
//JOptionPane.showMessageDialog(label, icon);
}
I just began using JMenu. To ease into it, I decided to use Netbeans form design tool, which has worked great for all components in this app.
Clicking a top-level menu item works great.
For one menu item, I made a submenu with 3 items, each with a mouse click listener.
Here's relevant code for one of the 3 submenus:
private JMenuItem mnuEditDicAddAllScratch;
mnuEditDicAddAllScratch = new JMenuItem();
private void mnuEditDicAddAllScratchMouseClicked(MouseEvent evt) {
new WordsToAdd(); // never happened
}
mnuEditDicAddAllScratch.addMouseListener(new MouseAdapter() {
public void mouseClicked(MouseEvent evt) {
mnuEditDicAddAllScratchMouseClicked(evt);
}
});
mnuEdit.add(mnuEditDicAddAllScratch);
It didn't work. Clicks ignored.
So I tried an Action listener:
private void mnuEditDicAddAllScratchActionPerformed(ActionEvent evt) {
new WordsToAdd(); // WORKED
}
mnuEditDicAddAllScratch.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
mnuEditDicAddAllScratchActionPerformed(evt);
}
});
And it worked.
So a question is, "Why didn't mouse click listener listen?"
Also, "If I should stay away from mouse click events, why or under what circumstances?"
(And, pre-emptive strike: I should stay away from Netbeans form designer.)
You should use the best tool for the job at hand. This means that for JMenuItems and for JButtons, you should use ActionListeners, not MouseListeners (exceptions notwithstanding). For instance if you disable a button, you want the button to not work, right? This works with ActionListeners but not with MouseListeners.
For the best information on this type of stuff, go to the source: Swing Tutorials.
mnuEditDicAddAllScratch.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
mnuEditDicAddAllScratchActionPerformed();
}
});
I want to get the mouse position of my JFrame. But when mouse is on its child component (such as a table, button that is added to the JFrame) MouseMotion event is no more listening. How can I get the mouse position?
I was trying to make a Sidebar on my Swing application, where sidebar is an undecorated JFrame. I have set to dispose it when mouse exits. But when I move the mouse over a component added to the sidebar, it disappears. Idea may be dumb I am new to Java.
You could implement mouseExited as kleopatra suggests, but do it similar to this:
MouseListener closer = new MouseAdapter() {
public void mouseExited(MouseEvent e) {
// obtain source frame and see if mouse has left it
Container cnt;
if (e.getSource() instanceof JFrame) {
// our frame, no conversion needed
cnt = (Container) e.getSource();
} else {
// inside a descendant
cnt = SwingUtilities.getAncestorOfClass(
JFrame.class, e.getComponent());
// convert mouse event to make it appear
// as if the frame generated it (I think :D)
e = SwingUtilities.convertMouseEvent(
e.getComponent(), e, (Component) cnt);
}
Rectangle r = new Rectangle(cnt.getSize());
if (!r.contains(e.getPoint())) {
cnt.setVisible(false);
// or whatever
}
}
};
This is meant to be set for all descendant components of your sidebar and itself. It should check if your mouse is still inside your sidebar no matter over which of it's children/descendants the mouse is hovering.
You should also consider using an undecorated JDialog instead of a JFrame.
The reason why your sidebar is disappearing might be that you only added a mouse listener to it and not to any of it's children. It might be counter-intuitive, but when your mouse pointer enters a child/descendant of the sidebar, a mouseExited event is generated for the sidebar and then a mouseEntered event is generated for whichever child/descendant the mouse has entered. This is just how Swing mouse events are designed to work and there ain't much you can do about it.
Assuming the use-case in your comment is the real issue to solve, the answer is to implement the mouseExited such that it checks whether the mouse is still somewhere over the frame and hide it only if not.
Something like:
MouseListener closer = new MouseAdapter() {
#Override
public void mouseExited(MouseEvent e) {
Rectangle r = new Rectangle(sideBar.getSize());
if (!r.contains(e.getPoint())) {
sideBar.setVisible(false);
}
}
};
I created a Java app in WindowBuilder for Eclipse. I built a menu and on one of the menu items I added the mouseclicked event.
JMenuItem mitemAbout = new JMenuItem("About");
mitemAbout.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent arg0) {
JOptionPane.showInternalMessageDialog( form, "Message", "title", JOptionPane.PLAIN_MESSAGE);
}
});
mitemHelp.add(mitemAbout);
I put a breakpoint on the JOptionPane line and when I click on the menu item in debug mode it doesn't even get to it.
Am I completely missing a step here?
Although JMenuItem components offer the addMouseListener method (inherited from java.awt.Component) MouseEvents are only processed for the MenuElements own functional use, i.e. any external MouseEvents will have no effect.
For JMenuItem components, use an ActionListener rather than a MouseListener to listen for user events:
mitemAbout.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
...
}
});
or use:
mitemAbout.setAction(myAction);