MouseDragRelease未在Node上调用

huangapple go评论69阅读模式
英文:

MouseDragRelease is not called on Node

问题

以下是代码部分的中文翻译:

public class Example extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Pane pane = new Pane();
        Scene scene = new Scene(pane, 1000, 1000);
        Circle circle = new Circle(400, 500, 50);
        Rectangle rect = new Rectangle(200, 200, 20, 30);
        Line line = new Line();
        line.setStroke(Color.RED);
        pane.getChildren().add(circle);
        pane.getChildren().add(rect);
        pane.getChildren().add(line);
        Node[] nodes = {circle, rect};
        scene.setOnMouseDragReleased(e -> {
            System.out.println("Scene: drag released");
        });
        for (Node node : nodes) {
            node.setOnDragDetected(e -> {
                System.out.println("drag started");
                line.setStartX(node.localToScene(node.getBoundsInLocal()).getCenterX());
                line.setStartY(node.localToScene(node.getBoundsInLocal()).getCenterY());
                line.setEndX(e.getX());
                line.setEndY(e.getX());
                node.startFullDrag();
            });
            node.setOnMouseDragged(e -> {
                line.setEndX(e.getX());
                line.setEndY(e.getY());
            });
            node.setOnMouseDragReleased(e -> {
                System.out.println("Node: drag released");
                line.setEndX((node.localToScene(node.getBoundsInLocal()).getCenterX()));
                line.setEndY((node.localToScene(node.getBoundsInLocal()).getCenterX()));
            });

            stage.setScene(scene);
            stage.show();
        }
    }
}

请注意,我已经去掉了HTML实体编码(如"),并将箭头(->)改为了正常的Java代码。此外,我保留了代码中的注释。

英文:
public class Example extends Application {
@Override
public void start(Stage stage) throws Exception {
Pane pane = new Pane();
Scene scene = new Scene(pane, 1000, 1000);
Circle circle = new Circle(400, 500, 50);
Rectangle rect = new Rectangle(200, 200, 20, 30);
Line line = new Line();
line.setStroke(Color.RED);
pane.getChildren().add(circle);
pane.getChildren().add(rect);
pane.getChildren().add(line);
Node[] nodes = {circle, rect};
scene.setOnMouseDragReleased(e -> {
System.out.println("Scene: drag released");
});
for (Node node:nodes) {
node.setOnDragDetected(e -> {
System.out.println("drag started");
line.setStartX(node.localToScene(node.getBoundsInLocal()).getCenterX());
line.setStartY(node.localToScene(node.getBoundsInLocal()).getCenterY());
line.setEndX(e.getX());
line.setEndY(e.getX());
node.startFullDrag();
});
node.setOnMouseDragged(e -> {
line.setEndX(e.getX());
line.setEndY(e.getY());
});
node.setOnMouseDragReleased(e -> {
System.out.println("Node: drag released");
line.setEndX((node.localToScene(node.getBoundsInLocal()).getCenterX()));
line.setEndY((node.localToScene(node.getBoundsInLocal()).getCenterX()));
});
stage.setScene(scene);
stage.show();
}
}
}

For some reason, drag release is called only for scene, but not for node. When line update in onMouseDragged for node is commented out, end of line doesn't follow the cursor, but onMouseDragRelease is called for both scene and node.
I want to have smooth line drawing, but also preserve onMouseDragRelease particulary for the node.

答案1

得分: 2

文档中:

当您拖动一个节点时,它仍然位于光标下方,因此在整个手势过程中都被视为潜在的手势目标。如果您需要将一个节点拖动到另一个节点并让其他节点了解此操作,您需要确保在被拖动的节点下方的节点被选为潜在的手势目标。您可以通过在被拖动的节点上调用setMouseTransparent(true)来实现这一点。

在您的情况下,该线条立即位于鼠标光标下方(因为您在拖动期间将线条的结束坐标设置为鼠标坐标),因此线条会接收鼠标拖动释放事件。

调用:

line.setMouseTransparent(true);

以便下方的节点可以接收事件。

如果需要在线条能够在拖动以外的时候接收鼠标事件,请在onDragDetected处理程序中调用:

line.setMouseTransparent(true);

并在onMouseDragReleased处理程序中调用:

line.setMouseTransparent(false);

请注意,onDragDetected仅在鼠标拖动了几个像素后才会被调用。从文档中可以看到:

请注意,此事件是基于拖动鼠标超过特定平台特定的距离阈值而生成的。

另一方面,onMouseDragged事件是在简单的鼠标按下-拖动-释放期间生成的,因此onMouseDragged会在鼠标拖动一个像素时立即被调用。因此,在拖动手势开始时,onMouseDragged处理程序会在onDragDetected处理程序之前被调用,导致线条的结束坐标与其起始坐标不同步。

解决此问题的一种方法是使用onMouseDragOver(它仅在完整的鼠标按下-拖动-释放手势中调用,由startFullDrag()调用来启动)代替onMouseDragged。由于您希望在任何地方检测拖动,将此处理程序添加到场景而不是单个节点。由于它仅在完整的鼠标按下-拖动-释放手势中调用,因此它只会在节点上拖动开始后才会被调用。我在下面的代码中实现了这个解决方案。

另一种选择是通过在onMouseDragged处理程序中调用setDragDetect(true)来强制检测鼠标拖动手势。

原始代码中还存在一些复制粘贴错误,我在下面的代码中进行了修复。

(感谢@SedJ601发现其中一些错误。)

public class Example extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Pane pane = new Pane();
        Scene scene = new Scene(pane, 1000, 1000);
        Circle circle = new Circle(400, 500, 50);
        Rectangle rect = new Rectangle(200, 200, 20, 30);
        Line line = new Line();
        line.setStroke(Color.RED);
        pane.getChildren().add(circle);
        pane.getChildren().add(rect);
        pane.getChildren().add(line);
        Node[] nodes = {circle, rect};
        scene.setOnMouseDragReleased(e -> {
            System.out.println("Scene: drag released");
        });
        for (Node node : nodes) {
            node.setOnDragDetected(e -> {
                System.out.println("drag started");
                line.setStartX(node.localToScene(node.getBoundsInLocal()).getCenterX());
                line.setStartY(node.localToScene(node.getBoundsInLocal()).getCenterY());
                line.setEndX(e.getX());

                // 修复了下面一行中的复制粘贴错误;
                line.setEndY(e.getY());

                line.setMouseTransparent(true);
                node.startFullDrag();
            }

            node.setOnMouseDragReleased(e -> {
                System.out.println("Node: drag released");
                line.setEndX((node.localToScene(node.getBoundsInLocal()).getCenterX()));
                // 请注意,您在下一行中存在复制粘贴错误,我已经修复了它:
                line.setEndY((node.localToScene(node.getBoundsInLocal()).getCenterY()));
                line.setMouseTransparent(false);
            });

        }

        // 用onMouseDragOver替代onMouseDragged:
        scene.setOnMouseDragOver(e -> {
            line.setEndX(e.getX());
            line.setEndY(e.getY());
        });

        stage.setScene(scene);
        stage.show();
    }
}
英文:

