Почему мой ChangeListener реагирует только на JMenu, а не на JMenuItem? - PullRequest
4 голосов
/ 12 мая 2011

Теперь у меня есть JMenu и некоторые JMenuItems.Я хочу, чтобы моя программа выполняла какие-то действия, когда состояние JMenu и JMenuItem меняется на «выбрано».Я не использую MouseLitener's 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 ]

6 голосов
/ 12 мая 2011

Ни в коем случае не обижайтесь, это только один из вопросов с историей

  • первоначальное требование: что-то сделать, когда мышь находится над JMenuItem
  • для всех, кто дорог: MouseListener
  • первоначальное отклоняющееся предложение (слава @mKorbel!): ChangeListener на buttonModel, проверка свойства ролловера

  • уточненное требование: doSomething, когда JMenuItem простовыделено и клавиатурой, и мышью.

  • уточненный дорогой: ChangeListener для buttonModel, свойство не указано
  • уточненное отклонение: ActionListener

  • текущее требование: сделайте что-нибудь, когда JMenu или JMenuItem «выбрали» свойство изменилось.

  • текущий любимый: нельзя сделать с помощью прослушивателя, переопределить ...
  • текущие отклонения: действие, MenuListener ...

правильный и полный (хотя задним числом, поскольку клавиатура еще не упоминалась) ответ был доступен уже в первом раунде: некоторый семантический слушатель, который «достаточно низкоуровневый», чтобы фиксировать изменения состояния (кандидаты на опрокидывание, вооружены, выбраны), нажатие кнопки «Уровень модели»), при которой элементы меню меняют свое выделенное состояние.К сожалению, точное отношение не очень хорошо известно (по крайней мере для меня), недокументировано (читай: ленивый я не смог найти ничего при быстром взгляде) и даже сбивает с толку (опять же, мне), поскольку опрокидывание всегда ложно (?)for menuItems

Реакция экспериментатора состоит в том, чтобы .. try: ниже приведен фрагмент кода, который прослушивает и регистрирует изменения состояния в каком-либо дереве меню (просто бросьте в произвольную строку меню, перемещайте мышь и перемещайтесь по клавиатуре),

И победителем является: - используйте 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;
}
4 голосов
/ 12 мая 2011

Это ожидаемое полиморфное поведение.Метод isSelected() JMenuItem наследуется от AbstractButton, в то время как тот же метод в Jmenu переопределяется так, что он "возвращает true, если меню выбрано в данный момент(выделено) «.

...