按下按钮时如何检测鼠标在节点上的移动?

How to detect mouse movement over node while button is pressed?

问题

您可以将事件侦听器添加到检测鼠标在其上移动的节点。如果在移动到节点之前按下鼠标按钮,这将不起作用。

问题

有谁知道按下按钮时如何检测鼠标移动?到目前为止,我只找到了使用 MOUSE_DRAGGED event and then instead of using getSource() using getPickResult() and evaluating the PickResult 数据的解决方案。

这是包含 Uluk 解决方案的代码。新旧解决方案可通过 useNewVersion(Uluk 的版本)布尔值进行切换:

import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.input.PickResult;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class Main extends Application {

    boolean useNewVersion= true;

    int rows = 10;
    int columns = 20;
    double width = 1024;
    double height = 768;

    @Override
    public void start(Stage primaryStage) {
        try {
            BorderPane root = new BorderPane();

            // create grid
            Grid grid = new Grid( columns, rows, width, height);

            MouseGestures mg = new MouseGestures();

            // fill grid
            for (int row = 0; row < rows; row++) {
                for (int column = 0; column < columns; column++) {

                    Cell cell = new Cell(column, row);

                    mg.makePaintable(cell);

                    grid.add(cell, column, row);
                }
            }

            root.setCenter(grid);

            // create scene and stage
            Scene scene = new Scene(root, width, height);
            scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
            primaryStage.setScene(scene);
            primaryStage.show();



        } catch (Exception e) {
            e.printStackTrace();
        }
    }

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

    private class Grid extends Pane {

        int rows;
        int columns;

        double width;
        double height;

        Cell[][] cells;

        public Grid( int columns, int rows, double width, double height) {

            this.columns = columns;
            this.rows = rows;
            this.width = width;
            this.height = height;

            cells = new Cell[rows][columns];

        }

        /**
         * Add cell to array and to the UI.
         */
        public void add(Cell cell, int column, int row) {

            cells[row][column] = cell;

            double w = width / columns;
            double h = height / rows;
            double x = w * column;
            double y = h * row;

            cell.setLayoutX(x);
            cell.setLayoutY(y);
            cell.setPrefWidth(w);
            cell.setPrefHeight(h);

            getChildren().add(cell);

        }

    }

    private class Cell extends StackPane {

        int column;
        int row;

        public Cell(int column, int row) {

            this.column = column;
            this.row = row;

            getStyleClass().add("cell");

            Label label = new Label(this.toString());

            getChildren().add(label);
        }

        public void highlight() {
            getStyleClass().add("cell-highlight");
        }

        public void unhighlight() {
            getStyleClass().remove("cell-highlight");
        }

        public String toString() {
            return this.column + "/" + this.row;
        }
    }

    public class MouseGestures {

        public void makePaintable( Node node) {

            if( useNewVersion) {

                node.setOnMousePressed( onMousePressedEventHandler);
                node.setOnDragDetected( onDragDetectedEventHandler);
                node.setOnMouseDragEntered( onMouseDragEnteredEventHandler);

            } else {

                node.setOnMousePressed( onMousePressedEventHandler);
                node.setOnMouseDragged( onMouseDraggedEventHandler);
                node.setOnMouseReleased( onMouseReleasedEventHandler);

            }

        }

        /* old version */

        EventHandler<MouseEvent> onMousePressedEventHandler = event -> {

            Cell cell = (Cell) event.getSource();

            if( event.isPrimaryButtonDown()) {
                cell.highlight();
            } else if( event.isSecondaryButtonDown()) {
                cell.unhighlight();
            }
        };

        EventHandler<MouseEvent> onMouseDraggedEventHandler = event -> {

            PickResult pickResult = event.getPickResult();
            Node node = pickResult.getIntersectedNode();

            if( node instanceof Cell) {

                Cell cell = (Cell) node;

                if( event.isPrimaryButtonDown()) {
                    cell.highlight();
                } else if( event.isSecondaryButtonDown()) {
                    cell.unhighlight();
                }       

            }

        };

        EventHandler<MouseEvent> onMouseReleasedEventHandler = event -> {
        };

        EventHandler<MouseEvent> onDragDetectedEventHandler = event -> {

            Cell cell = (Cell) event.getSource();
            cell.startFullDrag();

        };

        EventHandler<MouseEvent> onMouseDragEnteredEventHandler = event -> {

            Cell cell = (Cell) event.getSource();

            if( event.isPrimaryButtonDown()) {
                cell.highlight();
            } else if( event.isSecondaryButtonDown()) {
                cell.unhighlight();
            }       

        };

    }

}

最终你应该能够通过鼠标主键进行绘画并通过鼠标辅助键擦除绘画:

处理初始 DRAG_DETECTED 事件的(源)节点应调用 sourceNode.startFullDrag(),然后目标节点将能够处理 MouseDragEvent 之一,例如 MOUSE_DRAG_OVERMOUSE_DRAG_ENTERED 事件与相应的 targetNode.setOn<MouseDragEvent>() 方法。

一种解决方案是向启用 sourceNode.startFullDrag() 的场景添加事件过滤器。即使您开始将鼠标拖到 canvas 之外(如果您希望任何 space 在您的应用程序中没有节点),这也会起作用。

像这样:

scene.addEventFilter(MouseEvent.DRAG_DETECTED , new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent mouseEvent) {
        scene.startFullDrag();
    }
});

然后你可以:

node.setOnMouseDragEntered(new EventHandler<MouseEvent>() {
    @Override
    public void handle(MouseEvent event) {
        led.setOn(true);
    } 
});