How to select the first item in JPopupMenu?

In the past, when one made JPopupMenu visible, the first item will be selected by default: http://weblogs.java.net/blog/alexfromsun/archive/2008/02/jtrayicon_updat.html

Currently, the default behavior is a pop-up menu without any item selected. I would like to create JPopupMenu with one element that will be displayed selected and centered under the mouse pointer. I managed to make the element pop up in the center of the mouse, but I JMenuItem refuses to display as if it were selected. If I drag the mouse out of this element and back, it selects correctly.

Any ideas?

Here is my test file:

 import java.awt.Component; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; public class Test extends JFrame { public static void main(String[] args) { JFrame frame = new JFrame(); frame.setSize(800, 600); frame.getContentPane().addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) popupTriggered(e); } @Override public void mouseReleased(MouseEvent e) { if (e.isPopupTrigger()) popupTriggered(e); } private void popupTriggered(MouseEvent e) { JPopupMenu menu = new JPopupMenu(); final JMenuItem item = new JMenuItem("This is a JMenuItem"); menu.add(item); Point point = e.getPoint(); int x = point.x - (item.getPreferredSize().width / 2); int y = point.y - (item.getPreferredSize().height / 2); menu.show((Component) e.getSource(), x, y); } }); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setVisible(true); } } 
+6
java swing
source share
4 answers

Currently, the default behavior is a pop-up menu without selecting an item.

Actually, I would say that this is the correct behavior, at least in Windows. Other non-Java applications do this too. I don’t think it’s worth breaking this agreement, even if there is only one item in the menu. If you think otherwise, you can set the index of choice, as in sean.bright's answer .


So, I finally got the opportunity to try it on Java 1.6.0_11 and found some inconsistent behavior: if the pop-up menu leaves the parent frame, the item is automatically selected; if the popup menu is displayed completely inside the parent frame, nothing is selected. Sounds like a Swing bug, which at least guarantees RFE for consistent behavior.

0
source share

The secret is MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{menu, ...});

 import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; import javax.swing.MenuElement; import javax.swing.MenuSelectionManager; import javax.swing.SwingUtilities; /** * Demonstrates programmatic {@link JMenuItem} selection; * specifically how to make the first item selected by default */ public class TestPopup extends JFrame { public static void main(String[] args) { final JFrame frame = new JFrame("TestPopup"); frame.setSize(640, 480); frame.getContentPane().addMouseListener(new MouseAdapter() { @Override public void mousePressed(MouseEvent e) { if (e.isPopupTrigger()) { popupTriggered(e); } } private void popupTriggered(MouseEvent e) { final JPopupMenu menu = new JPopupMenu(); final JMenuItem item0 = new JMenuItem("JMenuItem 0"); final JMenuItem item1 = new JMenuItem("JMenuItem 1"); menu.add(item0); menu.add(item1); menu.pack(); // use invokeLater or just do this after the menu has been shown SwingUtilities.invokeLater(new Runnable() { public void run() { MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{menu, item0}); } }); int x = (int) ((int) (frame.getSize().width - (menu.getPreferredSize().width / 2.)) / 2.); int y = (int) ((int) (frame.getSize().height - (menu.getPreferredSize().height / 2.)) / 2.); menu.show(frame, x, y); // doesn't work: //item0.setSelected(true); // doesn't work: //menu.getSelectionModel().setSelectedIndex(0); // bingo; see also MenuKeyListener / MenuKeyEvent // MenuSelectionManager.defaultManager().setSelectedPath(new MenuElement[]{menu, item0}); } }); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.setLocationRelativeTo(null); frame.setVisible(true); } } 
+6
source share

MenuSelectionManager.defaultManager () is really a good solution, but it will not work if you try to pre-select the JPopupMenu submenu (it will hide the parent menu). In addition, this will ruin other keyboard navigation behaviors (you cannot press left to hide submenus, etc.)

Unfortunately, in Swing there is no good solution for this question ... My solution is ugly, but unfortunately this work is perfect:

 public static void setMenuSelectedIndex(final JPopupMenu popupMenu, final int index) { SwingUtilities.invokeLater(new Runnable(){public void run() { for (int i=0; i < index+1; i++) { popupMenu.dispatchEvent(new KeyEvent(popupMenu, KeyEvent.KEY_PRESSED, 0, 0, KeyEvent.VK_DOWN, '\0')); } }}); } 

As you can see, I basically mimic the "Down" Key-Key-Presses on a pop-up menu ...

The best solution might not be to simulate VK_DOWN hardcodedly, but to read a pop-up input map and determine which KeyCode means "select the next menu item" - but I think most of us would agree with this hack ...

You can also look at this method, which selects a menu item after selecting it. It uses the previous method.

 public static void setSelectedIndexWhenVisible(final JMenu menu, final int index) { menu.getPopupMenu().addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) { PopupUtils.setMenuSelectedIndex(menu.getPopupMenu(), index); menu.getPopupMenu().removePopupMenuListener(this); } @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { } @Override public void popupMenuCanceled(PopupMenuEvent e) { } }); } 
+1
source share

This is strange.

I tried this with Windows, and with Java 1.5.0_08 and even 1.6.0_07, the first item is selected automatically, as you expected.

So, I tried it with 1.6.0_11 , and it no longer works, the first element is not selected initially. Selecting an item in a selection method does not help.

One workaround (which I'm not at all proud of) is to automatically move the mouse after displaying a pop-up menu using MouseEvent coordinates. Maybe someone had an idea?

 import java.awt.AWTException; import java.awt.Robot; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPopupMenu; public class SelectedPopupMenu extends JFrame { public SelectedPopupMenu() { addMouseListener(new MouseAdapter() { public void mouseClicked(final MouseEvent e) { JPopupMenu popupMenu = new JPopupMenu(); popupMenu.add(new JMenuItem("Test-Item")); popupMenu.add(new JMenuItem("Test-Item-2")); // do not care to really hit the center of the popup popupMenu.show(SelectedPopupMenu.this, e.getX() - 30, e.getY() - 10); try { // shake mouse, so that first element is selected even in Java 1.6.0_11 Robot robot = new Robot(); robot.mouseMove(e.getX() + 1, e.getY()); robot.mouseMove(e.getX(), e.getY()); } catch (AWTException ex) { ex.printStackTrace(); } } }); } public static void main(String[] args) { JFrame frame = new SelectedPopupMenu(); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setSize(800, 600); frame.setVisible(true); } } 
0
source share

All Articles