I have a cross-platform Java application with a Swing user interface. On OS X, the application uses the screen menu bar for a more native user experience.
In general, the application creates one JFrame
per document. The screen menu bar must remain consistent across all of these windows. I have tried several ways of doing it, and found only one consistent and performant solution, which is adequate but not perfect. I am posting this question in case anyone else has a better approach, and with the hope that this information helps others.
Some approaches that do not work:
I tried adding the same JMenuBar
to multiple JFrame
instances, but Swing only supports a JMenuBar being attached to a single JFrame at a time, even as a screen menu bar.
I also tested with an AWT MenuBar
rather than a JMenuBar
, but the same phenomenon occurs. And MenuBar
has many limitations compared to JMenuBar
(e.g., no icons), so let's proceed with the requirement that we want a JMenuBar
.
One common solution is to create a copy of the JMenuBar
for each new JFrame
. However, there are at least two problems with that. First, you must keep the menu bars in sync. While you can use listeners to do it, it is a lot of extra code just to handle the OS X platform. However, the second and more serious issue is performance: if you have a complex menu bar with hundreds of menu items, cloning the menu bar is very slow. We found that this approach delayed the appearance of new windows by several seconds!
A new method was added to Apple's Java library in Java for OS X v10.6 Update 1 and 10.5 Update 6: Application.setDefaultMenuBar(JMenuBar)
.
The stated purpose of this method is to provide a menu bar when no JFrame
is active, but it also shows the default menu bar when a JFrame
with no JMenuBar
of its own is active.
However, there are several major problems with the setDefaultMenuBar
functionality:
setDefaultMenuBar
prevents the JVM from shutting down properly. Even a subsequent call to setDefaultMenuBar(null)
does not free the necessary resources.In short, setDefaultMenuBar
does not seem like a safe and robust way to go at all.
So, the question is: What is the most reliable, performant and compatible (across versions of OS X) way to implement a consistent screen JMenuBar
?
You may be able to leverage JDialog
, which inherits its parent's JMenuBar
. To keep the dialogs modeless, you can use
PropertyChangeEvent
to communicate among the dialogs and the main JFrame
, as suggested here.
Action
and Key Bindings to navigate among the dialogs.