JavaFX: Right click on menuitem


Question

I have been wondering that why was JavaFX MenuItems designed to do the designated action on a right click? Usually a menu item in any windows application is supposed to act on a left click of a mouse but in JavaFX it seen that both clicks act equally.

On another thought, is there a way to block a right click on MenuItems? I tried the following code, but it fails.

It looks like the event handler does not get registered at all.

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.Label;
import javafx.scene.control.MenuItem;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class ContextMenuDemo extends Application
{

@Override
public void start(Stage primaryStage)
{

    final ContextMenu cm = new ContextMenu();


    MenuItem menuItem1 = getMenuItemForLine("line 1");
    MenuItem menuItem2 = getMenuItemForLine("line 2");
    MenuItem menuItem3 = getMenuItemForLine("line 3");

    menuItem1.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>()
    {
        @Override
        public void handle(MouseEvent e)
        {
            if (e.getButton() == MouseButton.SECONDARY)
            {
                System.out.println("Desired Click");
            }
            else
            {
                System.out.println("No right click");
            }
            e.consume();
        }
    });

    menuItem2.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>()
    {
        @Override
        public void handle(MouseEvent e)
        {
            if (e.getButton() == MouseButton.SECONDARY)
            {
                System.out.println("Desired Click");
            }
            else
            {
                System.out.println("No right click");
            }
            e.consume();
        }
    });

    menuItem3.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>()
    {
        @Override
        public void handle(MouseEvent e)
        {
            if (e.getButton() == MouseButton.SECONDARY)
            {
                System.out.println("Desired Click");
            }
            else
            {
                System.out.println("No right click");
            }
            e.consume();
        }
    });


    cm.getItems().add(menuItem1);
    cm.getItems().add(menuItem2);
    cm.getItems().add(menuItem3);

    final Rectangle rectangle = new Rectangle(70, 70, Color.TAN);
    rectangle.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>()
    {
        @Override
        public void handle(MouseEvent e)
        {
            if (e.getButton() == MouseButton.SECONDARY)
            {
                cm.show(rectangle, e.getScreenX(), e.getScreenY());
            }
            else
            {
                System.out.println("No right click");
            }
        }
    });

    Group root = new Group();
    root.getChildren().addAll(rectangle);
    Scene scene = new Scene(root, 350, 250);
    primaryStage.setScene(scene);
    primaryStage.show();
}

private MenuItem getMenuItemForLine(String menuName)
{
    Label menuLabel = new Label(menuName);
    MenuItem menuItem = new MenuItem();
    menuItem.setGraphic(menuLabel);
    return menuItem;
}

public static void main(String[] args)
{
    launch(args);
}
}
1
2
3/4/2014 1:18:00 PM

Accepted Answer

You have lots of extraneous code. I removed some. The way to stop events is in the filtering. You have to find out when an event gets fired, selected seems to happen on pressed and onAction happens on released. The two events together on one node makes a click.

No need to add a handler to each menu item, and even then you could just re-use the same one. The parent menus get the onAction event.

package contextmenudemo;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.MenuItem;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class ContextMenuDemo extends Application {

    @Override
    public void start(Stage primaryStage) {

        final ContextMenu cm = new ContextMenu();
        cm.addEventFilter(MouseEvent.MOUSE_RELEASED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                if (event.getButton() == MouseButton.SECONDARY) {
                    System.out.println("consuming right release button in cm filter");
                    event.consume();
                }
            }
        });
        cm.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                System.out.println("right gets consumed so this must be left on "+
                        ((MenuItem)event.getTarget()).getText());
            }
        });

        MenuItem menuItem1 = new MenuItem("line 1");
        MenuItem menuItem2 = new MenuItem("line 2");
        MenuItem menuItem3 = new MenuItem("line 3");

        cm.getItems().addAll(menuItem1, menuItem2, menuItem3);

        final Rectangle rectangle = new Rectangle(70, 70, Color.TAN);
        rectangle.addEventHandler(MouseEvent.MOUSE_CLICKED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent e) {
                if (e.getButton() == MouseButton.SECONDARY) {
                    cm.show(rectangle, e.getScreenX(), e.getScreenY());
                } else {
                    System.out.println("No right click");
                }
            }
        });

        Group root = new Group();
        root.getChildren().addAll(rectangle);
        Scene scene = new Scene(root, 350, 250);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}
7
3/4/2014 2:24:32 PM

Have you tried to put in

e.consume();

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