LuminousNutria
LuminousNutria

Reputation: 2001

Center a JavaFX ContextMenu in the middle of a screen?

I am trying to create a ContextMenu that appears in the middle of the screen whenever the keyboard's escape button is pressed. I want to use it to handle loading, saving, and exiting in my game. It will be called from classes outside of Main.

The problem is I'm not sure how to find out the ContextMenu's height and width in pixels. so, I'm at a loss as far as how to center it in a window. I am trying to use Rectangle2D to find the center, but it is still slightly off.

How can I display my ContextMenu in the middle of the screen?

Displays my ContextMenu:

/**
 * Returns the Pane object so it can be made into a Scene object.
 * Each Scene has it's own class
 * Each class uses this method to create a Pane object for it.
 * @return Pane 
 */
public Pane getPane() {
   // create a GridPane object
   grid = new GridPane();

   // create ContextMenu and set anchor points.
   ContextMenu cm = Main.Org.createPopUpMenu();
   cm.setOnShowing(event -> {
      event.consume();
      cm.setAnchorX(cm.getAnchorX() - cm.getWidth() / 2.0);
      cm.setAnchorY(cm.getAnchorY() - cm.getHeight() / 2.0);
   });
   Rectangle2D bounds = Screen.getPrimary().getVisualBounds();

   // show ContextMenu if escape key is pressed.
   grid.setOnKeyReleased( event -> {
      if(event.getCode() == KeyCode.ESCAPE) {
         cm.show(grid, bounds.getWidth() / 2.0, bounds.getHeight() / 2.0);
      }
   });

   return grid;
}

Organizer class createPopUpMenu() method:

/**
 * Creates a pop-up menu for saving, loading, and exiting the game
 * @return ContextMenu 
 */
public ContextMenu createPopUpMenu() {
   ContextMenu contextMenu = new ContextMenu();

   MenuItem menuItem = new MenuItem();

   //create ImageViews
   image = new ImageView("/images/PopUpMenu_Exit.png");

   // add ImageViews to MenuItems
   menuItem.setGraphic(image);

   contextMenu.getItems().add(menuItem);

   menuItem.setOnAction( a -> {
      // quit the game
      Platform.exit();
      System.exit(0);
   });

   return contextMenu;
}

Upvotes: 0

Views: 622

Answers (1)

Slaw
Slaw

Reputation: 46315

Here's a small example (some explanations are in code-comments):

import javafx.application.Application;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.control.SeparatorMenuItem;
import javafx.scene.input.KeyCode;
import javafx.scene.input.KeyEvent;
import javafx.scene.layout.StackPane;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.Window;

public class Main extends Application {

  private ContextMenu menu;

  @Override
  public void start(Stage primaryStage) {
    primaryStage.addEventHandler(KeyEvent.KEY_PRESSED, event -> {
      if (event.getCode() == KeyCode.ESCAPE) {
        event.consume();
        showContextMenu(primaryStage);
      }
    });

    Label label = new Label("Press ESC to show ContextMenu.");
    primaryStage.setScene(new Scene(new StackPane(label), 500, 300));
    primaryStage.show();
  }

  private void showContextMenu(Window owner) {
    if (menu == null) {
      menu = new ContextMenu(
          new MenuItem("Copy"),
          new MenuItem("Cut"),
          new MenuItem("Paste"),
          new SeparatorMenuItem(),
          new MenuItem("Delete")
      );

      /*
       * Adjusts the ContextMenu's position once shown so that the center
       * of the ContextMenu is at the center of the screen (rather than
       * the top left corner). Do this here because the ContextMenu needs
       * to have been displayed in order to know the dimensions.
       *
       * Since the top left corner is already centered on the screen we don't need
       * to know the dimensions of the screen. We only need to move the ContextMenu
       * relative to itself.
       */
      menu.setOnShown(event -> {
        event.consume();
        menu.setAnchorX(menu.getAnchorX() - menu.getWidth() / 2.0);
        menu.setAnchorY(menu.getAnchorY() - menu.getHeight() / 2.0);
      });
    }

    /*
     * Displays the ContextMenu on the primary screen. The top left corner
     * of the ContextMenu will be at the center of the screen. Will need
     * to adjust the ContextMenu's position after it's shown.
     */
    Rectangle2D bounds = Screen.getPrimary().getVisualBounds();
    menu.show(owner, bounds.getWidth() / 2.0, bounds.getHeight() / 2.0);
  }

}

Upvotes: 2

Related Questions