0

I couldn't really explain the question in the title.

What I want to do is that when a right mouse-press (not click!) is performed on a element a ContextMenu shows up (this part is easy). The problem is that when I (still holding the mouse button) move my cursor over the items they do not get highlighted and when I release the mouse button the MenuItem does not get selected. The ContextMenu does not seem to be aware of the cursor until I release the button from the press that opened it.

Basically a right mouse-press shows a ContextMenu and releasing the button over a MenuItem should select it. What I am talking about is available in basically every single program (browsers, IDEs, etc.).

var contextMenu = new ContextMenu();
var mi1 = new MenuItem("Item 1");
mi1.setOnAction(e -> System.out.println("Item 1"));
var mi2 = new MenuItem("Item 2");
mi2.setOnAction(e -> System.out.println("Item 2"));
contextMenu.getItems().addAll(mi1, mi2);

node.setOnMousePressed(e -> {
    if (e.getButton() == MouseButton.SECONDARY)
        contextMenu.show(node, e.getScreenX(), e.getScreenY());
});
Nand
  • 568
  • 3
  • 18
  • Are you wanting to open the `ContextMenu` with the right mouse button, then while the mouse button is still pressed, release it over a `MenuItem` to fire it? – Dustin Jun 25 '20 at 20:58
  • @DustinR Exactly! I also want the MenuItem to be highlighted ("focused") when the cursor is over it but that's not as important as the firing. – Nand Jun 25 '20 at 21:12
  • why do you want to confuse your users? the open mouse gesture for opening a context menu is OS dependent .. – kleopatra Jun 26 '20 at 05:54
  • It's like that on basically all Linux-based OSes, Windows and Mac. It shouldn't confuse anybody, just introduce more convenience because it works like other parts of the OS. – Nand Jun 26 '20 at 11:20
  • I used "hacky" methods of casting and looking up elements and while it seems a bit off, it works as I want it to and is far better than nothing. Might publish my solution if I can make it good enough. – Nand Jun 26 '20 at 14:41

1 Answers1

0

If you want to show the ContextMenu when the right mouse button is clicked, the following will work.

        node.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
            // If the menu is already open, then close it to avoid multiple
            if (cm.isShowing()) {
                cm.hide();
            }
            if (e.isSecondaryButtonDown()) {
                cm.show(stage);
            }
        });

As for then moving the mouse to a MenuItem and releasing the already pressed secondary mouse button to activate the MenuItem, this doesn't seem to be supported.

The MenuItem's onAction is called by default even if the MouseButton is the secondary MouseButton, so unless you implement your own control, then this will be the best you can get.

I've included a complete runnable example of the behavior that I've described below:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

public class Main extends Application {

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        Button buttonTest = new Button("Right-Click me!");
        stage.setScene(new Scene(buttonTest));
        stage.show();

        ContextMenu cm = new ContextMenu();
        MenuItem miTest = new MenuItem("Test");
        miTest.setOnAction(e -> new
                Alert(Alert.AlertType.INFORMATION,"Test").showAndWait());
        cm.getItems().add(miTest);
        buttonTest.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
            if (cm.isShowing()) {
                cm.hide();
            }
            if (e.isSecondaryButtonDown()) {
                cm.show(stage);
                e.consume();
            }
        });
    }
}

Note: If you can give an example of an application that exhibits this behavior, maybe I could look into it further and see if there's an equivalent implementation in JavaFX. You mention IDEs, browsers, etc. but I'm unable to reproduce what I think you're describing.

Dustin
  • 693
  • 8
  • 20
  • I'm afraid this answer does not add anything to the question. My code already shows the context menu on secondary mouse-press and does it in a much simpler way with same unwanted end result of the ContextMenu not detecting movements over it while the button is held. – Nand Jun 25 '20 at 22:06
  • As `MenuItem` doesn't have a `.addEventFilter` and only a `.setOnAction` I don't think that you can get the behavior you want without some serious tweaking. You'd have to create your own version of `ContextMenu` from what I can tell. – Dustin Jun 25 '20 at 22:23
  • I tried some workarounds with suggestions from https://stackoverflow.com/questions/27332981/contextmenu-and-programmatically-selecting-an-item but it got complex and messy so I thought I'd ask here. My initial thought was to add an event listener to the scene property of ContextMenu (getScene). – Nand Jun 25 '20 at 22:27
  • I also found this https://stackoverflow.com/questions/10315774/javafx-2-0-activating-a-menu-like-a-menuitem/38525867#38525867 but couldn't succeed. – Nand Jun 25 '20 at 22:28
  • You could always hack a solution together by getting the X & Y of the MenuItem and adding event filter for MouseEvent.MOUSE_RELEASED, then call menuItem.fire() if the mouse were within bounds, but this just seems like over-engineering. – Dustin Jun 25 '20 at 22:44