Чтобы понять проблему, я сначала рекомендовал бы взглянуть на документацию свойств layoutX / layoutY узла.
публичный финал DoubleProperty layoutXProperty
Определяет координату х перевода, который добавляется к этому
Преобразование узла для макета. Значение должно быть
вычисляется как смещение, необходимое для регулировки положения узла
от текущей позиции layoutBounds minX (которая может быть не 0) до
нужное место.
Например, если текстовый узел должен быть расположен в finalX
textnode.setLayoutX(finalX - textnode.getLayoutBounds().getMinX());
Неспособность вычесть layoutBounds minX может привести к неправильному размещению
узел. Метод relocate (x, y) автоматически сделает правильный
вычисления и, как правило, должны использоваться над настройкой layoutX
непосредственно.
Окончательный перевод узла будет вычислен как layoutX + translateX,
где layoutX устанавливает стабильную позицию узла и translateX
при необходимости вносит динамические корректировки в эту позицию.
Если узел управляется и имеет Region в качестве родителя, тогда макет
Регион будет устанавливать layoutX в соответствии со своей собственной политикой размещения. Если
узел не управляется или парентируется группой, тогда приложение может установить
layoutX непосредственно, чтобы позиционировать его.
Короче говоря, для каждого узла, который визуализируется в сцене, его позиция фактически является суммой значений layoutX / Y и translateX / Y относительно его родительского узла. LayoutX / Y изначально обновляется в соответствии с его политикой размещения родителей. По этой причине нет смысла обновлять / полагаться на значения layoutX / Y узла, IF его родительский элемент (например, .StackPane, HBox, VBox и т. Д.) Управляет его положением.
Панель не будет управлять / определять свой дочерний макет. По этой причине значения layoutX / Y по умолчанию его дочерних элементов всегда равны 0.
Из приведенной выше информации, если мы сейчас посмотрим на ваш код, вы обновляете значения перевода и неправильно устанавливаете значения макета. Вместо этого вам нужно сделать следующее:
- Взять начальные значения layoutX / Y.
- Обновите translateX / Y при перетаскивании.
- А при отпускании мыши пересчитать значения layoutX / Y и сбросить
значения translateX / Y.
Ниже приведена краткая демонстрация того, что я описал.
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class PaneLayoutDemo extends Application {
double sceneX, sceneY, layoutX, layoutY;
@Override
public void start(Stage stage) throws Exception {
Pane root = new Pane();
Scene sc = new Scene(root, 600, 600);
stage.setScene(sc);
stage.show();
root.getChildren().addAll(getBox("green"), getBox("red"), getBox("yellow"));
}
private StackPane getBox(String color) {
StackPane box = new StackPane();
box.getChildren().add(new Label("Drag me !!"));
box.setStyle("-fx-background-color:" + color + ";-fx-border-width:2px;-fx-border-color:black;");
box.setPrefSize(150, 150);
box.setMaxSize(150, 150);
box.setMinSize(150, 150);
box.setOnMousePressed(e -> {
sceneX = e.getSceneX();
sceneY = e.getSceneY();
layoutX = box.getLayoutX();
layoutY = box.getLayoutY();
System.out.println(color.toUpperCase() + " Box onStart :: layoutX ::" + layoutX + ", layoutY::" + layoutY);
});
box.setOnMouseDragged(e -> {
double offsetX = e.getSceneX() - sceneX;
double offsetY = e.getSceneY() - sceneY;
box.setTranslateX(offsetX);
box.setTranslateY(offsetY);
});
box.setOnMouseReleased(e -> {
// Updating the new layout positions
box.setLayoutX(layoutX + box.getTranslateX());
box.setLayoutY(layoutY + box.getTranslateY());
// Resetting the translate positions
box.setTranslateX(0);
box.setTranslateY(0);
});
return box;
}
public static void main(String[] args) {
Application.launch(args);
}
}
Как только вы ознакомитесь с демо, попробуйте изменить корень с Pane на StackPane и посмотрите разницу в поведении.