3

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

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

谢谢!

4

2 回答 2

2

试试这个 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);
    }
}

用 style.css

.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;
}

截屏:

截屏

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

于 2013-10-10T18:10:10.337 回答
0

这是我刚刚创建的一个示例应用程序,用于识别线条:

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

希望能帮助到你!

于 2013-10-10T11:34:25.287 回答