【问题标题】:How to drag a `Shape` that is below anther `shape` in JavaFX scene graph?如何在 JavaFX 场景图中拖动位于另一个“形状”下方的“形状”?
【发布时间】:2018-06-06 20:56:20
【问题描述】:

我正在使用 JavaFX 编写一个教育应用程序,用户可以在其中绘制和操作贝塞尔曲线 LineQuadCurveCubicCurve。这些曲线应该能够用鼠标拖动。我有两种选择:

1- 使用类LineQuadCurveCubicCurve,然后用透明颜色填充它们,并用另一种颜色(比如黑色)描边它们。此选项出现的问题是用户想要拖动一条曲线,但看到另一条曲线被拖动。原因是用户要拖动的曲线位于场景图中的另一条曲线下方。例如,在下图中,较小的曲线无法拖动,因为它在场景图中较大的曲线下方。

2- 使用 javafx.scene.shape.Path 类,在这种情况下,问题是操作这样的路径有点复杂,因为它由一些 PathElements 组成,并且简单地操作元素不会改变 @987654331 @,除非我们从元素属性中删除一个元素,然后添加一个新元素。因此我更喜欢方法1。

如何克服第一种方法中出现的问题?

提前感谢您的帮助。我的程序代码的简化版本如下。

import javafx.application.Application;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.input.MouseEvent;
import javafx.scene.paint.Color;
import javafx.scene.shape.CubicCurve;
import javafx.scene.shape.QuadCurve;
import javafx.stage.Stage;

public class SampleForStackOverflow extends Application
{
    double lastMouseX;
    double lastMouseY;
    double lastTranslateX;
    double lastTranslateY;

    @Override
    public void start(Stage window)
    {
        final double STROKE_WIDTH = 5;

        QuadCurve quad = new QuadCurve(100, 200, 150, 50, 200, 200);
        quad.setFill(Color.TRANSPARENT);
        quad.setStroke(Color.BLACK);
        quad.setStrokeWidth(STROKE_WIDTH);
        quad.setOnMousePressed(e -> {
            lastMouseX = e.getSceneX();
            lastMouseY = e.getSceneY();
            lastTranslateX = quad.getTranslateX();
            lastTranslateY = quad.getTranslateY();
        });
        quad.setOnMouseDragged(e -> followMouse(quad, e));

        CubicCurve cubic = new CubicCurve(0, 300, 100, 0, 300, 0, 300, 300);
        cubic.setFill(Color.TRANSPARENT);
        cubic.setStroke(Color.BLACK);
        cubic.setStrokeWidth(STROKE_WIDTH);
        cubic.setOnMousePressed(e -> {
            lastMouseX = e.getSceneX();
            lastMouseY = e.getSceneY();
            lastTranslateX = cubic.getTranslateX();
            lastTranslateY = cubic.getTranslateY();
        });
        cubic.setOnMouseDragged(e -> followMouse(cubic, e));

        Group root = new Group(quad, cubic);
        Scene scene = new Scene(root, 500, 500);
        window.setScene(scene);
        window.show();
    }


    private void followMouse(Node node, MouseEvent e)
    {
        double deltaX = e.getSceneX() - lastMouseX;
        double deltaY = e.getSceneY() - lastMouseY;
        node.setTranslateX(deltaX + lastTranslateX);
        node.setTranslateY(deltaY + lastTranslateY);
    }

    public static void main(String[] args) {
        launch(args);
    }
}

