The Java on Mac OS X About, Quit and Preferences menu items and events

When writing Java GUI code for the macOS platform (formerly Mac OS X), you'll want to properly handle the Mac About, Quit, and Preferences menu items and events. Fortunately doing this is very simple, and I'll demonstrate that in this "Java on macOS" tutorial.

UPDATE: The technique shown below works on Java versions prior to Java 10. For Java 9 and newer, see my new tutorial, How to enable About, Preferences, and Quit menu items on MacOS and Java 9 and Java 10.

The Mac Application and ApplicationAdapter classes

The key behind properly handling the About, Quit, and Preferences menu items and events comes from using Apple's Application and ApplicationAdapter classes. Using the source code from a Java/Mac application I just created, let's look at how this works.

Update for Mac OS X 10.9 (Mavericks), 10.10 (Yosemite) and newer

I recently learned that Apple has deprecated the approach I’ve used for many years. In short, the new approach is to use the following classes to handle the Mac OS X About, Preferences, and Quit menu items:

  • AboutHandler
  • PreferencesHandler
  • QuitHandler

The following code shows how to set up an AboutHandler. The code is written in Scala, but it is easily translated to Java:

val macApplication = Application.getApplication

// About menu handler
macApplication.setAboutHandler(new AboutHandler {
    def handleAbout(e: AboutEvent) {
        val aboutPanel = new AboutPanel
        JOptionPane.showMessageDialog(myJFrame,
            "Put your long message or JComponent here ...",
            "Put your dialog title here",
            JOptionPane.PLAIN_MESSAGE)
    }
})

As you can see, this is all you have to do:

  • Create an Application instance with Application.getApplication
  • Add an AboutHandler with the Application’s setAboutHandler method
  • Implement the desired behavior in the handleAbout method

I don’t show it here, but Java on the Mac OS X platform also includes these handlers:

  • PreferencesHandler
  • QuitHandler

The Application class also has these methods:

  • setPreferencesHandler
  • setQuitHandler

If you want to know the new way to handle these events on Mac OS X 10.9, 10.10, and newer, I hope these examples have been helpful.

If you’re using older versions of Mac OS X, please read the content below for instructions on how to configure the About, Preferences, and Quit menu items on previous versions of Mac OS X).

The Mac ApplicationAdapter classes

We build a handler for the Mac OS X About, Quit, and Preferences events by extending the Mac ApplicationAdapter class. As you can see from the source code below, when I handle the "Quit" event I close the application with System.exit; and when I receive an About or Preferences event, I display a dialog in response to those events.

In your Java/Mac application you will handle these events differently, this is really all we have to do with the Mac ApplicationAdapter class.

package com.devdaily.desktopshield;

import javax.swing.JOptionPane;
import com.apple.eawt.ApplicationAdapter;
import com.apple.eawt.ApplicationEvent;

/**
 * MacAdapter.java
 * Copyright 2010, Alvin J. Alexander, devdaily.com.
 * 
 * This file is part of the DesktopShield application. This class implements the 
 * Apple/Mac/Java ApplicationAdapter class, specifically the handleQuit
 * method of that class, to help shut down this application properly.
 *
 * The DesktopShield application is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * The DesktopShield application is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the DesktopShield application. If not, see <http://www.gnu.org/licenses/>.
*/
public class MyApplicationAdapter extends ApplicationAdapter
{
  private DesktopShield handler;
  
  public MyApplicationAdapter(DesktopShield handler)
  {
    this.handler = handler;
  }

  public void handleQuit(ApplicationEvent e)
  {
    System.exit(0);
  }

  public void handleAbout(ApplicationEvent e)
  {
    // tell the system we're handling this, so it won't display
    // the default system "about" dialog after ours is shown.
    e.setHandled(true);
    JOptionPane.showMessageDialog(null, "Show About dialog here");
  }

  public void handlePreferences(ApplicationEvent e)
  {
    JOptionPane.showMessageDialog(null, "Show Preferences dialog here");
  }
}

The only real magic in this class is in regards to the handleAbout method. In that method we have to use the ApplicationEvent setHandled method to let the system know that we are handling this event by showing our own custom dialog. If we don't do this, the system will display another default About dialog immediately after ours, and we don't want that.

