Конфликт ActionListener и MouseListener

#java #nullpointerexception #listener #actionlistener #mouselistener

#java #исключение nullpointerexception #прослушиватель #actionlistener #mouselistener

Вопрос:

Я пытаюсь заставить мое приложение сворачиваться на панели задач и восстанавливаться при двойном щелчке на trayIcon . У меня также есть всплывающее меню, в котором есть пункт, который восстанавливает окно при нажатии.

     trayIcon = new TrayIcon(image, "Anything", popup);
    trayIcon.addActionListener(actionListener);
    trayIcon.addMouseListener(mouseListener);
    sysTray.add(trayIcon);
  

И вот код для actionListener и mouseListener :

 private ActionListener actionListener = new ActionListener()
{
   @Override
   public void actionPerformed(ActionEvent e) 
   {
      if (e.getActionCommand().equals("Restore"))
      { // RIGHT CLICK -> RESTORE
        // Do something
      }
   }
};

private MouseListener mouseListener = new MouseListener()
{
   @Override
   public void mouseClicked(MouseEvent e) 
   {
       if (javax.swing.SwingUtilities.isLeftMouseButton(e) amp;amp; e.getClickCount()>1)                                                  
       {  // DOUBLE LEFT MOUSE CLICK
          // Do something
       }
    }
    // Rest of the code
 }
  

Restore Опция всплывающего меню работает нормально, однако, когда я дважды щелкаю по trayIcon в системном трее, я получаю Null Pointer Exception строку at if(e.getActionCommand().equals("Restore"))

Как я могу устранить это и, если возможно, объединить обоих слушателей в один?

Комментарии:

1. Зачем вам вообще нужен прослушиватель мыши или проверка команды action? Прослушиватель действий вызывается только при двойном щелчке / выборе клавиатуры

2. Я проверяю ActionEvent, потому что у меня есть более одного пункта меню, и мне нужно различать их, однако я опустил код для остальных. ActionListener также вызывается, когда я выбираю один из пунктов меню. Однако вы правы насчет MouseListener, на самом деле я ищу способ реализовать MouseListener в ActionListener.

3. Мне лично не нравится практика использования одного ActionListener для разных действий. Одна из причин заключается в том, что он выдает одну и ту же информацию во всех событиях, даже если это неприменимо. Это один из таких случаев — TrayIcon просто не заполняет ActionCommand . Решение, которое я реализовал, состояло в использовании single RestoreListener , который просто восстановил фрейм без каких-либо проверок, и поместил этот прослушиватель в только пункт меню restore и TrayIcon.

4. Хорошо, я сделал, как вы сказали, и это работает с небольшим недостатком. Теперь, когда я дважды щелкаю по значку TrayIcon, окно восстанавливается, однако у него нет фокуса, в отличие от опции «Восстановить», которая восстанавливает окно и обеспечивает фокус, хотя они оба выполняют по существу один и тот же код. Есть обходные пути?

5. Интересно… К сожалению, я не смогу протестировать какие-либо решения до понедельника, но: вы пытались requestFocus() использовать фрейм через WindowListener ?

Ответ №1:

Примечание. Этот ответ взят из беседы с OP в комментариях, и некоторые решения были получены из OP

TrayIcon Не заполняет ActionCommand поле при запуске события, следовательно, код завершает работу с NPE.

Поскольку значок в трее вызывает его ActionListener только при двойном щелчке или при аналогичном действии (с клавиатуры), вы можете создать RestoreListener , который вообще не проверяет это условие и используется только со значком в трее и пунктом меню «Восстановить».

 private ActionListener restoreListener = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // Do the actual restoration
    }
};
  

И фактически добавление его к элементам…

 trayIcon = new TrayIcon(image, "Anything", popup);
trayIcon.addActionListener(restoreListener);

MenuItem restoreMenuItem = new MenuItem(...);
restoreMenuItem.addActionListener(restoreListener);
  

Кажется, что это ведет себя немного иначе, чем MouseListener то, что оно не помещает окно сверху, это можно исправить, вызвав toTop() его.