在按住按钮JavaFX的同时对多个节点进行鼠标拖动检测

2022-08-11 00:00:00 user-interface mouse mouseevent java javafx

我将直接回答这个问题。我如何为我的应用程序实现一个系统,让我在按住鼠标左键的同时为下面显示的这些矩形上色?当它被释放时,它就会停止着色。我通过互联网搜索了一下,但我仍然不明白这些鼠标事件是如何工作的。

祝你有愉快的一天!


解决方案

来自javafx.scene.input.MouseEvent的文档:

拖动手势

有三种类型的拖动手势。它们都是由鼠标按下事件启动的,并由于鼠标释放事件而终止,源节点决定将发生哪个手势。

默认设置为简单的按下-拖动-释放手势。它最适合用于更改形状的大小、拖动形状等等。整个按下-拖动-释放手势被传递到一个节点。按下鼠标按钮时,将拾取最顶端的节点,并将所有后续鼠标事件传递到同一节点,直到释放该按钮。如果鼠标单击事件是从这些事件生成的,它仍会传递到同一节点。

在简单的按下拖动释放手势期间,其他节点不会参与,也不会获得任何事件。如果这些节点需要参与手势,则必须激活完整的按下-拖动-释放手势。此手势最适合用于通过"Wire"连接节点、将节点拖动到其他节点等。MouseDragEvent中对此手势类型的描述更为详细,它包含传递到手势目标的事件。

第三种手势类型是平台支持的拖放手势。它最适合于传输数据,也适用于应用程序之间(不一定是FX)。此手势类型在DragEvent中有更详细的描述。

简而言之,当按下鼠标按键时,会自动激活简单的按下拖动释放手势,并将所有MouseEvent发送到手势源。当您开始拖动时,DRAG_DETECTED事件最终会到达。在其处理程序中,您可以通过在节点或场景上调用startFullDrag方法来启动完整的按拖放手势--MouseDragEvent开始传递到手势目标,或者您可以通过在节点或场景上调用startDragAndDrop方法来开始拖放手势-系统切换到拖放模式,DragEvent开始传递,而不是MouseEvent。如果您不调用这些方法中的任何一个,则简单的按拖放手势将继续。

[...]

如果我正确理解了您的问题,您希望能够将鼠标拖动到多个节点上并让它们做出反应,所有操作都在一个手势中完成。您将需要使用完整的 按下-拖动-释放手势即可完成此操作。如前所述,您必须侦听DRAG_DETECTED事件并调用Node#startFullDrag()Scene#startFullDrag()以激活完全按下-拖动-释放手势。然后,您的用户界面中的每个"正方形"都需要侦听MOUSE_DRAG_ENTERED事件。请注意,事件类型为MOUSE_DRAG_ENTERED和非MOUSE_ENTERED

举个例子:

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.layout.GridPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class App extends Application {

  @Override
  public void start(Stage primaryStage) {
    GridPane root = new GridPane();
    root.setPadding(new Insets(2));
    root.setVgap(2);
    root.setHgap(2);

    // start full press-drag-release gesture
    root.setOnDragDetected(
        event -> {
          if (event.getButton() == MouseButton.PRIMARY) {
            event.consume();
            root.startFullDrag();
          }
        });

    for (int i = 0; i < 12; i++) {
      for (int j = 0; j < 12; j++) {
        Rectangle rect = new Rectangle(50, 50, Color.WHITE);
        rect.setStroke(Color.BLACK);
        root.add(rect, i, j);

        // detect MOUSE_DRAG_ENTERED events
        rect.setOnMouseDragEntered(
            event -> {
              event.consume();
              rect.setFill(Color.BLACK);
            });
      }
    }

    primaryStage.setTitle("MouseDragEvent Example");
    primaryStage.setScene(new Scene(root));
    primaryStage.show();
  }
}
上述通过在根GridPane上设置Node#onDragDetected属性来侦听DRAG_DETECTED事件。请注意,如果您开始在其中一个Rectangle上拖动,则事件将向上冒泡到根,并由前面提到的处理程序处理。此外,由于您明确提到了左鼠标按键,因此我添加了鼠标按键是否为主按键的检查。

然后,每个Rectangle通过设置其Node#onMouseDragEntered属性来侦听MOUSE_DRAG_ENTERED事件。仅当完全按下-拖动-释放手势生效时,才会传递这些事件。

相关文章