From the documentation:

> When you drag a node, it's still under cursor, so it is considered being a potential gesture target during the whole gesture. If you need to drag a node to a different node and let the other node know about it, you need to ensure that the nodes under the dragged node are picked as the potential gesture targets. You can achieve this by calling setMouseTransparent(true) on the dragged node

In your case, the line is immediately under the mouse cursor (because you set the end coordinates of the line to the mouse coordinates during dragging), so the line receives the mouse drag released event.

Call

line.setMouseTransparent(true);

so that the node underneath can receive the event.

If you need the line to be able to receive mouse events at times other than the dragging, call

line.setMouseTransparent(true);

in the onDragDetected handler, and

line.setMouseTransparent(false);

in the onMouseDragReleased handler.

Note also that onDragDetected is only called after the mouse has been dragged a few pixels. From the documentation

> Note that his event is generated based on dragging the mouse over a platform-specific distance threshold.

On the other hand, onMouseDragged events are generated during simple mouse press-drag-release, so onMouseDragged is invoked immediately the mouse is dragged a single pixel. Consequently, during the beginning of the drag gesture, the onMouseDragged handler is invoked before the onDragDetected handler, causing the line's end coordinates to be set while its start coordinates are out of sync.

One solution to this is to use onMouseDragOver (which is only invoked during full mouse press-drag-release gestures, which are initiated by the call to startFullDrag()) in place of onMouseDragged. Since you want to detect drag over anywhere, add this handler to the scene, not to the individual nodes. Since it is only invoked during the full mouse press-drag-release gestures, it will only be invoked after dragging has started on a node. I implement this solution in the code below.

Another option is to force detection of a mouse drag gesture by calling setDragDetect(true) in the onMouseDragged handler.

There are also a couple of copy-paste errors in the original code which I have fixed below.

(Credit to @SedJ601 for spotting a couple of these bugs.)

public class Example extends Application {
@Override
public void start(Stage stage) throws Exception {
Pane pane = new Pane();
Scene scene = new Scene(pane, 1000, 1000);
Circle circle = new Circle(400, 500, 50);
Rectangle rect = new Rectangle(200, 200, 20, 30);
Line line = new Line();
line.setStroke(Color.RED);
pane.getChildren().add(circle);
pane.getChildren().add(rect);
pane.getChildren().add(line);
Node[] nodes = {circle, rect};
scene.setOnMouseDragReleased(e -> {
System.out.println("Scene: drag released");
});
for (Node node:nodes) {
node.setOnDragDetected(e -> {
System.out.println("drag started");
line.setStartX(node.localToScene(node.getBoundsInLocal()).getCenterX());
line.setStartY(node.localToScene(node.getBoundsInLocal()).getCenterY());
line.setEndX(e.getX());
// Copy-paste bug fixed in line below;
line.setEndY(e.getY());
line.setMouseTransparent(true);
node.startFullDrag();
});
node.setOnMouseDragReleased(e -> {
System.out.println("Node: drag released");
line.setEndX((node.localToScene(node.getBoundsInLocal()).getCenterX()));
// Note you had a copy-and-paste error in the next line, which I have fixed:
line.setEndY((node.localToScene(node.getBoundsInLocal()).getCenterY()));
line.setMouseTransparent(false);
});
}
// onMouseDragged replaced by onMouseDragOver:
scene.setOnMouseDragOver(e -> {
line.setEndX(e.getX());
line.setEndY(e.getY());
});
stage.setScene(scene);
stage.show();
}
}

huangapple
  • 本文由 发表于 2023年3月7日 02:11:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75654376.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定