JavaFX - соединить перетаскиваемый узел линиями

Я строю редактор в JavaFx, в котором пользователь может добавлять модули. Каждый модуль имеет несколько входов, которые являются JavaFX-кружками и могут быть перемещены с помощью перетаскивания. Между кругами могут быть линии (от центра одного круга к центру другого круга).

Я также посмотрел на этот вопрос, но проблема в том, что мои круги не являются потомками узла, в котором нарисованы линии.

Итак, у меня есть следующий код (я использую ControlsFX для рисования границ):

public class EditorTest extends Application
{

    private Pane editorPane;

    @Override
    public void start(Stage primaryStage) throws Exception 
    {
        VBox root = new VBox();
        MenuBar menuBar = new MenuBar();
        menuBar.getMenus().add(new Menu("Test"));
        editorPane = new Pane();

        root.getChildren().add(menuBar);
        root.getChildren().add(editorPane);

        editorPane.setPrefSize(1000, 700);

        initBindings();

        Scene scene = new Scene(root);

        editorPane.requestFocus();

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

    private void initBindings()
    {
        editorPane.setOnMouseClicked((event) -> 
        {
            if (event.getButton() == MouseButton.SECONDARY)
            {
                Module moduleInput = new Module();
                Node inputGui = moduleInput.getGui();
                inputGui.setLayoutX(event.getX());
                inputGui.setLayoutY(event.getY());

                Module moduleOutput = new Module();
                Node outputGui = moduleOutput.getGui();
                outputGui.setLayoutX(event.getX() + 200);
                outputGui.setLayoutY(event.getY());

                Wire line = new Wire();
                line.setInput(moduleInput.getPort());
                line.setOutput(moduleOutput.getPort());

                editorPane.getChildren().add(inputGui);
                editorPane.getChildren().add(outputGui);
                editorPane.getChildren().add(line);
            }
        });
    }


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

}

Это класс для строк:

public class Wire extends Line
{

private Port input;
private Port output;

public Wire()
{
    super();
    setStroke(Color.GREEN);
    setStrokeWidth(3);
}

public void setInput(Port input)
{
    this.input = input;
    input.connectWire(this);
    update();
}

public void setOutput(Port output)
{
    this.output = output;
    output.connectWire(this);
    update();
}

public void update()
{
    if (input != null)
    {
        Point2D centerInput = input.localToScene(input.getCenterX(), input.getCenterY());
        System.out.println(centerInput);
        setStartX(centerInput.getX());
        setStartY(centerInput.getY());
    }

    if (output != null)
    {
        Point2D centerOutput = output.localToScene(output.getCenterX(), output.getCenterY());
        setEndX(centerOutput.getX());
        setEndY(centerOutput.getY());
    }
}

}

Это для входов:

public class Port extends Circle
{

    private Wire connLine;

    public Port()
    {
        super(10, Color.ALICEBLUE);
        setStroke(Color.BLACK);
    }

    public void connectWire(Wire connLine)
    {
        this.connLine = connLine;
    }

    public void update()
    {
        if (connLine != null)
            connLine.update();
    }
}

Это модули:

public class Module extends Pane
{
    private double oldX;
    private double oldY;

    private Port circle;

    public Module()
    {
        HBox root = new HBox(5);
        root.setAlignment(Pos.CENTER);
        circle = new Port();
        root.getChildren().add(circle);

        getChildren().add(root);
    }

    public Node getGui()
    {
        Node returnPane = Borders.wrap(this).lineBorder().title("Test").buildAll();

        returnPane.setOnMousePressed((event) ->
        {
            if (event.getButton() == MouseButton.PRIMARY)
            {
                oldX = returnPane.getLayoutX() - event.getSceneX();
                oldY = returnPane.getLayoutY() - event.getSceneY();
            }
        });

        returnPane.setOnMouseDragged((event) -> 
        {
            if (event.getButton() == MouseButton.PRIMARY)
            {
                double newX = event.getSceneX() + oldX;
                if (newX > 0 && newX < returnPane.getScene().getWidth()) 
                {
                    returnPane.setLayoutX(newX);
                }  
                double newY = event.getSceneY() + oldY;
                if (newY > 0 && newY < returnPane.getScene().getHeight()) 
                {
                    returnPane.setLayoutY(newY);
                }  
            }
        });

        returnPane.layoutXProperty().addListener((obs, newValue, oldValue) -> 
        {
            circle.update();
        });

        returnPane.layoutYProperty().addListener((obs, newValue, oldValue) -> 
        {
            circle.update();
        });

        return returnPane;
    }

    public Port getPort()
    {
        return circle;
    }
}

Так что я думаю, что проблема где-то в update метод Wireиз-за перевода из локальных в родительские координаты, но с локальным преобразованием в сцену это не работает из-за других узлов. Я тоже не понимаю, почему это не работает с localToParentпотому что в координатном пространстве модуля gui должно быть правильно...

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

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

Итак, как мне правильно перевести координаты, чтобы соединить линию с центрами портов, и это можно поместить в ScrollPane?

0 ответов

Другие вопросы по тегам