【问题讨论】:

    标签: java javafx path shape bezier


    【解决方案1】:

    您应该明确地将曲线的填充颜色设置为 null 并将 pickOnBounds 设置为 false,而不是在您的第一个场景中使用透明颜色。透明颜色仍会捕获鼠标事件,但 null 不会,并且当 pickOnBounds 为 false 时,仅当您恰好位于形状的彩色部分上方时才会捕获鼠标事件。

    【讨论】:

    • 非常感谢@mipa。事实是,结合您建议的方式和使用@JKostikiadis 建议的方法setPickOnBounds(false),解决了我的问题,完全符合我的需要。我真的没想到问题会以如此简单的方式消失。谢谢你和@JKostikiadis。我还要求您编辑您的答案,并使用方法setPickOnBounds(false) 提及其他任何参考您的答案的人。谢谢。
    【解决方案2】:

    使用路径创建 QuadCurve 和 CubicCurve 似乎对我来说很好用。这是一个完整的例子:

    import javafx.application.Application;
    import javafx.scene.Node;
    import javafx.scene.Scene;
    import javafx.scene.input.MouseEvent;
    import javafx.scene.layout.Pane;
    import javafx.scene.shape.CubicCurveTo;
    import javafx.scene.shape.MoveTo;
    import javafx.scene.shape.Path;
    import javafx.scene.shape.QuadCurveTo;
    import javafx.stage.Stage;
    
    public class SampleForStackOverflow extends Application {
    
        private final double STROKE_WIDTH = 5;
    
        private double lastMouseX;
        private double lastMouseY;
        private double lastTranslateX;
        private double lastTranslateY;
    
        @Override
        public void start(Stage window) {
    
            Path quad = initQuadCurve(100, 200, 200, 200, 150, 50);
            Path cubic = initCubicCurve(0, 300, 300, 300, 100, 0, 300, 0);
    
            Pane root = new Pane(cubic, quad);
    
            Scene scene = new Scene(root, 500, 500);
            window.setScene(scene);
            window.show();
        }
    
        private Path initQuadCurve(int xStart, int yStart, int xEnd, int yEnd, int controlX, int controlY) {
    
            Path curvePath = new Path();
            curvePath.setStrokeWidth(STROKE_WIDTH);
    
            MoveTo moveTo = new MoveTo(xStart, yStart);
    
            QuadCurveTo quadTo = new QuadCurveTo();
            quadTo.setControlX(controlX);
            quadTo.setControlY(controlY);
            quadTo.setX(xEnd);
            quadTo.setY(yEnd);
    
            curvePath.getElements().addAll(moveTo, quadTo);
    
            curvePath.setOnMousePressed(e -> {
                lastMouseX = e.getSceneX();
                lastMouseY = e.getSceneY();
                lastTranslateX = curvePath.getTranslateX();
                lastTranslateY = curvePath.getTranslateY();
            });
    
            curvePath.setOnMouseDragged(e -> followMouse(curvePath, e));
    
            return curvePath;
        }
    
        private Path initCubicCurve(int xStart, int yStart, int xEnd, int yEnd, int x1Control, int y1Control, int x2Control,
                int y2Control) {
    
            Path curvePath = new Path();
            curvePath.setStrokeWidth(STROKE_WIDTH);
            MoveTo moveTo = new MoveTo(xStart, yStart);
    
            CubicCurveTo cubicTo = new CubicCurveTo();
            cubicTo.setControlX1(x1Control);
            cubicTo.setControlY1(y1Control);
            cubicTo.setControlX2(x2Control);
            cubicTo.setControlY2(y2Control);
            cubicTo.setX(xEnd);
            cubicTo.setY(yEnd);
    
            curvePath.getElements().addAll(moveTo, cubicTo);
    
            curvePath.setOnMousePressed(e -> {
                lastMouseX = e.getSceneX();
                lastMouseY = e.getSceneY();
                lastTranslateX = curvePath.getTranslateX();
                lastTranslateY = curvePath.getTranslateY();
            });
    
            curvePath.setOnMouseDragged(e -> followMouse(curvePath, e));
    
            return curvePath;
        }
    
        private void followMouse(Node node, MouseEvent e) {
            double deltaX = e.getSceneX() - lastMouseX;
            double deltaY = e.getSceneY() - lastMouseY;
            node.setTranslateX(deltaX + lastTranslateX);
            node.setTranslateY(deltaY + lastTranslateY);
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }
    

    老实说,我的第一次尝试是致电 quad.setPickOnBounds(false);(以及立方体),如下面的两个帖子所示:

    Mouse Events get Ignored on the Underlying Layer

    JavaFX Pass MouseEvents through Transparent Node to Children

    但是它不起作用或者我错过了一些东西,但是如果你自己创建路径有效,发现它没有必要让事情变得更加复杂。无论如何,如果您想遵循第一种方法,我建议您查看链接。如果您要遵循第二种方法,在我看来,操纵路径不会很困难。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-10
      • 1970-01-01
      • 2017-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-01
      • 1970-01-01
      相关资源
      最近更新 更多