4

我有一个 Swing 应用程序,我需要在其中启用来自不同线程的 JMenu。我在 OSX 上执行此操作,并通过 apple.laf.useScreenMenuBar 使用本机屏幕菜单。自从切换到 java 7 以来,最初禁用的菜单现在从未启用,我不知道为什么。我附上了一个说明问题的小程序。单击 Fixed > Change 菜单项应在短暂暂停后启用测试菜单(应打开和关闭对话框)。

使用 java6 它工作正常。在 java 7 中,菜单未启用。如果我不使用屏幕菜单,它适用于 6 或 7,如果我使用 EventQueue.invokeAndWait,它适用于 6 或 7,但我认为我不需要这样做。

这是一个错误,还是我误解了摆动线程之间的交互应该如何工作?

import java.awt.EventQueue;
import java.awt.event.*;
import javax.swing.*;

public class MainWindow extends JFrame implements ActionListener {

    private JMenu testMenu;

    public MainWindow () {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle("Menu Enable Test");

        JMenuBar bar = new JMenuBar();

        JMenu fixedMenu = new JMenu("Fixed");
        JMenuItem change = new JMenuItem("Change");
        change.addActionListener(this);
        fixedMenu.add(change);
        bar.add(fixedMenu);

        testMenu = new JMenu("Test");
        testMenu.setEnabled(false);
        JMenuItem seeMe = new JMenuItem("Can you see me?");
        testMenu.add(seeMe);

        bar.add(testMenu);

        setJMenuBar(bar);

        setSize(800,600);
        setLocationRelativeTo(null);
        setVisible(true);
    }

    public void makeVisible () {
        testMenu.setEnabled(true);
    }

    public void actionPerformed(ActionEvent ae) {
        new RemoteChanger(this);
    }

    private class RemoteChanger extends JDialog implements Runnable {
        private MainWindow window;

        public RemoteChanger (MainWindow window) {
            super(window);
            setSize(200,100);
            setLocationRelativeTo(window);
            this.window = window;
            setVisible(true);
            Thread t = new Thread(this);
            t.start();
        }

        public void run() {
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {}

            EventQueue.invokeLater(new Runnable() {
                public void run() {
                    window.makeVisible();                   
                }
            });

            setVisible(false);

        }
    }

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

}
4

1 回答 1

0

我认为问题的根源在于您setVisible(false)不在 Swing 线程中。将其移动到invokeLater()调用内部似乎更正确,并为您提供预期的行为。

EventQueue.invokeLater(new Runnable() {
    public void run() {
        window.makeVisible();    
        setVisible(false);
    }
});
于 2013-04-17T18:29:48.120 回答