I have a working example for defining ContextMenu in a panel in JavaFX FXML, but I'm not sure if it is optimal. Currently, only standard JavaFX controls (such as Button, TextField) define a property to specify the ContextMenu popup. However, I wanted the popup menu to appear anywhere on the panel, in my case VBox.
I used the VBox approach to support the context menu. This is a "clumsy" solution, but it works. Is there a better approach? Is any fundamental concept missing?
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(); } }
The main application ...
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); } }
source share