web-dev-qa-db-fra.com

Comment créer un menu contextuel

Je suis novice sur javafx. Je veux afficher le menu contextuel sur clic droit de la souris. Je trouve un tutoriel ici et ici mais je ne comprends pas. Je veux créer un menu contextuel qui s'affiche en image sur ce lien. 

En ce moment, je crée une scène mais je ne veux pas de scène. J'ai besoin d'afficher un menu contextuel qui montre un clic droit et se ferme lorsque je clique n'importe où. 

Voici mon code dans lequel j'utilise stage mais je dois ouvrir un menu contextuel comme ci-dessus. 

 public void MouseClickedOnTree(MouseEvent event) {
if (event.isSecondaryButtonDown()) {

        System.out.println("secondary press");
        final Stage optionstage = new Stage();

        VBox vBox = new VBox(5);
        vBox.setMinHeight(50);
        vBox.setMinWidth(50);
        Button btnNewTestBed = new Button("New Testbed");
        btnNewTestBed.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                try {
                     optionstage.close();
                    stage.show();
                } catch (IOException ex) {
                    Exceptions.printStackTrace(ex);
                }
            }
        });
        Button btnOpenTestbed = new Button("Open Testbed");
        btnOpenTestbed.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                optionstage.close();

            }
        });
        optionstage.addEventHandler(KeyEvent.KEY_PRESSED, new EventHandler<KeyEvent>() {
            @Override
            public void handle(KeyEvent t) {
                if (t.getCode() == KeyCode.ESCAPE) {
                    System.out.println("click on escape");
                    //Stage sb = (Stage) label.getScene().getWindow();//use any one object
                    if(optionstage.isShowing())
                        optionstage.close();
                }
            }
        });

        vBox.getChildren().addAll(btnNewTestBed, btnOpenTestbed);
        optionstage.setScene(new Scene(vBox, 100, 100));
        //stage.setScene(new Scene(new Group(new Text(50,50, "my second window")))); 
        optionstage.setX(event.getSceneX());
        optionstage.setY(event.getScreenY());
        optionstage.initStyle(StageStyle.UNDECORATED);
        optionstage.show();

    }

Veuillez me fournir tout lien ou référence. 

11
Sandip Armal Patil

Le contexte de votre code n'est pas très clair: est-ce à l'intérieur d'un gestionnaire d'événements? Si oui, à quoi sert-il un gestionnaire d'événements? Si non, quelle est la variable event dans la déclaration d'ouverture if?

Les deux liens que vous fournissez sont assez complexes. sous JavaFX (contrairement à Swing), vous ne devriez envisager de sous-classer que les classes de nœuds existantes pour des cas d'utilisation assez avancés. Vous n'avez pas besoin de ce niveau de complexité pour créer un menu contextuel.

Le moyen le plus simple de créer un menu contextuel est d'utiliser une Control (ou une sous-classe); il vous suffit de créer une ContextMenu, d'y ajouter MenuItems et de la définir comme contextMenu sur votre contrôle:

TextField textField = new TextField("Type Something"); // we will add a popup menu to this text field
final ContextMenu contextMenu = new ContextMenu();
MenuItem cut = new MenuItem("Cut");
MenuItem copy = new MenuItem("Copy");
MenuItem paste = new MenuItem("Paste");
contextMenu.getItems().addAll(cut, copy, paste);
cut.setOnAction(new EventHandler<ActionEvent>() {
    @Override
    public void handle(ActionEvent event) {
        System.out.println("Cut...");
    }
});
// ...
textField.setContextMenu(contextMenu);

Si vous voulez utiliser une ContextMenu sur un nœud qui n'est pas une Control (une Pane ou une Shape, par exemple), vous n'avez pas de méthode setContextMenu(...), vous avez donc besoin d'un peu plus de travail:

final AnchorPane pane = new AnchorPane();
// fill pane with nodes, etc
// create context menu and menu items as above
pane.setOnMousePressed(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent event) {
        if (event.isSecondaryButtonDown()) {
            contextMenu.show(pane, event.getScreenX(), event.getScreenY());
        }
    }
});

Voir le Javadocs for ContextMenu ou le tutorial pour plus de détails.

23
James_D

James_D a déjà fourni un exemple de travail cohérent avec les tutoriels, mais j'ai rencontré des problèmes avec celui-ci. James a raison de dire que pour tout nœud de type Control, la manière correcte d’ouvrir le menu contextuel consiste à utiliser Control.setContextMenu () . Cependant, contrairement au didacticiel, la méthode correcte pour enregistrer un menu contextuel sur des nœuds non-Control est la suivante (Java 8):

    pane.addEventHandler(ContextMenuEvent.CONTEXT_MENU_REQUESTED, event -> {
        contextMenu.show(pane, event.getScreenX(), event.getScreenY());
        event.consume();
    });
    pane.addEventHandler(MouseEvent.MOUSE_PRESSED, event -> {
        contextMenu.hide();
    });

Ceci est cohérent avec ce que setContextMenu fait en coulisse. L'implémentation setContextMenu de Controls utilise et consomme ContextMenuEvent mais not ne consomme pas l'événement de la souris. Cela signifie que si vous enregistrez un écouteur pour MouseEvent dans un volet et que vous utilisez setContextMenu sur un contrôle dans le volet, un clic droit sur le contrôle ouvrira les deux menus contextuels: et consomme le MouseEvent. J'ai découvert dans mon code avec openjdk-8 que l'enregistrement d'un écouteur ContextMenuEvent dans le volet résout ce problème de menu contextuel en double.

J'ai également constaté qu'un menu enregistré sur un volet ne disparaît pas par défaut lorsque l'utilisateur clique ailleurs. L'écouteur MOUSE_PRESSED qui ne consomme pas son événement garantit que le menu est ignoré alors qu'il devrait l'être.

14
fuzzyBSc

La réponse de James_D en haut est fausse. Si vous cliquez avec le bouton droit de la souris sur ce volet non contrôlé, mais que vous cliquez à l'extérieur, le menu contextuel ne se cache pas. 

J'aime la réponse de fuzzyBSc, mais celle-ci est plus succincte. Les deux vont marcher. 

pane.setOnContextMenuRequested(e -> 
contextMenu.show(pane, e.getScreenX(), e.getScreenY()));
0
trilogy