Using FXML to Create ContextMenu within a Pane


Question

I've got a working example for defining a ContextMenu on a Pane in JavaFX FXML, but am not sure it is optimal. Currently, only JavaFX standard controls (e.g. Button, TextField) define a property for specifying a popup ContextMenu. Yet I wanted to have a popup menu appear anywhere in a Pane, in my case a VBox.

I took the approach of extending VBox to support a context menu. It is a 'clunky' solution but works. Is there a better approach? Am I missing some fundamental concept?

Here is my solution...

FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import custommenu.view.ContextMenuPane?>

<AnchorPane xmlns:fx="http://javafx.com/fxml" fx:controller="custommenu.controller.CustomMenuController">
    <children>
        <VBox fx:id="vbox" onContextMenuRequested="#showMenu"
            onMousePressed="#hideMenu" prefHeight="200" prefWidth="200">
        </VBox>
        <ContextMenuPane>
            <contextMenu>
                <ContextMenu fx:id="menu">
                    <items>
                        <MenuItem text="add" onAction="#add" />
                    </items>
                </ContextMenu>
            </contextMenu>
        </ContextMenuPane>
    </children>
</AnchorPane>

CustomMenuPane...

package custommenu.view;

import javafx.scene.control.ContextMenu;
import javafx.scene.layout.Pane;

public class ContextMenuPane extends Pane {

    private ContextMenu contextMenu;

    public void setContextMenu(ContextMenu contextMenu) {
        this.contextMenu = contextMenu;
    }

    public ContextMenu getContextMenu() {
        return contextMenu;
    }

}

Controller...

package custommenu.controller;

import javafx.fxml.FXML;
import javafx.scene.control.ContextMenu;
import javafx.scene.input.ContextMenuEvent;
import javafx.scene.layout.VBox;

public class CustomMenuController {

    @FXML private VBox vbox;
    @FXML private ContextMenu menu;

    @FXML public void add() {
        System.out.println("add");
    }

    @FXML
    public void showMenu(ContextMenuEvent event) {
        System.out.println("showMenu");

        menu.show(vbox, event.getScreenX(), event.getScreenY());
        event.consume();
    }

    @FXML public void hideMenu() {
        menu.hide();
    }
}

Main App...

package custommenu;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public class CustomMenuApplication extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        Pane myPane = (Pane)FXMLLoader.load(getClass().getResource("/custommenu/custom_menu_main.fxml"));
        Scene scene = new Scene(myPane);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

     public static void main(String[] args) {
         launch(args);
     }
}
1
6
7/7/2013 11:37:20 AM

In This example there is button which has context menu when click on left/right it will open the popup when you click on other area except button it will hide the popup context menu

public class Main extends Application{

public static void main(String[] args) {
    launch(args);
  }
  @Override
  public void start(Stage stage) {
    Scene scene = new Scene(new Group(), 450, 250);
    Button notification = new Button();

    MenuItem item1 = new MenuItem("About");
    item1.setOnAction(new EventHandler<ActionEvent>() {
      public void handle(ActionEvent e) {
        System.out.println("About");
      }
    });
    MenuItem item2 = new MenuItem("Preferences");
    item2.setOnAction(new EventHandler<ActionEvent>() {
      public void handle(ActionEvent e) {
        System.out.println("Preferences");
      }
    });

    MenuItem item3 = new MenuItem("About");
    item1.setOnAction(new EventHandler<ActionEvent>() {
      public void handle(ActionEvent e) {
        System.out.println("About");
      }
    });
    MenuItem item4 = new MenuItem("Preferences");
    item2.setOnAction(new EventHandler<ActionEvent>() {
      public void handle(ActionEvent e) {
        System.out.println("Preferences");
      }
    });
    MenuItem item5 = new MenuItem("About");
    item1.setOnAction(new EventHandler<ActionEvent>() {
      public void handle(ActionEvent e) {
        System.out.println("About");
      }
    });
    MenuItem item6 = new MenuItem("Preferences");
    item2.setOnAction(new EventHandler<ActionEvent>() {
      public void handle(ActionEvent e) {
        System.out.println("Preferences");
      }
    });

    MenuItem item7 = new MenuItem("About");
    item1.setOnAction(new EventHandler<ActionEvent>() {
      public void handle(ActionEvent e) {
        System.out.println("About");
      }
    });
    MenuItem item8 = new MenuItem("Preferences");
    item2.setOnAction(new EventHandler<ActionEvent>() {
      public void handle(ActionEvent e) {
        System.out.println("Preferences");
      }
    });
    final ContextMenu contextMenu = new ContextMenu(item1, item2,item3, item4,item5, item6,item7, item8);
    contextMenu.setMaxSize(50, 50);

    contextMenu.setOnShowing(new EventHandler<WindowEvent>() {
      public void handle(WindowEvent e) {
        System.out.println("showing");
      }
    });
    contextMenu.setOnShown(new EventHandler<WindowEvent>() {
      public void handle(WindowEvent e) {
        System.out.println("shown");
      }
    });

   // contextMenu.hide();


    notification.setContextMenu(contextMenu);
    GridPane grid = new GridPane();
    grid.setVgap(4);
    grid.setHgap(10);
    grid.setPadding(new Insets(5, 5, 5, 5));
    grid.add(new Label("To: "), 0, 0);
    grid.add(notification, 1, 0);

    Group root = (Group) scene.getRoot();
    root.getChildren().add(grid);
    stage.setScene(scene);
    stage.show();
    notification.addEventHandler(MouseEvent.MOUSE_CLICKED, (MouseEvent me)->{
        if(me.getButton()==MouseButton.PRIMARY ){
            System.out.println("Mouse Left Pressed");
            System.out.println(notification.getScaleX());
            System.out.println(notification.getScaleY());
            System.out.println(me.getScreenX());
            System.out.println(me.getScreenY());
            contextMenu.show(notification,me.getScreenX(),me.getScreenY());
        }else{
            contextMenu.hide();
        }
    });
  }

}

0
3/11/2015 9:46:42 AM

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