Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can JavaFX 8 set a default menu bar?

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.

like image 970
Hakanai Avatar asked Jun 27 '14 12:06

Hakanai


2 Answers

Currently my trick is as follows:

Pane pane = new Pane();
pane.maxWidth(1);
pane.maxHeight(1);
pane.resize(1, 1);
pane.getChildren().add(menuBar);
Scene scene = new Scene(pane,1,1);
scene.setFill(null);
primaryStage.initStyle(StageStyle.TRANSPARENT);
primaryStage.setWidth(1);
primaryStage.setHeight(1);
primaryStage.setScene(scene);
primaryStage.show();

I don't use this stage for anything. It should appear invisible as well. Annoying & ugly, but it works.

The other sad fact is that I must set any window to have the same menubar.... This may or may not work for you.

like image 189
msj121 Avatar answered Nov 15 '22 06:11

msj121


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.

like image 24
Sebastian S Avatar answered Nov 15 '22 06:11

Sebastian S