Next, we'll look at using the Mac Application class.

My Java/Mac Application class

The Mac ApplicationAdapter class is where the actions are handled, but for it to work, we first have to tell the Mac OS X JRE that we've created it. We do this with the Mac Application class, as shown in this Java/Mac source code:

package com.devdaily.desktopshield;

import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import com.apple.eawt.Application;
import com.apple.eawt.ApplicationEvent;

/**
 * DesktopShield.java
 * Copyright 2010, Alvin J. Alexander, devdaily.com.
 * 
 * This is a simple application that displays a black JFrame that occupies the
 * entire screen. While this isn't interesting by itself, I use it as a 
 * "screen" or "shield" that hides my Desktop while I'm working in another
 * application, such as a text editor. By not seeing all the clutter on
 * my desktop, this helps me focus on the text editor.
 * 
 * This file is part of my "DesktopShield" application.
 *
 * The DesktopShield application is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * The DesktopShield application is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with the DesktopShield application. If not, see <http://www.gnu.org/licenses/>.
 *
 */
public class DesktopShield
{
  private JFrame mainFrame;
  private static final String APP_NAME = "DesktopShield";
  
  public static void main(String[] args)
  {
    new DesktopShield();
  }
  
  public DesktopShield()
  {
    // set some mac-specific properties
    System.setProperty("apple.awt.graphics.EnableQ2DX", "true");
    System.setProperty("apple.laf.useScreenMenuBar", "true");
    System.setProperty("com.apple.mrj.application.apple.menu.about.name", APP_NAME);

    // create an instance of the Mac Application class, so i can handle the 
    // mac quit event with the Mac ApplicationAdapter
    Application macApplication = Application.getApplication();
    MyApplicationAdapter macAdapter = new MyApplicationAdapter(this);
    macApplication.addApplicationListener(macAdapter);
    
    // need to enable the preferences option manually
    macApplication.setEnabledPreferencesMenu(true);

    // display the jframe
    SwingUtilities.invokeLater(new Runnable()
    {
      public void run()
      {
        mainFrame = new DesktopShieldFrame();
        mainFrame.pack();
        mainFrame.setVisible(true);
      }
    });
  }

  public void handleQuitEvent(ApplicationEvent e)
  {
    System.exit(0);
  }
  
}

To simplify matters, for the purpose of our discussion, the only code we need to look at are these lines:

// create an instance of the Mac Application class, so i can handle the 
// mac quit event with the Mac ApplicationAdapter
Application macApplication = Application.getApplication();
MyApplicationAdapter macAdapter = new MyApplicationAdapter(this);
macApplication.addApplicationListener(macAdapter);

// need to enable the preferences option manually
macApplication.setEnabledPreferencesMenu(true);

As you can see, we create an instance of the Mac Application class in the first line of code, and then construct our implementation of the ApplicationAdapter class by passing in that reference. We then tell the Application instance that the adapter is the ApplicationListener for our application.

That is all the work I'd expect to have to do, but for some reason we also have to tell our Application instance to enable the Preferences menu item. If we don't do this, it will appear disabled in our application's menu.

I don't know exactly why this is done this way, but I'll guess that for many small applications there are no preferences to set, and this is probably a correct call. Here's the explanation for this from Apple's Application javadoc:

(setEnabledPreferencesMenu(true)) Enables the Preferences item in the application menu. The ApplicationListener receives a callback for selection of the Preferences item in the application menu only if this is set to true.

Because an application may not have a preferences window, by default this is set to false, meaning that the Preferences item in the application menu is grayed out and unselectable. If a Preferences item isn't present, this method adds and enables it.

Java on Mac - handling About, Quit, and Preferences

In summary, that's really all you have to do to handle the Mac About, Quit, and Preferences menu items and events in a "Java/Swing/GUI Mac OS X" application.

If you'd like the source code for a small but complete Java/Swing/Mac application that demonstrates all of this, here's another link to my Java/Mac DesktopShield application, which demonstrates handling these Mac Application, ApplicationAdapter, and About, Quit, and Preferences events.

Finally, here are links to the javadoc for Apple's Application and ApplicationAdapter classes: