How do I set a tab for tabpane in Javafx? - javafx

I am trying to create a button in my tabpane, that can switch to another tab(0 → 1).
This is for creating a chat program using Javafx, and I'm currently using Scenebuilder to design the GUI.
myTabPane_1.getSelectionModel().select(1);
I expect it to change from tab index # '0' to index # '1', but it stays the same.

There is something that you are not showing in your code and because you did not supply enough information no one will be able to help you modify your code so here is a working example of how to change tabs using index and by passing the actual tab
public class Main extends Application {
#Override
public void start(Stage stage) {
VBox vBox = new VBox();
vBox.setAlignment(Pos.CENTER);
Tab tabOne = new Tab("Tab One", new Label("This is Tab One"));
Tab tabTwo = new Tab("Tab Two", new Label("This is Tab Two"));
TabPane tabPane = new TabPane();
tabPane.getTabs().addAll(tabOne, tabTwo);
vBox.getChildren().add(tabPane);
Button button = new Button("Change Tab by passing index");
button.setOnAction(event -> {
if(tabPane.getSelectionModel().getSelectedItem().getText().equals("Tab One"))
tabPane.getSelectionModel().select(1);
else
tabPane.getSelectionModel().select(0);
});
vBox.getChildren().add(button);
Button buttonTwo = new Button("Change Tab by passing tab");
buttonTwo.setOnAction(event -> {
if(tabPane.getSelectionModel().getSelectedItem().getText().equals("Tab One"))
tabPane.getSelectionModel().select(tabTwo);
else
tabPane.getSelectionModel().select(tabOne);
});
vBox.getChildren().add(buttonTwo);
stage.setScene(new Scene(vBox));
stage.show();
}
}

Related

Click on open JavaFX Menu embedded in JFXPanel does not close it

When embedding a Menu in a Swing window through a JFXPanel, I cannot close the menu by clicking on it. Sometimes it blinks, as if it closed and immediately reopened.
package testjavafx;
public class TestMenuJavaFX extends Application {
#Override
public void start(Stage primaryStage) {
MenuBar menuBar = new MenuBar(
new Menu("Menu 1", null,
new MenuItem("Menu item 1-1"),
new MenuItem("Menu item 1-2")),
new Menu("Menu 2", null,
new MenuItem("Menu item 2-1"),
new MenuItem("Menu item 2-2")),
new Menu("Menu 3", null,
new MenuItem("Menu item 3-1"),
new MenuItem("Menu item 3-1")));
menuBar.setPrefWidth(300);
Region root = new Pane(menuBar);
root.setPrefSize(300, 185);
useJFXPanel(root);
//usePrimaryStage(primaryStage, root);
}
private static void useJFXPanel(Region root) {
JFXPanel jfxPanel = new JFXPanel();
jfxPanel.setScene(new Scene(root));
JFrame jFrame = new JFrame("test menu JavaFX");
jFrame.setSize((int) root.getWidth(), (int) root.getHeight());
jFrame.add(jfxPanel);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
}
private static void usePrimaryStage(Stage primaryStage, Parent root) {
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(TestMenuJavaFX.class, args);
}
}
By using the method usePrimaryStage I get the expected behavior (click on the menu to open it, click again to close it), but with useJFXPanel the problem appears.
This is an event handling issue, the mouse click is first dispatched to the JFXPanel as a Swing mouse event then the JFXPanel internally dispatches a JavaFX mouse event to its embedded Scene.
It appears that, during the Swing part, the menu loses focus and closes, and when the event reaches the Menu instance it finds it closed and therefore opens it.
I tried to inherit the Menu class to add a mouse click event handler to it, however it does not handle mouse clicks, and using the showing/shown and hiding/hidden events provided did not help it (because the problem happens earlier).
I also tried to subclass MenuBar to add a mouse click event handler, but the handler is only called when clicking on the bar outside of a menu, so no luck here, and to subclass JFXPanel to override processMouseEvent and retrieve the MenuBarButton instance through reflection black magic but i couldn't make it work.
This is a bug, right? And is there a (easy and clean, ideally) workaround to this issue?
I'm using OpenJDK 11.0.10.9 and JavaFX 17.0.0.1.
On my system, this wouldn't run, but hung on startup because the JFrame is created and shown on the wrong thread. Correcting that did display the behavior you describe, which does appear to be a bug.
I found one workaround, which is to capture a ON_HIDING event and schedule a call to hide the menu further down the event queue, using Platform.runLater(...). The resulting code looks like;
public class TestMenuJavaFX extends Application {
#Override
public void start(Stage primaryStage) {
MenuBar menuBar = new MenuBar(
new Menu("Menu 1", null,
new MenuItem("Menu item 1-1"),
new MenuItem("Menu item 1-2")),
new Menu("Menu 2", null,
new MenuItem("Menu item 2-1"),
new MenuItem("Menu item 2-2")),
new Menu("Menu 3", null,
new MenuItem("Menu item 3-1"),
new MenuItem("Menu item 3-1")));
menuBar.setPrefWidth(300);
menuBar.getMenus().forEach(menu -> {
menu.addEventHandler(Menu.ON_HIDING, e -> {
Platform.runLater(menu::hide);
});
});
Region root = new Pane(menuBar);
root.setPrefSize(300, 185);
useJFXPanel(root);
//usePrimaryStage(primaryStage, root);
}
private static void useJFXPanel(Region root) {
JFXPanel jfxPanel = new JFXPanel();
jfxPanel.setScene(new Scene(root));
SwingUtilities.invokeLater(() -> {
JFrame jFrame = new JFrame("test menu JavaFX");
jFrame.setSize((int) root.getWidth(), (int) root.getHeight());
jFrame.add(jfxPanel);
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
});
}
private static void usePrimaryStage(Stage primaryStage, Parent root) {
primaryStage.setScene(new Scene(root));
primaryStage.show();
}
public static void main(String[] args) {
launch(TestMenuJavaFX.class, args);
}
}

