Динамическое изменение включенного состояния пункта меню TrayIcon

У меня есть код, который успешно использует SystemTray, TrayIcon, PopupMenu, MenuItem. Я пытаюсь сделать так, чтобы включенное состояние MenuItem было точным, основываясь на состоянии чего-то, что происходит в нескольких других потоках. У меня есть возможность запустить процесс (который я назвал getUnknownConditionFromTheThreads()), который может сказать мне, нужно ли мне включить или отключить пункт меню в этот конкретный момент времени.

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

Другими словами, пользователь щелкает правой кнопкой мыши значок в области уведомлений, меню отображается с включенным/отключенным состоянием в данный момент, затем запускается метод mouseClicked() и запускается setEnabled(), но уже слишком поздно!

Так что я мог бы попытаться закачать состояние в иконку в трее, чтобы оно было готово заранее, но это означало бы большую сложность, потому что есть много независимых потоков, и никто из них не «знает», какое состояние включения/отключения у пункт меню должен быть.

Мой вопрос: есть ли «хитрость», чтобы включить / отключить элемент всплывающего меню на основе события, сгенерированного пользователем на значке в трее?

Код ниже, как правило, то, что я делаю. Здесь нет ничего «причудливого», просто чтобы показать, что когда пользователь щелкает правой кнопкой мыши, включение/отключение пункта меню не отражается.

Вот как теперь работает код: скажем, по умолчанию для пункта меню включено, и следующий вызов getUnknownConditionFromTheThreads() вернет false. Пользователь увидит, что элемент включен при первом щелчке правой кнопкой мыши. Следующий щелчок правой кнопкой мыши отключит его.

PopupMenu popup = new PopupMenu();
final MenuItem itemToDisable = new MenuItem("Testing");
ActionListener listener = new ActionListener(){
    public void actionPerformed(ActionEvent arg0) {
    .....
    }
};
itemToDisable.addActionListener(listener);
popup.add(itemToDisable);
trayIcon = new TrayIcon(xImg, xMsg, popup);
trayIcon.addActionListener(listener);
trayIcon.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseClicked(MouseEvent e) {
        boolean someCondition = getUnknownConditionFromTheThreads();
        itemToDisable.setEnabled(someCondition);  // Not reflected first time
    }
});
SystemTray.getSystemTray().add(trayIcon);

person Dale    schedule 26.11.2018    source источник


Ответы (2)


Вместо mouseClicked используйте mousePressed:

trayIcon.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        boolean someCondition = getUnknownConditionFromTheThreads();
        itemToDisable.setEnabled(someCondition);  // Reflected first time
    }
});
person Dale    schedule 26.11.2018

Вы также можете попробовать:

PopupMenu popup = new PopupMenu() {
    @Override
    public void show(Component origin, int x, int y) {
        boolean someCondition = getUnknownConditionFromTheThreads();
        itemToDisable.setEnabled(someCondition);  // Reflected first time
        super(origin, x, y);
    }
}
person Perdi Estaquel    schedule 27.11.2018
comment
Спасибо, но этот метод не сработал, когда я щелкнул правой кнопкой мыши значок в трее. Кроме того, я думаю, вы имеете в виду super.show(origin, x, y); - person Dale; 03.12.2018