Меню Java на Mac отображается серым цветом при смене фокуса

У меня есть JFrame с JMenuBar, который я разрабатываю и тестирую в системе Mac. В этом JFrame я запрограммировал одно из JMenus для отключения. Однако, когда я переключаю внимание с моего Java-приложения на какую-то другую программу на своем компьютере, а затем возвращаюсь к этому JFrame, происходят странные вещи. Я заметил, что все меню становятся отключенными. Я также заметил, что все меню стали активными. Кто-нибудь может сказать мне, что здесь происходит?

Вот фрагмент кода, который будет воспроизводить ошибку (по крайней мере, на моей машине):

public class MenuProblemExample {

    public static void main(String[] args) {
        System.setProperty("apple.laf.useScreenMenuBar", "true");
        JFrame frame = new JFrame();
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        fileMenu.add(new JMenuItem("open"));
        menuBar.add(fileMenu);
        JMenu editMenu = new JMenu("Edit");
        editMenu.add(new JMenuItem("select all"));
        menuBar.add(fileMenu);
        menuBar.add(editMenu);
        frame.setJMenuBar(menuBar);
        fileMenu.setEnabled(false);
        frame.setVisible(true);        
    }
}

Когда я запускаю это, включенное свойство не стабильно при переключении фокуса на другое окно, а затем обратно.


person Community    schedule 07.12.2012    source источник
comment
Можете ли вы опубликовать SSCCE или скриншот?   -  person Branislav Lazic    schedule 07.12.2012
comment
У меня все работает нормально. Я не пользователь Mac OS, но могу поспорить, что в этой строке кода что-то не так: System.setProperty("apple.laf.useScreenMenuBar", "true"); Зачем вы вообще устанавливаете это свойство?   -  person Branislav Lazic    schedule 07.12.2012
comment
Это приводит к тому, что строка меню фрейма отображается в верхней части экрана, как это делают собственные приложения в операционной системе Mac OSX.   -  person    schedule 07.12.2012
comment
А UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); означает? :)   -  person Branislav Lazic    schedule 07.12.2012
comment
Я не понимаю вашего вопроса. Этого кода нет в моем примере.   -  person    schedule 07.12.2012
comment
Поместите это в свой метод main. Также окружите его блоком try/cath и расскажите, как выглядит ваше меню. P.S. Удалите эту строку System.setProperty("apple.laf.useScreenMenuBar", "true");.   -  person Branislav Lazic    schedule 07.12.2012
comment
Я только что сделал это и закомментировал System.setProperty(apple.laf.useScreenMenuBar, true). Это приводит к тому, что строка меню отображается внутри фрейма (а не в верхней части экрана). В этой ситуации нет проблем с включенным свойством JMenu. Он работает правильно. Но я хочу, чтобы меню было вверху экрана.   -  person    schedule 07.12.2012
comment
В верхней части экрана? Что ты имеешь в виду?   -  person Branislav Lazic    schedule 07.12.2012
comment
Например: monodevelop.com/@api/deki/files/256/ =MacMainMenu.png   -  person    schedule 07.12.2012
comment
Вау... я выхожу. Честно говоря, в настоящее время я понятия не имею, как это решить.   -  person Branislav Lazic    schedule 07.12.2012
comment
Я подозреваю, что это ошибка, но я полагаю, что любой, кто разрабатывал приложение Java для Mac, сталкивался с ней и может указать мне правильное направление для ее исправления.   -  person    schedule 07.12.2012
comment
Я также подозреваю, что часть проблемы заключается в том, что я вызываю setEnabled(false) для элементов JMenu, а не для содержащихся в них элементов JMenuItem. Я не воспроизвел проблему, когда изменил код, чтобы отключить отдельные элементы JMenuItem.   -  person    schedule 07.12.2012
comment
Объекты Swing GUI должны создаваться и управляться только на поток отправки событий.   -  person trashgod    schedule 07.12.2012
comment
@trashgod: не могли бы вы объяснить, почему или дать ссылку на место, где ваш комментарий оправдан? Кроме того, у меня нет ни малейшего представления о том, как выполнить то, что вы предлагаете. Буду признателен за указатели или ссылку.   -  person    schedule 07.12.2012
comment
Я нашел эту статью javaworld.com/ javaworld/jw-08-2007/, который, кажется, имеет отношение к комментарию TrashGod. Я все еще учусь и буду рад любым комментариям или ссылкам на хорошие материалы для чтения.   -  person    schedule 07.12.2012


Ответы (1)


Объекты Swing GUI должны создаваться и управляться только на поток отправки событий.

Приложения Mac, использующие экранную строку меню, изначально отключают меню в фоновом режиме. Ваше приложение должно соответствующим образом включать меню, когда ваше приложение выходит на передний план, используя, например. a WindowListener.

Приложение: Для тестирования в этом исправленном примере добавлена ​​кнопка-переключатель, которая отслеживает состояние пункта меню File > Open.

import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import javax.swing.AbstractAction;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JToggleButton;

/**
 * @see http://stackoverflow.com/a/13756527/230513
 */
public class MenuProblemExample {

    public static void main(String[] args) {
        System.setProperty("apple.laf.useScreenMenuBar", "true");
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                JMenuBar menuBar = new JMenuBar();
                JMenu fileMenu = new JMenu("File");
                final JMenuItem openItem = new JMenuItem("open");
                openItem.setEnabled(false);
                fileMenu.add(openItem);
                menuBar.add(fileMenu);
                JMenu editMenu = new JMenu("Edit");
                editMenu.add(new JMenuItem("select all"));
                menuBar.add(fileMenu);
                menuBar.add(editMenu);
                frame.setJMenuBar(menuBar);
                frame.add(new JToggleButton(new AbstractAction("Toggle") {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        JToggleButton b = (JToggleButton) e.getSource();
                        openItem.setEnabled(b.isSelected());
                    }
                }));
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}
person trashgod    schedule 07.12.2012
comment
org.jhotdraw.samples.draw.Main, приведенный здесь, является примером. - person trashgod; 07.12.2012
comment
Что ж, я, конечно, могу использовать WindowListener, но мне любопытно, что вы говорите, что такое поведение предусмотрено дизайном. Конечно, это меню должно исчезнуть, когда мое приложение не находится в фокусе, но я не понимаю, как вообще желательно, чтобы свойства моих пунктов меню менялись только от перемещения фокуса к другому окну и обратно. Особенно учитывая, что я видел, как это непредсказуемо меняется от всех пунктов меню, внезапно включенных до всех пунктов меню, внезапно отключенных, я думаю, что это ошибка. - person ; 07.12.2012
comment
Я не могу исключить ошибку, но Apple Рекомендации по интерфейсу пользователя определяют управление состоянием включено отдельного элемента. Если вы не работаете с EDT, вы столкнетесь с непредсказуемым поведением. Как только вы попали на EDT, как показано выше, вам будет легче оставаться на нем. - person trashgod; 07.12.2012
comment
Спасибо, что указали на проблему, связанную с работой над потоком диспетчеризации событий. Это было среди вещей, которых я не знал, что я не знал. - person ; 07.12.2012
comment
@AdamCross: это основа, но ее легко упустить из виду. Я думаю, вы правы насчет пунктов и меню. Я обновил пример для справки. - person trashgod; 08.12.2012