JPopupMenu仅能激活单个JMenuItem,如何通过上下键切换选中项?
嘿,我来帮你搞定这个JPopupMenu的导航问题!你遇到的setArmed(true)无效的情况,其实是因为JPopupMenu有自己的**选择模型(SingleSelectionModel)**在管理选中状态,直接操作菜单项的armed属性会被它的内部逻辑覆盖。不用删除重插菜单项,咱们用选择模型来处理就好,下面是具体的解决方案:
核心思路
JPopupMenu的getSelectionModel()方法能拿到它的选择管理器,通过这个模型切换选中索引,再配合设置菜单项的armed状态,就能实现上下键的导航效果,而且完全不用重新构建菜单。
修改你的代码
我会在你的PopUpMenu类里添加键盘监听和选择模型的逻辑,你可以直接参考:
1. 添加成员变量存储键盘监听器(方便后续移除)
在PopUpMenu类里加一个KeyAdapter的成员:
private KeyAdapter menuNavigationKeyListener;
2. 在构造函数里添加PopupMenu监听器(用于隐藏时移除键盘监听)
避免文本框在菜单隐藏后还响应上下键的导航逻辑,我们在菜单隐藏时移除监听器:
public PopUpMenu(javax.swing.JTextArea jt, JPopupMenu Pm) { this.jTextArea = jt; Pmenu = Pm; // 添加PopupMenu监听器,隐藏时移除键盘监听 Pmenu.addPopupMenuListener(new PopupMenuListener() { @Override public void popupMenuWillBecomeVisible(PopupMenuEvent e) {} @Override public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { if (menuNavigationKeyListener != null) { jTextArea.removeKeyListener(menuNavigationKeyListener); } } @Override public void popupMenuCanceled(PopupMenuEvent e) { if (menuNavigationKeyListener != null) { jTextArea.removeKeyListener(menuNavigationKeyListener); } } }); }
3. 修改colocar方法,添加键盘导航逻辑
在菜单显示后,给文本框添加键盘监听器,处理上下键的切换:
public void colocar(Component e, int x, int y, ArrayList<Ocurrencia> predicciones) { this.Pmenu.setVisible(false); this.Pmenu.removeAll(); JMenuItem menuItem; for (int i = 0; i < predicciones.size(); i++) { Pmenu.add(menuItem = new JMenuItem(predicciones.get(i).getPrediccion())); menuItem.setHorizontalTextPosition(JMenuItem.RIGHT); menuItem.addActionListener(new ActionListenerImpl(jTextArea)); } this.Pmenu.show(e, x, y); // 初始化默认选中第一个菜单项 int itemCount = Pmenu.getComponentCount(); if (itemCount > 0) { SingleSelectionModel selectionModel = Pmenu.getSelectionModel(); selectionModel.setSelectedIndex(0); ((JMenuItem) Pmenu.getComponent(0)).setArmed(true); } // 创建键盘导航监听器 menuNavigationKeyListener = new KeyAdapter() { @Override public void keyPressed(KeyEvent evt) { int keyCode = evt.getKeyCode(); if (!Pmenu.isVisible()) return; int itemCount = Pmenu.getComponentCount(); if (itemCount == 0) return; SingleSelectionModel selectionModel = Pmenu.getSelectionModel(); int currentIndex = selectionModel.getSelectedIndex(); // 处理向下键 if (keyCode == KeyEvent.VK_DOWN) { int nextIndex = (currentIndex + 1) % itemCount; selectionModel.setSelectedIndex(nextIndex); // 取消当前项的armed状态,设置下一项为armed if (currentIndex != -1 && Pmenu.getComponent(currentIndex) instanceof JMenuItem) { ((JMenuItem) Pmenu.getComponent(currentIndex)).setArmed(false); } JMenuItem nextItem = (JMenuItem) Pmenu.getComponent(nextIndex); nextItem.setArmed(true); } // 处理向上键 else if (keyCode == KeyEvent.VK_UP) { int prevIndex = (currentIndex - 1 + itemCount) % itemCount; selectionModel.setSelectedIndex(prevIndex); // 取消当前项的armed状态,设置上一项为armed if (currentIndex != -1 && Pmenu.getComponent(currentIndex) instanceof JMenuItem) { ((JMenuItem) Pmenu.getComponent(currentIndex)).setArmed(false); } JMenuItem prevItem = (JMenuItem) Pmenu.getComponent(prevIndex); prevItem.setArmed(true); } } }; this.jTextArea.addKeyListener(menuNavigationKeyListener); this.jTextArea.requestFocus(); }
为什么这样有效?
- 先通过
SingleSelectionModel.setSelectedIndex()告诉JPopupMenu当前选中的是哪一项,这是它内部认可的选中状态。 - 然后再设置
setArmed(true),就能让菜单项显示出激活的视觉效果,不会被内部逻辑覆盖。 - 同时我们在菜单隐藏时移除键盘监听器,避免干扰文本框的正常输入操作。
这样就完美实现了上下键切换JPopupMenu选中项的需求,完全不用删除重插菜单项~
内容的提问来源于stack exchange,提问作者Juan Carlos Serrano Pérez
相关产品推荐
相关产品推荐

