JavaFX 检测鼠标事件
JavaFX detecting mouse events
我正在尝试将节点从一个 window 拖放到另一个。该代码创建了两个 windows 并向其中一个添加了一个可拖动标签。目标是将节点从一个 window 移动到另一个,然后再移动回来。这是我目前拥有的。
public class Main extends Application {
private static Node transferNode;
@Override
public void start(Stage primaryStage) {
initFirstWindow();
initSecondWindow();
}
public static void initFirstWindow() {
BorderPane borderPane = new BorderPane();
Label label = new Label("clickable");
label.setOnDragDetected(event -> {
label.startFullDrag();
System.out.println("Full drag");
event.consume();
});
borderPane.setCenter(label);
Stage stage = new Stage();
stage.setTitle("Window number 1");
stage.setScene(new Scene(borderPane, 300, 275));
makeSceneDragAware(stage.getScene());
stage.show();
}
public static void initSecondWindow() {
Stage stage = new Stage();
stage.setTitle("Window number 2");
stage.setScene(new Scene(new BorderPane(), 300, 275));
makeSceneDragAware(stage.getScene());
stage.show();
}
public static void makeSceneDragAware(Scene scene) {
scene.setOnMouseDragReleased(event -> {
System.out.println("Released drag");
if (transferNode != null) {
((BorderPane)scene.getRoot()).setCenter(transferNode);
transferNode = null;
event.consume();
}
});
}
public static void main(String[] args) {
launch(args);
}
}
问题在于,在目标 window 上方释放时 setOnMouseDragReleased
不会被触发。它仅在与拖动节点相同的 window 中触发。
更新:
进行更新以希望获得更多牵引力。我想指出一些使用 JavaFX 的 D&D 功能的代码。
public class Main extends Application {
private final DataFormat NODE_TYPE = new DataFormat("transferable-node");
private Node transferNode;
@Override
public void start(Stage primaryStage) {
initFirstWindow();
initSecondWindow();
}
public void initFirstWindow() {
BorderPane borderPane = new BorderPane();
Label label = new Label("clickable");
label.setOnDragDetected(event -> {
System.out.println("Full drag");
Dragboard db = label.startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();
transferNode = label;
content.put(NODE_TYPE, "");
db.setContent(content);
event.consume();
});
borderPane.setCenter(label);
Stage stage = new Stage();
stage.setTitle("Window number 1");
stage.setScene(new Scene(borderPane, 300, 275));
makeSceneDragAware(stage.getScene());
stage.show();
}
public void initSecondWindow() {
Stage stage = new Stage();
stage.setTitle("Window number 2");
stage.setScene(new Scene(new BorderPane(), 300, 275));
makeSceneDragAware(stage.getScene());
stage.show();
}
public void makeSceneDragAware(Scene scene) {
scene.setOnDragOver(event -> {
event.acceptTransferModes(TransferMode.ANY);
event.consume();
});
scene.setOnDragDropped(event -> {
if (transferNode != null) {
((BorderPane)scene.getRoot()).setCenter(transferNode);
transferNode = null;
event.setDropCompleted(true);
event.consume();
}
});
}
public static void main(String[] args) {
launch(args);
}
}
这段代码在技术上可以工作并满足在两个 windows 之间移动节点的目标,但是它对我不起作用,因为我不希望任何被拖动的元素与外部进行拖动交互程式。使用 D&D 还将停止触发我应用程序其他部分所需的 setOnMouseDragged
事件。
所以我已经通过以下代码实现了目标。
public class Main extends Application {
private Node transferNode;
private final ArrayList<Stage> stageList = new ArrayList<>();
@Override
public void start(Stage primaryStage) {
initFirstWindow();
initSecondWindow();
}
public void initFirstWindow() {
BorderPane borderPane = new BorderPane();
Label label = new Label("clickable");
label.setOnDragDetected(event -> {
label.startFullDrag();
transferNode = label;
});
label.setOnMouseReleased(event -> {
Point point = MouseInfo.getPointerInfo().getLocation().getLocation();
Stage stage = windowUnderPoint(point);
if (stage != null) {
MouseDragEvent mouseEvent = new MouseDragEvent(
MouseDragEvent.MOUSE_DRAG_RELEASED, 0, 0, point.getX(), point.getY(),
MouseButton.PRIMARY, 1,
false, false, false, false, false, false, false,
false, false, new PickResult(stage, point.getX(), point.getY()), label);
stage.fireEvent(mouseEvent);
}
});
borderPane.setCenter(label);
Stage stage = new Stage();
stage.setTitle("Window number 1");
stage.setScene(new Scene(borderPane, 300, 275));
stage.setX(400);
makeStageDragAware(stage);
stage.show();
stageList.add(stage);
}
public void initSecondWindow() {
Stage stage = new Stage();
stage.setTitle("Window number 2");
stage.setScene(new Scene(new BorderPane(), 300, 275));
stage.setX(800);
makeStageDragAware(stage);
stage.show();
stageList.add(stage);
}
public void makeStageDragAware(Stage stage) {
stage.addEventHandler(MouseDragEvent.MOUSE_DRAG_RELEASED, event -> {
if (transferNode != null && transferNode.getScene().getWindow() != stage) {
((BorderPane) stage.getScene().getRoot()).setCenter(transferNode);
transferNode = null;
event.consume();
}
});
}
public Stage windowUnderPoint(Point point) {
for (Stage stage : stageList) {
if (inRange(stage.getX(), stage.getX() + stage.getWidth(), point.getX()) &&
inRange(stage.getY(), stage.getY() + stage.getHeight(), point.getY())) {
return stage;
}
}
return null;
}
public boolean inRange(double low, double high, double number) {
return (number >= low && number <= high);
}
public static void main(String[] args) {
launch(args);
}
}
基本上,当拖动节点被释放时,它会获取当前鼠标相对于显示器的坐标,并检查其下是否存在任何 known/registered 阶段。如果找到有效阶段,它将触发阶段 MOUSE_DRAG_RELEASED
事件。
我正在尝试将节点从一个 window 拖放到另一个。该代码创建了两个 windows 并向其中一个添加了一个可拖动标签。目标是将节点从一个 window 移动到另一个,然后再移动回来。这是我目前拥有的。
public class Main extends Application {
private static Node transferNode;
@Override
public void start(Stage primaryStage) {
initFirstWindow();
initSecondWindow();
}
public static void initFirstWindow() {
BorderPane borderPane = new BorderPane();
Label label = new Label("clickable");
label.setOnDragDetected(event -> {
label.startFullDrag();
System.out.println("Full drag");
event.consume();
});
borderPane.setCenter(label);
Stage stage = new Stage();
stage.setTitle("Window number 1");
stage.setScene(new Scene(borderPane, 300, 275));
makeSceneDragAware(stage.getScene());
stage.show();
}
public static void initSecondWindow() {
Stage stage = new Stage();
stage.setTitle("Window number 2");
stage.setScene(new Scene(new BorderPane(), 300, 275));
makeSceneDragAware(stage.getScene());
stage.show();
}
public static void makeSceneDragAware(Scene scene) {
scene.setOnMouseDragReleased(event -> {
System.out.println("Released drag");
if (transferNode != null) {
((BorderPane)scene.getRoot()).setCenter(transferNode);
transferNode = null;
event.consume();
}
});
}
public static void main(String[] args) {
launch(args);
}
}
问题在于,在目标 window 上方释放时 setOnMouseDragReleased
不会被触发。它仅在与拖动节点相同的 window 中触发。
更新: 进行更新以希望获得更多牵引力。我想指出一些使用 JavaFX 的 D&D 功能的代码。
public class Main extends Application {
private final DataFormat NODE_TYPE = new DataFormat("transferable-node");
private Node transferNode;
@Override
public void start(Stage primaryStage) {
initFirstWindow();
initSecondWindow();
}
public void initFirstWindow() {
BorderPane borderPane = new BorderPane();
Label label = new Label("clickable");
label.setOnDragDetected(event -> {
System.out.println("Full drag");
Dragboard db = label.startDragAndDrop(TransferMode.MOVE);
ClipboardContent content = new ClipboardContent();
transferNode = label;
content.put(NODE_TYPE, "");
db.setContent(content);
event.consume();
});
borderPane.setCenter(label);
Stage stage = new Stage();
stage.setTitle("Window number 1");
stage.setScene(new Scene(borderPane, 300, 275));
makeSceneDragAware(stage.getScene());
stage.show();
}
public void initSecondWindow() {
Stage stage = new Stage();
stage.setTitle("Window number 2");
stage.setScene(new Scene(new BorderPane(), 300, 275));
makeSceneDragAware(stage.getScene());
stage.show();
}
public void makeSceneDragAware(Scene scene) {
scene.setOnDragOver(event -> {
event.acceptTransferModes(TransferMode.ANY);
event.consume();
});
scene.setOnDragDropped(event -> {
if (transferNode != null) {
((BorderPane)scene.getRoot()).setCenter(transferNode);
transferNode = null;
event.setDropCompleted(true);
event.consume();
}
});
}
public static void main(String[] args) {
launch(args);
}
}
这段代码在技术上可以工作并满足在两个 windows 之间移动节点的目标,但是它对我不起作用,因为我不希望任何被拖动的元素与外部进行拖动交互程式。使用 D&D 还将停止触发我应用程序其他部分所需的 setOnMouseDragged
事件。
所以我已经通过以下代码实现了目标。
public class Main extends Application {
private Node transferNode;
private final ArrayList<Stage> stageList = new ArrayList<>();
@Override
public void start(Stage primaryStage) {
initFirstWindow();
initSecondWindow();
}
public void initFirstWindow() {
BorderPane borderPane = new BorderPane();
Label label = new Label("clickable");
label.setOnDragDetected(event -> {
label.startFullDrag();
transferNode = label;
});
label.setOnMouseReleased(event -> {
Point point = MouseInfo.getPointerInfo().getLocation().getLocation();
Stage stage = windowUnderPoint(point);
if (stage != null) {
MouseDragEvent mouseEvent = new MouseDragEvent(
MouseDragEvent.MOUSE_DRAG_RELEASED, 0, 0, point.getX(), point.getY(),
MouseButton.PRIMARY, 1,
false, false, false, false, false, false, false,
false, false, new PickResult(stage, point.getX(), point.getY()), label);
stage.fireEvent(mouseEvent);
}
});
borderPane.setCenter(label);
Stage stage = new Stage();
stage.setTitle("Window number 1");
stage.setScene(new Scene(borderPane, 300, 275));
stage.setX(400);
makeStageDragAware(stage);
stage.show();
stageList.add(stage);
}
public void initSecondWindow() {
Stage stage = new Stage();
stage.setTitle("Window number 2");
stage.setScene(new Scene(new BorderPane(), 300, 275));
stage.setX(800);
makeStageDragAware(stage);
stage.show();
stageList.add(stage);
}
public void makeStageDragAware(Stage stage) {
stage.addEventHandler(MouseDragEvent.MOUSE_DRAG_RELEASED, event -> {
if (transferNode != null && transferNode.getScene().getWindow() != stage) {
((BorderPane) stage.getScene().getRoot()).setCenter(transferNode);
transferNode = null;
event.consume();
}
});
}
public Stage windowUnderPoint(Point point) {
for (Stage stage : stageList) {
if (inRange(stage.getX(), stage.getX() + stage.getWidth(), point.getX()) &&
inRange(stage.getY(), stage.getY() + stage.getHeight(), point.getY())) {
return stage;
}
}
return null;
}
public boolean inRange(double low, double high, double number) {
return (number >= low && number <= high);
}
public static void main(String[] args) {
launch(args);
}
}
基本上,当拖动节点被释放时,它会获取当前鼠标相对于显示器的坐标,并检查其下是否存在任何 known/registered 阶段。如果找到有效阶段,它将触发阶段 MOUSE_DRAG_RELEASED
事件。