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

时间:2011-05-12 05:56:05

标签: java swing jmenu jmenuitem changelistener

现在,我有一个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

2 个答案:

答案 0 :(得分:6)

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

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

  • 精炼要求:当JMenuItem刚刚通过键盘和鼠标突出显示时,执行doSomething。

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

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

  • 当前的宠儿:无法使用监听器,覆盖...
  • 当前偏差:Action,MenuListener ......

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

答案 1 :(得分:4)

这是预期的多态行为。 JMenuItemisSelected()方法继承自AbstractButton,而Jmenu中的相同方法被覆盖,因此如果菜单当前被选中(突出显示),则返回true。 “