web-dev-qa-db-ja.com

ポップアップメニューの作成方法

私はjavafxの初心者です。右クリックでポップアップメニューを表示したい。チュートリアル ここここ が1つありますが、理解できません。このリンクの画像に表示されるポップアップメニューを作成したい。

現在、ステージを作成していますが、ステージは必要ありません。右クリックで表示されるポップアップメニューを表示して、どこかをクリックすると閉じる必要があります。

これが私がステージを使用しているコードですが、上記のリンクのようなポップアップメニューを操作する必要があります。

 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();

    }

リンクまたは参照を提供してください。

12

コードのコンテキストはあまり明確ではありません。これはイベントハンドラ内にありますか?もしそうなら、それは何のためのイベントハンドラですか?そうでない場合、最初のeventステートメントのifは何ですか?

提供する2つのリンクはかなり複雑です。 JavaFXでは(Swingとは異なり)、かなり高度なユースケースでは、既存のNodeクラスのサブクラス化のみを検討する必要があります。ポップアップメニューを作成するためだけに、このレベルの複雑さは必要ありません。

ポップアップメニューを作成する最も簡単な方法は、Control(またはサブクラス)を使用することです。 ContextMenuを作成し、MenuItemsを追加して、コントロールでcontextMenuとして設定するだけです。

_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);
_

NodeでContextMenuを使用する場合、Control(a PaneまたはShapeではありませんたとえば)、setContextMenu(...)メソッドがないため、もう少し作業が必要です。

_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());
        }
    }
});
_

詳細は Javadocs for ContextMenuまたは tutorial を参照してください。

24
James_D

James_Dはすでにチュートリアルと一致する実用的な例を提供していますが、私はそれで問題に遭遇しました。 Jamesは、タイプControlのすべてのNodeに対して、コンテキストメニューを開く正しい方法は Control.setContextMenu() を使用することであると述べていますが、チュートリアルに反しています非コントロールノードにコンテキストメニューを登録する正しい方法は、次のとおりです(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();
    });

これは、setContextMenuが舞台裏で行うことと一致しています。 ControlsのsetContextMenu実装は ContextMenuEvent を使用および消費しますが、notはマウスイベントを消費します。これは、ペインでMouseEventのリスナーを登録し、ペイン内のコントロールでsetContextMenuを使用する場合、コントロールを右クリックすると、実際に両方のコンテキストメニューが開きます。 MouseEventを消費します。 openjdk-8を使用したコードで、ペインにContextMenuEventリスナーを登録すると、この重複するコンテキストメニューの問題が解決されることがわかりました。

また、ペインに登録されたメニューは、ユーザーが他の場所をクリックしたときに、デフォルトでは閉じないこともわかりました。イベントを消費しないMOUSE_PRESSEDリスナーは、必要なときにメニューを閉じるようにします。

14
fuzzyBSc

James_Dのより高い答えは間違っています。その非コントロールペインを右クリックしても離れた場所にある場合、コンテキストメニューは自動的に非表示になりません。

私はfuzzyBScの答えが好きですが、これはより簡潔です。どちらも機能します。

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