Руководство JavaFX ContextMenu

1- JavaFX ContextMenu

Когда вы не можете дать пространство интерфейса вашего пользователя для требующейся функции, вы можете использовать контекстное меню ( ContextMenu). Контекстное меню это поп ап окно появляющееся в соответствии с кликом мыши. Контекстное меню может содержать один или более пунктов меню.
Заметьте, что  ContextMenu довольно похоже на Menu, вы можете добавлять пункты вида MenuItem, CheckMenuItem, RadioMenuItem и  SeparatorMenuItem в контекстное меню.

2- Пример ContextMenu

Простой пример ниже изображает  ContextMenu, которое появляется когда пользователь нажимает на правую кнопку мыши на круг.
ContextMenuDemo.java
package org.o7planning.javafx.contextmenu;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class ContextMenuDemo extends Application {

    @Override
    public void start(Stage stage) {

        Label label = new Label();

        Circle circle = new Circle();
        circle.setRadius(80);
        circle.setFill(Color.AQUA);

        VBox root = new VBox();
        root.setPadding(new Insets(5));
        root.setSpacing(5);

        root.getChildren().addAll(label, circle);

        // Create ContextMenu
        ContextMenu contextMenu = new ContextMenu();

        MenuItem item1 = new MenuItem("Menu Item 1");
        item1.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                label.setText("Select Menu Item 1");
            }
        });
        MenuItem item2 = new MenuItem("Menu Item 2");
        item2.setOnAction(new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                label.setText("Select Menu Item 2");
            }
        });

        // Add MenuItem to ContextMenu
        contextMenu.getItems().addAll(item1, item2);

        // When user right-click on Circle
        circle.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {

            @Override
            public void handle(ContextMenuEvent event) {

                contextMenu.show(circle, event.getScreenX(), event.getScreenY());
            }
        });

        Scene scene = new Scene(root, 400, 200);

        stage.setTitle("JavaFX ContextMenu (o7planning.org)");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        Application.launch(args);
    }

}

3- Горячая клавиша (Accelerator) и виды MenuItem

Как и  Menu, вы можете добавить пункты вида  MenuItem, CheckMenuItem, RadioMenuItem, SeparatorMenuItem в ContextMenu. Вы так же можете прикрепить горячие клавиши (Accelerator) в элементы, пользователь может нажать на горячие класвиши вместо того, чтобы нажимать на тот элемент.
ContextMenuDemo2.java
package org.o7planning.javafx.contextmenu;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CheckMenuItem;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.RadioMenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.control.ToggleGroup;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;

public class ContextMenuDemo2 extends Application {

    @Override
    public void start(Stage stage) {

        Circle circle = new Circle();
        circle.setRadius(80);
        circle.setFill(Color.AQUA);

        VBox root = new VBox();
        root.setPadding(new Insets(5));
        root.setSpacing(5);

        root.getChildren().addAll(circle);

        // Create ContextMenu
        ContextMenu contextMenu = new ContextMenu();

        MenuItem menuItem = new MenuItem("Menu Item");

        // Set accelerator to menuItem.
        menuItem.setAccelerator(KeyCombination.keyCombination("Ctrl+O"));

        Menu parentMenu = new Menu("Parent");
        MenuItem childMenuItem1 = new MenuItem("Child 1");
        MenuItem childMenuItem2 = new MenuItem("Child 2");
        parentMenu.getItems().addAll(childMenuItem1, childMenuItem2);

        CheckMenuItem checkMenuItem = new CheckMenuItem("Check Menu Item");
        checkMenuItem.setSelected(true);

        SeparatorMenuItem separatorMenuItem = new SeparatorMenuItem();

        RadioMenuItem radioMenuItem1 = new RadioMenuItem("Radio - Option 1");
        RadioMenuItem radioMenuItem2 = new RadioMenuItem("Radio - Option 2");
        ToggleGroup group = new ToggleGroup();

        radioMenuItem1.setToggleGroup(group);
        radioMenuItem2.setToggleGroup(group);

        // Add MenuItem to ContextMenu
        contextMenu.getItems().addAll(menuItem, parentMenu, checkMenuItem, //
                separatorMenuItem, radioMenuItem1, radioMenuItem2);

        // When user right-click on Circle
        circle.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {

            @Override
            public void handle(ContextMenuEvent event) {

                contextMenu.show(circle, event.getScreenX(), event.getScreenY());
            }
        });

