4

I have a swing application in which I need to enable a JMenu from a different thread. I'm doing this on OSX and am using the native screen menu via apple.laf.useScreenMenuBar. Since switching to java 7 the initially disabled menus now never become enabled and I can't figure out why. I've attached a small program which illustrates the problem. Clicking on the Fixed > Change menu item should enable the test menu after a brief pause (a dialog should open and close).

Using java6 it works fine. In java 7 the menu is not enabled. If I don't use the screen menu it works in 6 or 7, and if I use EventQueue.invokeAndWait it works in 6 or 7, but I don't think I should need to do this.

Is this a bug, or am I mis understanding how interactions between swing threads should work?

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();
    }

}
mKorbel
  • 109,525
  • 20
  • 134
  • 319
Simon Andrews
  • 317
  • 1
  • 5
  • 10
  • Don't know the answer to your question (am on Windows that does not display the problem), but +1 for posting an SSCCE. – Andrew Thompson Apr 17 '13 at 10:46
  • It works fine on Ubuntu. In any case, The `MainWindow` instance should be made on the Event Dispatch Thread, since it extends a swing component. – Lone nebula Apr 17 '13 at 11:09
  • The `new MainWindow()` line in the `main` method also needs to be inside an `EventQueue.invokeLater`. I don't know if that will resolve the problem, though. – VGR Apr 17 '13 at 11:09
  • I tried putting the MainWindow() call inside an invokeLater call, but the problem still persists as before. – Simon Andrews Apr 17 '13 at 11:13

1 Answers1

0

I think the source of the issue is your setVisible(false) being outside of the Swing thread. Moving it inside of the invokeLater() call seems more correct and gives you the expected behavior.

EventQueue.invokeLater(new Runnable() {
    public void run() {
        window.makeVisible();    
        setVisible(false);
    }
});
martinez314
  • 12,162
  • 5
  • 36
  • 63
  • true could be usage of Thread.sleep(int) instead of Swing Timer – mKorbel Apr 17 '13 at 18:53
  • This still fails if the setVisible(false) goes before the window.makeVisible(). I'm coming to the conclusion that this is a bug in the menu switching code in the OSX LAF when using the screen menu bar. – Simon Andrews Apr 18 '13 at 08:14