Как перетащить `Shape`, который находится ниже пыльника` shape` в графе сцены JavaFX? - PullRequest
0 голосов
/ 06 июня 2018

Я пишу учебное приложение с использованием JavaFX, в котором пользователь может рисовать и манипулировать кривыми Безье Line, QuadCurve и CubicCurve.Эти кривые должны иметь возможность перетаскивания мышью.У меня есть два варианта:

1 - использование классов Line, QuadCurve и CubicCurve, а затем заполнение их прозрачным цветом и обводка другим цветом, скажем черным.Проблема, которая возникает для этой опции, состоит в том, что пользователь хочет перетащить кривую, но видит, что перетаскивается другая кривая.Причина этого заключается в том, что кривая, которую пользователь собирается перетащить, находится ниже другой на графике сцены.Например, на следующем рисунке меньшая кривая не может перетаскиваться, поскольку она находится ниже большей кривой на графике сцены.

A curve below another

2- Использование класса javafx.scene.shape.Path, в этом случае проблема заключается в том, что манипулирование таким путем немного сложнее, поскольку он состоит из некоторых PathElement s, и простое управление элементами не меняет 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);
    }
}

Ответы [ 2 ]

0 голосов
/ 07 июня 2018

Вместо использования прозрачного цвета в вашем первом сценарии вы должны явно установить цвет заливки ваших кривых на ноль и установить для pickOnBounds значение false.Прозрачный цвет будет по-прежнему перехватывать события мыши, но при нулевом - не будет, а при значении pickOnBounds, если оно ложно, события мыши будут перехватываться, только если вы находитесь точно над цветными частями вашей фигуры.

0 голосов
/ 07 июня 2018

Создание QuadCurve и CubicCurve с использованием Paths, кажется, работает нормально для меня.Вот полный пример:

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 через прозрачный узел дочерним элементам

Но это не работает или я что-то пропустил, но при созданиипуть сам по себе работает не нужно усложнять вещь больше.В любом случае, я рекомендую взглянуть на ссылки, если вы хотите следовать первому подходу.Если вы собираетесь следовать второму подходу, манипулирование путями, по моему мнению, не будет очень трудным.

...