按下按钮时如何检测鼠标在节点上的移动?
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_OVER
或 MOUSE_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);
}
});
问题
您可以将事件侦听器添加到检测鼠标在其上移动的节点。如果在移动到节点之前按下鼠标按钮,这将不起作用。
问题
有谁知道按下按钮时如何检测鼠标移动?到目前为止,我只找到了使用 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_OVER
或 MOUSE_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);
}
});