为什么我的ChangeListener只对JMenu作出反应,而对JMenuItem不作出反应?

现在,我有一个JMenu,还有一些JMenuItems。 当JMenu和JMenuItem的状态更改为“selected”时,我希望我的程序执行一些操作。 我不使用MouseLitener的MouseOver,因为我希望用户也可以使用键盘在菜单中导航。 现在,我写了这个监听器:

class MenuItemListener implements ChangeListener { @Override public void stateChanged(ChangeEvent arg0) { JMenuItem item = (JMenuItem) arg0.getSource(); if(item.isSelected()) System.out.println(item.getText()+" pressed!"); } } 

当我将这个监听器添加到JMenu时,它可以正常工作,但是当我将它添加到JMenuItem时,没有任何反应……当我删除if语句以便监听器对两者做出反应时,当菜单被选中并且被选中时我对JMenu以及对于JMenuItem。 所以,正如我所见,JMenuItem无法“通过”isSelected()测试……但是什么可能是个问题呢? :S

没有任何方向的违法行为,这只是有历史的问题之一

  • 初始要求:当鼠标hover在JMenuItem上时执行某些操作
  • 最初每个人都亲爱的:MouseListener
  • 初始偏离建议(感谢@mKorbel!):buttonModel上的ChangeListener,检查翻转属性

  • 精致要求:当JMenuItem刚刚突出显示时,通过键盘和鼠标两者来完成。

  • 精制的darling:buttonModel上的ChangeListener,未指定属性
  • 精炼偏差:ActionListener

  • 当前要求:当JMenu或JMenuItem“选中”属性发生更改时,执行doSomething。

  • 当前的宠儿:无法用听众完成,覆盖……
  • 当前偏差:Action,MenuListener ……

正确和完整(事后看来,因为还没有提到键盘)答案在第一轮已经有了:一些语义监听器“足够低级”来捕捉状态变化(候选人是翻转,武装,选中,按下buttonModel级别),这使menuItems改变其突出显示的状态。 不幸的是,确切的关系并不为人所知(至少对我而言),没有文件记录(读:懒得我快速找不到任何东西)甚至混淆(再次,对我来说)因为翻转是假的总是(?)对于menuItems

实验主义者的反应是试试:下面是一个代码片段,它监听并记录某些菜单树上的状态变化(只需扔进任意一个menuBar并移动鼠标并通过键盘导航)。

获胜者是: – 使用ChangeListener并检查源是选择还是武装。

  ChangeListener ch = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { if (e.getSource() instanceof JMenuItem) { JMenuItem item = (JMenuItem) e.getSource(); if (item.isSelected() || item.isArmed()) { System.out.println("Highlighted: " + item.getActionCommand()); } } } }; 

适用于键盘和鼠标,包括JMenu和JMenuItem

 //----------- code snippet to track property changes in menuItem/buttonModel // test menu JMenu menu = new JMenu("Sample menu"); menu.setMnemonic('s'); installListeners(menu); // first menuitem JMenuItem other = menu.add("content1"); installListeners(other); // second menuitem other = menu.add("again + "); installListeners(other); // sub JMenu sub = new JMenu("subMenu"); installListeners(sub); menu.add(sub); // menus in sub other = sub.add("first in sub"); installListeners(other); other = sub.add("second in sub"); installListeners(other); getJMenuBar().add(menu); private void installListeners(JMenuItem menu) { menu.getModel().addChangeListener(getChangeListener()); menu.addChangeListener(getChangeListener()); } private ChangeListener getChangeListener() { ChangeListener ch = new ChangeListener() { @Override public void stateChanged(ChangeEvent e) { if (e.getSource() instanceof ButtonModel) { ButtonModel model = (ButtonModel) e.getSource(); System.out.println("from model: " + createStateText(model)); } else if (e.getSource() instanceof JMenuItem) { JMenuItem item = (JMenuItem) e.getSource(); System.out.println(" from item: " + createStateText(item)); } } private String createStateText(ButtonModel model) { String text = model.getActionCommand() + " armed: " + model.isArmed(); text += " selected: " + model.isSelected(); text += " rollover " + model.isRollover(); text += " pressed: " + model.isPressed(); return text; } private String createStateText(JMenuItem model) { String text = model.getActionCommand() + " armed: " + model.isArmed(); text += " selected: " + model.isSelected(); // not supported on JMenuItem nor on AbstractButton // text += " rollover " + model.isRollover(); // text += " pressed: " + model.isPressed(); return text; } }; return ch; } 

这是预期的多态行为。 JMenuItemisSelected()方法inheritance自AbstractButton ,而重写了Jmenu的相同方法,因此如果当前选择(突出显示)菜单,则返回true。