簡體   English   中英

如何在JavaFX場景圖中拖動一個“形狀”下面的“形狀”?

[英]How to drag a `Shape` that is below anther `shape` in JavaFX scene graph?

我正在使用JavaFX編寫一個教育應用程序,用戶可以在其中繪制和操作Bezier曲線LineQuadCurveCubicCurve 這些曲線應該能夠用鼠標拖動。 我有兩種選擇:

1-使用LineQuadCurveCubicCurve ,然后用透明顏色填充它們,並用另一種顏色描繪它們,比如黑色。 此選項出現的問題是用戶想要拖動曲線,但會看到拖動另一條曲線。 這樣做的原因是用戶要拖動的曲線位於場景圖中的另一個曲線下方。 例如,在下圖中,較小的曲線不能拖動,因為它低於場景圖中較大的曲線。

一條曲線低於另一條

2-使用類javafx.scene.shape.Path ,在這種情況下問題是操縱這樣的路徑有點復雜,因為它由一些PathElement組成,並且簡單地操作元素不會改變Path ,除非我們從其elements屬性中刪除一個元素,並添加一個新元素。 因此,我更喜歡方法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);
    }
}

您應該明確地將曲線的填充顏色設置為null並將pickOnBounds設置為false,而不是在第一個場景中使用透明顏色。 透明顏色仍將捕獲鼠標事件但null不會捕獲,而當pickOnBounds為false時,僅當您正好在形狀的彩色部分上時才會捕獲鼠標事件。

使用Paths創建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); (以及對於立方體而言)如以下兩個帖子所示:

在底層圖層上忽略鼠標事件

JavaFX通過透明節點將MouseEvents傳遞給子節點

但是它不起作用或者我錯過了一些東西,但是如果自己創造路徑,那么就不必再復雜化了。 在任何情況下,如果您想要遵循第一種方法,我建議您查看鏈接。 如果您要遵循第二種方法,操縱路徑在我看來並不會非常困難。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM