如何使JavaFX上下文菜单中的MenuItems支持onMouseOver事件

如何使JavaFX上下文菜单中的MenuItems支持onMouseOver事件,java,javafx-2,javafx,contextmenu,menuitem,Java,Javafx 2,Javafx,Contextmenu,Menuitem,我正在寻找一些关于如何处理我遇到的问题的指导。我有一个JavaFX场景,其中有一些节点(形状)通过一条或多条线相互连接。我可以右键单击某个形状以打开关联菜单。假设这个刚刚右键单击的特定形状有3行(称为line1、line2、line3),您希望使用关联菜单删除其中一行。例如,您可以选择“line2”,它将触发onAction事件以删除该行。一切正常 问题是,您不知道屏幕上的3行中的哪一行是line1、line2或line3(当然,除非它们有标签),因此在删除之前,您不知道要删除哪一行。例如,我真

我正在寻找一些关于如何处理我遇到的问题的指导。我有一个JavaFX场景,其中有一些节点(形状)通过一条或多条线相互连接。我可以右键单击某个形状以打开关联菜单。假设这个刚刚右键单击的特定形状有3行(称为line1、line2、line3),您希望使用关联菜单删除其中一行。例如,您可以选择“line2”,它将触发onAction事件以删除该行。一切正常

问题是,您不知道屏幕上的3行中的哪一行是line1、line2或line3(当然,除非它们有标签),因此在删除之前,您不知道要删除哪一行。例如,我真正想做的是将鼠标放在关联菜单中的“line2”上,并使场景中的line2更改颜色或其他指示它将被删除的内容(在单击鼠标之前)。但是,我看到MenuItem支持的唯一事件是单击时的onAction事件。有没有什么方法可以让它具有onMouseOver功能?如果没有,该功能如何实现


谢谢

这是我刚刚在aproach上创建的一个示例应用程序,用于识别行:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Tooltip;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.stage.Stage;

public class MainTest extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        // TODO Auto-generated method stub
        AnchorPane anchorPane = new AnchorPane();
        Scene scene = new Scene(anchorPane);
        stage.setScene(scene);

        Line linea = new Line(0, 0, 50, 50);
        linea.setFill(Color.BLACK);
        final Tooltip t = new Tooltip("Line 1");
        linea.setOnMouseEntered(new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {
                Line line = (Line) event.getSource();
                line.setStroke(Color.RED);

                t.show((Line) event.getSource(), event.getScreenX(),
                        event.getScreenY());

            }
        });
        linea.setOnMouseExited(new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent event) {
                Line line = (Line) event.getSource();
                line.setStroke(Color.BLACK);
                t.hide();
            }
        });
        anchorPane.getChildren().add(linea);
        stage.show();
    }
}
导入javafx.application.application;
导入javafx.event.EventHandler;
导入javafx.scene.scene;
导入javafx.scene.control.Tooltip;
导入javafx.scene.input.MouseEvent;
导入javafx.scene.layout.ancorpane;
导入javafx.scene.paint.Color;
导入javafx.scene.shape.Line;
导入javafx.stage.stage;
公共类MainTest扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
public void start(Stage)引发异常{
//TODO自动生成的方法存根
锚烷锚烷=新锚烷();
场景=新场景(anchorPane);
舞台场景;
linea=新行(0,0,50,50);
线条。刚毛填充(颜色。黑色);
最终工具提示t=新工具提示(“第1行”);
linea.setonmouseintered(新的EventHandler(){
@凌驾
公共无效句柄(MouseeEvent事件){
Line=(Line)event.getSource();
直线调整行程(颜色为红色);
t、 显示((行)event.getSource(),event.getScreenX(),
event.getScreenY());
}
});
linea.setOnMouseExited(新的EventHandler(){
@凌驾
公共无效句柄(MouseeEvent事件){
Line=(Line)event.getSource();
线。设定行程(颜色。黑色);
t、 隐藏();
}
});
anchorPane.getChildren().add(linea);
stage.show();
}
}
希望有帮助

试试这个SSCCE:

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.effect.DropShadow;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class ContextMenuDemo extends Application {

    private DropShadow ds = new DropShadow();

    @Override
    public void start(Stage primaryStage) {

        final Line line1 = new Line(60, 10, 150, 10);
        final Line line2 = new Line(60, 30, 150, 50);
        final Line line3 = new Line(60, 60, 150, 90);

        final ContextMenu cm = new ContextMenu();
        cm.getItems().add(getMenuItemForLine("line 1", line1));
        cm.getItems().add(getMenuItemForLine("line 2", line2));
        cm.getItems().add(getMenuItemForLine("line 3", line3));

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

        Group root = new Group();
        root.getChildren().addAll(rectangle, line1, line2, line3);
        Scene scene = new Scene(root, 300, 250);
        // load style of modified paddings for menuitems
        scene.getStylesheets().add(getClass().getResource("style.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private MenuItem getMenuItemForLine(String menuName, final Line line) {

        Label menuLabel = new Label(menuName);
        // apply style to occupy larger space for label
        menuLabel.setStyle("-fx-padding: 5 10 5 10");
        MenuItem mi = new MenuItem();
        mi.setGraphic(menuLabel);
        line.setStroke(Color.BLUE);

        menuLabel.addEventHandler(MouseEvent.MOUSE_ENTERED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                line.setStroke(Color.RED);
                line.setEffect(ds);
            }
        });

        menuLabel.addEventHandler(MouseEvent.MOUSE_EXITED, new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent event) {
                line.setStroke(Color.BLUE);
                line.setEffect(null);
            }
        });

        return mi;
    }

    public static void main(String[] args) {
        launch(args);
    }
}
截图:

说明:

这是一个MenuItem不适用于
MenuItem.addEventHandler(MouseEvent.MOUSE_ENTERED,…)
的bug。作为一种解决方法,我们定义了新的
标签
,向其注册事件处理程序,并将其设置为菜单项的图形,而menuitem的文本(标签)故意留下一个空标签。但是菜单项的图形(默认情况下)并没有占用菜单项的所有空间,因此在菜单项的边缘没有正确处理鼠标事件。为了克服这个问题,我们通过css重置menuitem的所有填充、menuitem的标签和图形。您可以通过注释上述代码中的样式加载来观察这一点。

您想在鼠标上方显示上下文菜单吗?我理解上述内容,但可能我的问题不够清楚。我希望线条不是在鼠标上方而是在鼠标位于上下文菜单中的某个项目上时改变颜色。因此,上下文菜单可能有两行——“line1”和“line2”。如果鼠标位于上下文菜单中显示“line1”的行上,则line1将变为红色。如果将您已有的代码。。。我只是从零开始创建的,如果我能修改你的代码会更容易。谢谢Uluk Biy!这正是我想要的效果。很好的解决方法。
.menu-item {
/*    -fx-skin: "com.sun.javafx.scene.control.skin.MenuItemSkin";*/
    -fx-background-color: transparent;
    -fx-padding: 0em; /* do not pad for item. we want to ccupy all spaces for graphics only */
}

.menu-item:focused {
     -fx-background: -fx-accent;
     -fx-background-color: -fx-selection-bar;
     -fx-text-fill: -fx-selection-bar-text;
}

.menu-item .graphic-container {
    -fx-padding: 0em; /* do not pad for graphics, label graphic pads itself */
}

.menu-item .label {
    -fx-padding: 0em;  /* do not pad for label, since there is no label text set */
    -fx-text-fill: -fx-text-base-color;
}