JavaFX custom dialog set Layout of node

We created a Custom Dialog without an FXML file. We are using JavaFX 8.
The dialog loads and functions as expected but we can not move the Buttons and the TextField to enhance the styling.
We have tried to use tf.setLayoutY(50) this has no effect.
We used this tf.setPromptText("This Works ?") and it works.
We would rather not use css to accomplish this styling.
And we will consider a FXML file if we can keep the two event handlers that force data to be entered in the TextField.
So the question is: How to style this Custom Dialog?
The code is a mess as it includes some concepts we tried:
public void CustomDialog() {
Dialog dialog = new Dialog<>();
dialog.setResizable(false);
final Window window = dialog.getDialogPane().getScene().getWindow();
stage = (Stage) window;
stage.setMinHeight(600);
stage.setMinWidth(400);
TextField tf = new TextField();
tf.setLayoutX(10);
tf.setLayoutY(50);
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
dialog.getDialogPane().getChildren().add(tf);
dialog.getDialogPane().setContent(tf);
// Create an event filter that consumes the action if the text is empty
EventHandler<ActionEvent> filter = event -> {
if (tf.getText().isEmpty()) {
event.consume();
}
};
// lookup the buttons
ButtonBase okButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.OK);
Button cancelButton = (Button) dialog.getDialogPane().lookupButton(ButtonType.CANCEL);
// add the event-filter
okButton.addEventFilter(ActionEvent.ACTION, filter);
cancelButton.addEventFilter(ActionEvent.ACTION, filter);
stage.setOnCloseRequest(event -> {
if (tf.getText().isEmpty()) {
event.consume();
}
}
//Scene scene = new Scene(root);
//dialogStage.setScene(scene);
dialog.initModality(Modality.APPLICATION_MODAL);
//dialogStage.setAlwaysOnTop(true);
//dialogStage.setResizable(false);
tf.setPromptText("This Works ?");
tf.requestFocus();// This does not work
dialog.showAndWait();
}
Grendel we enhanced your answer so anyone who comes by and sees the code you posted in your question will understand as you said it was a mess
Your posted answer was real old school but less work perhaps than building a FXML file
Besides it is good to know some old school tricks
public void NewDialog(){
Label lblAmt = new Label("Enter Amount");
Button btnOK = new Button("OK");
TextField txtAmt = new TextField();
AnchorPane secondaryLayout = new AnchorPane();
secondaryLayout.setStyle("-fx-border-color:red;-fx-border-width:10px; -fx-background-color: lightblue;");
secondaryLayout.getChildren().addAll(lblAmt,btnOK,txtAmt);
lblAmt.setLayoutX(30);
lblAmt.setLayoutY(30);
txtAmt.setLayoutX(164);
txtAmt.setLayoutY(25);
txtAmt.setMaxWidth(116);
btnOK.setLayoutX(190);
btnOK.setLayoutY(100);
btnOK.setStyle("-fx-font-size: 18px;-fx-font-weight: bold;");
lblAmt.setStyle("-fx-font-size: 18px;-fx-font-weight: bold;");
txtAmt.setStyle("-fx-font-size: 18px;-fx-font-weight: bold;");
Scene secondScene = new Scene(secondaryLayout, 300, 180);
EventHandler<ActionEvent> filter = event -> {
if(txtAmt.getText().isEmpty()) {
event.consume();
}
};
// New window (Stage)
Stage newWindow = new Stage();
newWindow.initStyle(StageStyle.UNDECORATED);
//newWindow.initModality(Modality.APPLICATION_MODAL);
newWindow.setResizable(false);
newWindow.setTitle("Second Stage");
newWindow.setScene(secondScene);
btnOK.addEventHandler(ActionEvent.ACTION,filter);
btnOK.setOnAction(evt -> {
String str = txtAmt.getText();
System.out.println("################ str "+str);
if(txtAmt.getText().equals("")) {
evt.consume();
txtAmt.requestFocus();
}else{
newWindow.close();
}
});
newWindow.setOnCloseRequest(event -> {
if(txtAmt.getText().isEmpty()) {
event.consume();
}
});
txtAmt.requestFocus();
newWindow.showAndWait();
}

