How to detect mouse movement over a node while a button is clicked?

Problem

You can add an event listener to the node that detects mouse movement above it. This does not work if the mouse button was pressed before you navigated through the node.

Question

Does anyone know how to detect mouse movement at the click of a button? So far, I have found a solution using the MOUSE_DRAGGED event, and then instead of using getSource () with getPickResult () and evaluating PickResult .

Here is the code including Uluk's solution. The old and new solution can be switched using useNewVersion (Uluk version) boolean:

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

In the end, you can draw using the main mouse button and erase the paint using the additional mouse button:

enter image description here

+6
source share
2 answers

(source) a node that processes the initial DRAG_DETECTED event should call sourceNode.startFullDrag() , then the target node will be able to handle one of MouseDragEvent s, for example, the MOUSE_DRAG_OVER or MOUSE_DRAG_ENTERED event with the corresponding method targetNode.setOn<MouseDragEvent>() .

+2
source

One solution is to add an event filter to the scene, which allows sourceNode.startFullDrag (). This will work even if you start dragging the mouse outside of your canvas (if you want any space without nodes in your application).

Like this:

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

And then you could:

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

Source: https://habr.com/ru/post/986798/


All Articles