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
?