        Scene scene = new Scene(root, 400, 200);

        stage.setTitle("JavaFX ContextMenu (o7planning.org)");
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        Application.launch(args);
    }

}

4- ContextMenu и события

Есть некоторые события в  ContextMenu, которые могут быть для вас полезны например onShowing это событие происходящее перед тем как отображается contextMenu. Вы можете использовать это событие, чтобы сделать что-то например добавить MenuItem в ContextMenu.
// Called just prior to the ContextMenu being shown.
public final void setOnShowing(EventHandler<WindowEvent> value)

// Called just after the ContextMenu is shown.
public final void setOnShown(EventHandler<WindowEvent> value)

// Called just prior to the ContextMenu being hidden.
public final void setOnHiding(EventHandler<WindowEvent> value)

// Called just after the ContextMenu has been hidden.
public final void setOnHidden(EventHandler<WindowEvent> value)

// Called when there is an external request to close this
public final void setOnCloseRequest(EventHandler<WindowEvent> value)
ContextMenuEventDemo.java
package org.o7planning.javafx.contextmenu;

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.control.TextArea;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

public class ContextMenuEventDemo extends Application {

  private int index = 1;

  @Override
  public void start(Stage stage) {

      TextArea textArea = new TextArea();
      textArea.setMinHeight(100);

      Circle circle = new Circle();
      circle.setRadius(80);
      circle.setFill(Color.GRAY);

      VBox root = new VBox();
      root.setPadding(new Insets(5));
      root.setSpacing(5);

      root.getChildren().addAll(textArea, circle);

      // Create ContextMenu
      ContextMenu contextMenu = new ContextMenu();
      MenuItem menuItem = new MenuItem("Menu Item");
      contextMenu.getItems().add(menuItem);

      // When user right-click on Circle
      circle.setOnContextMenuRequested(new EventHandler<ContextMenuEvent>() {

          @Override
          public void handle(ContextMenuEvent event) {

              contextMenu.show(circle, event.getScreenX(), event.getScreenY());
          }
      });
      // Called just prior to the ContextMenu being shown.
      // Add new MenuItem to ContextMenu.
      contextMenu.setOnShowing(new EventHandler<WindowEvent>() {

          @Override
          public void handle(WindowEvent event) {
              textArea.appendText("On Showing..\n");

              MenuItem menuItem = new MenuItem("New Menu Item " + index++);
              contextMenu.getItems().add(menuItem);
          }
      });

      // Called just after the ContextMenu is shown.
      contextMenu.setOnShown(new EventHandler<WindowEvent>() {

          @Override
          public void handle(WindowEvent event) {
              textArea.appendText("On Show..\n");
          }
      });
   
      // Called just prior to the ContextMenu being hidden.
      contextMenu.setOnHiding(new EventHandler<WindowEvent>() {

          @Override
          public void handle(WindowEvent event) {
              textArea.appendText("On Hiding..\n");
          }
      });
   
      // Called just after the ContextMenu has been hidden.
      contextMenu.setOnHidden(new EventHandler<WindowEvent>() {

          @Override
          public void handle(WindowEvent event) {
              textArea.appendText("On Hidden..\n");
          }
      });

      Scene scene = new Scene(root, 400, 250);

      stage.setTitle("JavaFX ContextMenu (o7planning.org)");
      stage.setScene(scene);
      stage.show();
  }

  public static void main(String[] args) {
      Application.launch(args);
  }

}