javafx - Navigation Sidebar with Toggle

So in windows 10 you have the windows menu with the icons on the left side:
When clicking on the hamburger icon the menu expands and text is show.
The expanded part is overlaying the content. The text is showing. and it was animated in (sliding transition).
In my application I want to make a similar menu on the right side (see blue part):
I have absolutely no idea how to get this effect. Currently I made a button with a graphic. I only display the graphic and when I click on the hamburger I show all the text by changing the setContentDisplay(ContentDisplay.GRAPHIC_ONLY) to setContentDisplay(ContentDisplay.RIGHT) 2 things that are wrong with this approach.
it pushes the content.
You cannot add a transition.
Any help would be appreciated, especially examples.
Demo
I made a demo that shows what I currently have:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
BorderPane root = new BorderPane();
JFXButton[] jfxButtons = {
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
};
JFXHamburger hamburger = new JFXHamburger();
HamburgerNextArrowBasicTransition transition = new HamburgerNextArrowBasicTransition(hamburger);
transition.setRate(-1);
hamburger.setAlignment(Pos.CENTER_RIGHT);
hamburger.setPadding(new Insets(5));
hamburger.setStyle("-fx-background-color: #fff;");
hamburger.setOnMouseClicked(event -> {
transition.setRate(transition.getRate() * -1);
transition.play();
if (transition.getRate() == -1) {
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
} else {
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setContentDisplay(ContentDisplay.RIGHT);
}
}
});
ScrollPane scrollPane = new ScrollPane();
VBox vBox = new VBox();
scrollPane.setContent(vBox);
vBox.getStyleClass().add("content_scene_right");
vBox.getChildren().add(hamburger);
vBox.getChildren().addAll(jfxButtons);
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setMaxWidth(Double.MAX_VALUE);
jfxButton.setRipplerFill(Color.valueOf("#40E0D0"));
VBox.setVgrow(jfxButton, Priority.ALWAYS);
jfxButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
vBox.setFillWidth(true);
Label labelHoverOverTest = new Label("Testing label");
VBox vbox2 = new VBox();
vbox2.getChildren().addAll(labelHoverOverTest);
vbox2.setAlignment(Pos.CENTER_RIGHT);
root.setRight(scrollPane);
root.setCenter(vbox2);
Scene scene = new Scene(root);
primaryStage.setMinWidth(400);
primaryStage.setMinHeight(400);
primaryStage.setScene(scene);
primaryStage.show();
}
}
I used JFoenix and fontawesomefx for this demo, but it can also be javafx scene buttons with any graphic.
Here are some images of what the demo looks like:
As you can see it pushes it the content in the center and I can't add any transition.
(here is a sample from bootstrap to give you an idea on What I'm trying to make it look like 1: https://bootsnipp.com/snippets/Pa9xl, 2: https://bootsnipp.com/snippets/featured/navigation-sidebar-with-toggle (with this one the content still moves, but it should give you a clear idea on what my vision is))
Problem is that you are using BorderPane and placing everything on same layer, so when content on right changes width it will affect one in the center and such.
In other to avoid this you should make it layered, so for root of view use StackPane, this pane should have 2 children, 1 for main content and 1 for sidebar, make sure that sidebar is above main content, now this 2 can be any Pane that you want. This way sidebar will be placed over main content and it won't push content.
Using code you provided and just adding StackPane you get something like this:
#Override
public void start(Stage primaryStage) {
StackPane root = new StackPane();
BorderPane mainContent = new BorderPane();
BorderPane sidebar = new BorderPane();
JFXButton[] jfxButtons = {
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),
new JFXButton("Some text", new FontAwesomeIconView(FontAwesomeIcon.LINK)),};
JFXHamburger hamburger = new JFXHamburger();
HamburgerNextArrowBasicTransition transition = new HamburgerNextArrowBasicTransition(hamburger);
transition.setRate(-1);
hamburger.setAlignment(Pos.CENTER_RIGHT);
hamburger.setPadding(new Insets(5));
hamburger.setStyle("-fx-background-color: #fff;");
hamburger.setOnMouseClicked(event -> {
transition.setRate(transition.getRate() * -1);
transition.play();
if (transition.getRate() == -1) {
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
} else {
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setContentDisplay(ContentDisplay.RIGHT);
}
}
});
ScrollPane scrollPane = new ScrollPane();
VBox vBox = new VBox();
scrollPane.setContent(vBox);
vBox.getStyleClass().add("content_scene_right");
vBox.getChildren().add(hamburger);
vBox.getChildren().addAll(jfxButtons);
for (JFXButton jfxButton : jfxButtons) {
jfxButton.setMaxWidth(Double.MAX_VALUE);
jfxButton.setRipplerFill(Color.valueOf("#40E0D0"));
VBox.setVgrow(jfxButton, Priority.ALWAYS);
jfxButton.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}
vBox.setFillWidth(true);
Label labelHoverOverTest = new Label("Testing label");
VBox vbox2 = new VBox();
vbox2.getChildren().addAll(labelHoverOverTest);
vbox2.setAlignment(Pos.CENTER_RIGHT);
mainContent.setCenter(vbox2);
sidebar.setRight(scrollPane);
root.getChildren().addAll(mainContent, sidebar);
Scene scene = new Scene(root);
primaryStage.setMinWidth(400);
primaryStage.setMinHeight(400);
primaryStage.setScene(scene);
primaryStage.show();
}
As for transition I'm not sure what is problem there, for me it works fine.

How to disable right click on a menu in javafx

In javaFX code, a menu can popup by left click or right click. How to disable right click?
public void start(Stage primaryStage)
{
BorderPane root = new BorderPane();
MenuBar menuBar = new MenuBar();
Menu hello = new Menu("hello");
menuBar.getMenus().addAll(hello);
Menu world = new Menu("world");
menuBar.getMenus().addAll(world);
root.setCenter(menuBar);
MenuItem item = new MenuItem("laugh");
hello.getItems().add(item);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
When I right click the "hello" menu, it will popup menuitem "laugh".
The basic approach is to register a eventFilter on the MenuBar that consumes the events that should not be delivered to the children.
Doing so manually in your application code:
public class DisableRightClickOpenMenu extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
BorderPane root = new BorderPane();
MenuBar menuBar = new MenuBar();
menuBar.addEventFilter(MouseEvent.MOUSE_PRESSED, ev -> {
if (ev.getButton() == MouseButton.SECONDARY) {
ev.consume();
}
});
Menu hello = new Menu("hello");
menuBar.getMenus().addAll(hello);
Menu world = new Menu("world");
menuBar.getMenus().addAll(world);
root.setCenter(menuBar);
MenuItem item = new MenuItem("laugh");
hello.getItems().add(item);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
If you want this behaviour across all your applications, you can implement a custom menuBarSkin that registers the filter and install the custom skin via a stylesheet.
The skin:
public class ExMenuBarSkin extends MenuBarSkin {
/**
* Instantiates a skin for the given MenuBar. Registers an
* event filter that consumes right mouse press.
*
* #param menuBar
*/
public ExMenuBarSkin(MenuBar menuBar) {
super(menuBar);
menuBar.addEventFilter(MouseEvent.MOUSE_PRESSED, ev -> {
if (ev.getButton() == MouseButton.SECONDARY) {
ev.consume();
}
});
}
}
In your stylesheet (replace with your fully qualified class name):
.menu-bar {
-fx-skin: "de.swingempire.fx.event.ExMenuBarSkin";
}
Its usage (replace the name with your stylesheet file name):
URL uri = getClass().getResource("contextskin.css");
primaryStage.getScene().getStylesheets().add(uri.toExternalForm());
This is usual behavior of menu in many programs. I don't think you can change it. However, you can use some other controls and simulate menu. (Like HBox and Labels).
I agree as far as I know there's no a standard way to do this, but you may want to consider the following workaround.
It is replacing the Menu node with a Menu object composed by an HBox and a Label: an EventHandler is added to the HBox and by checking the mouse button pressed we add/remove on the fly the MenuItem to its parent.
#Override
public void start(final Stage primaryStage) {
final BorderPane root = new BorderPane();
final MenuBar menuBar = new MenuBar();
final Menu menuHello = new Menu();
final Menu menuWorld = new Menu("world");
final MenuItem menuitem = new MenuItem("laugh");
final HBox hbox = new HBox();
menuBar.getMenus().addAll(menuHello, menuWorld);
root.setCenter(menuBar);
hbox.setPrefWidth(30);
hbox.getChildren().add(new Label("hello"));
menuHello.setGraphic(hbox);
menuHello.getItems().add(menuitem);
hbox.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
#Override
public void handle(final MouseEvent e) {
if (e.getButton() == MouseButton.SECONDARY) {
System.out.println("Right click");
menuHello.getItems().remove(menuitem);
} else {
System.out.println("Left click");
if (!menuHello.getItems().contains(menuitem)) {
menuHello.getItems().add(menuitem);
menuHello.show(); // The .show method prevent 'losing' the current click }
}
}
});
final Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
This will produce the following result - preview
Note that I've used an HBox just for habit, there's no a particular reason.
While using a workaround like this, my suggestion would be to fill all the Menus with the same 'pattern', such as the HBox + Label combo in my example, and stylize them via css/code (width/height, background/fill/hover... colors etc.) in order to have them as uniform as possible and avoid creating graphic inconsistencies due to have different nodes types in the same menubar.

How an action can be performed when clicking on a menu item?

I am doing a project in javafx using Netbeans IDE. I am new to javafx. I have a menu bar in my project. I need to open a new page on the same windows when clicked on each menu item(not new scene). The code is given below :
private VBox addVBox1() {
final VBox vbox = new VBox();
vbox.setPadding(new Insets(20,40,30,4));
vbox.setSpacing(10);
MenuBar menuBar = new MenuBar();
Menu menuFile1 = new Menu("ADD");
Menu menuFile2 = new Menu("EDIT");
Menu menuFile3 = new Menu("VIEW");
Menu menuFile4 = new Menu("HELP");
MenuItem add1 = new MenuItem("ENTER STUDENT DETAILS");
MenuItem add2 = new MenuItem("ENTER C-MARK");
MenuItem add3 = new MenuItem("ENTER ATTENDANCE");
MenuItem add4 = new MenuItem("EDIT STUDENT DETAILS");
MenuItem add6 = new MenuItem("EDIT C-MARK");
MenuItem add8 = new MenuItem("EDIT ATTENDANCE");
MenuItem add10 = new MenuItem("STUDENT DETAILS");
MenuItem add11 = new MenuItem("C-MARK");
MenuItem add12 = new MenuItem("ATTENDANCE");
MenuItem add13 = new MenuItem("VIEW HELP");
add1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
//...WHAT TO INCLUDE HERE ?
}
});
menuFile1.getItems().addAll(add1,add2,add3);
menuFile2.getItems().addAll(add4,add6,add8);
menuFile3.getItems().addAll(add10,add11,add12);
menuFile4.getItems().addAll(add13);
menuBar.getMenus().addAll(menuFile1,menuFile2,menuFile3,menuFile4);
vbox.getChildren().addAll(menuBar);
return vbox;
}
In my project, I open new pages when clicking on buttons. Its code is:
btn2.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent e) {
((Stage)btn2.getScene().getWindow()).setScene(new Scene(new Login()));
}
});
Is it possible to implement this code in case of menu item ? How should I edit this code to perform an action when clicked on a menu item ?
I don't know exactly what you mean by a new page. There is a Pagination control, but I don't think you mean that. Here's how to add a TextArea but you have to design the UI and choose your own controls.
add1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
vbox.getChildren().add(new TextArea());
}
});
This is how to make a new window but you may want to ask a question about designing dialog boxes. Here's a SO answer https://stackoverflow.com/a/14168238/2855515
add1.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent t) {
Stage stage = new Stage();
Scene scene = new Scene(new VBox());
stage.setTitle("popup");
stage.setScene(scene);
stage.show();
}
});
I think this question has not been answered correctly and the question has been misinterpreted.
TomJ asked:
Is it possible to implement this code in case of menu item?
When he says "menu item", Does he mean Menu or MenuItem? He's clearing showing the correct code for how to do it for a MenuItem. I think he's asking about how to do that same thing for a Menu. I tried doing this for a Menu, and the code for invoking a handler on a Menu is slightly different than doing it for a MenuItem.
Here's a simple code example where the execute method is called when the Execute Menu is clicked:
Menu viewMenu = new Menu("View");
MenuItem viewJobs = new MenuItem("Jobs");
viewJobs.setOnAction(viewJobsAction);
MenuItem viewFileSelection = new MenuItem("File Selection");
viewFileSelection.setOnAction(e->{viewFileSelection());
viewMenu.getItems().addAll(viewJobs, viewFileSelection);
Menu execute = new Menu("Execute");
execute.onShownProperty().setValue(e->{execute());
// if the following line is not added, the onShownProperty event handler
// will never be called!
execute.getItems().addAll(new MenuItem());
Menu help = new Menu("Help");
MenuItem helpItem = new MenuItem("Help");
helpItem.setOnAction(e->{showHelp()}
MenuItem aboutItem = new MenuItem("About");
aboutItem.setOnAction(e->{showAbout()}
help.getItems().addAll(helpItem,aboutItem);
menubar.getMenus().addAll(viewMenu, execute, help);
It's necessary to have a bogus MenuItem added to the Execute Menu for this to work. For Menu, it's better to use the onShownProperty or onShowingProperty rather than using the setOnAction. Any of them will work, but the setOnAction will require a second click before the handler will be called.
The JavaDoc for onShowingProperty for Menu says:
Called just prior to the ContextMenu being shown, even if the menu has
no items to show. Note however that this won't be called if the menu
does not have a valid anchor node.
It sounds like the code should work without any MenuItems added, but it doesn't. It says however that the call won't be made if the menu doesn't have a valid anchor node. I'm not sure what an anchor node is, and I couldn't find any documentation about how to add an anchor node to a menu. Adding the bogus empty MenuItem clearly made the Execute Menu have a valid anchor node. If someone knows more about anchor nodes, please reply and explain it, but the code example I gave works acceptably.

Resources