Can JavaFX 8 set a default menu bar?


Question

A trivial toy application with a screen menu bar can be written like this in Java FX 8:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {
    public static void main(final String[] args) throws Exception {
        launch(Main.class, args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        MenuBar menuBar = new MenuBar();
        Menu fileMenu = new Menu("File");
        MenuItem newNotebookMenuItem = new MenuItem("New Notebook...");
        newNotebookMenuItem.setAccelerator(KeyCombination.keyCombination("Meta+N"));
        newNotebookMenuItem.setOnAction(event -> { System.out.println("Action fired"); });
        fileMenu.getItems().add(newNotebookMenuItem);
        menuBar.getMenus().add(fileMenu);
        menuBar.setUseSystemMenuBar(true);

        VBox root = new VBox();
        root.getChildren().add(menuBar);
        Scene scene = new Scene(root, 400, 350);
        stage.setScene(scene);
        stage.show();
    }
}

This might be OK for making toy apps like calculators where there is only one window and the application closes when the last window closes, but my application is document-based. When a document-based application has no documents open, there are no windows open but the menu should remain visible so that the user can open a new document.

The usual way to do this is setDefaultMenuBar in the com.apple.eawt APIs, but this is not great because:

  1. Setting the menu bar from there hangs the application (possibly some kind of incompatibility between AWT and JavaFX - it doesn't happen with the same application running as pure Swing.)
  2. It requires me to build a javafx MenuBar for the real windows but a JMenuBar for the default menu bar and JavaFX doesn't let me reuse my Action classes, so awful adapters would end up being written to bridge the gap.

Is there a proper way to set this which I just haven't found yet? I expected to find such a method on Application (some mailing list posts were hinting that it might end up there) but it looks like it's still missing.

1
7
6/27/2014 12:46:25 PM

Here is another possibility without any scene hacks, yet be aware it uses private APIs:

List<MenuBase> menus = new ArrayList<>();
menus.add(GlobalMenuAdapter.adapt(fileMenu));

Toolkit.getToolkit().getSystemMenu().setMenus(menus);

Important: This is a OS X only solution, so you still need to add your menu to the scene for other operating systems.

1
1/21/2015 8:18:55 PM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon