首页 > 解决方案 > 翻译节点后布局 x 和 y 保持不变

问题描述

我目前在窗格上有一些堆栈窗格,当用鼠标拖动时,它们会在窗格中移动。当我按下堆栈窗格时,我通过获取鼠标的坐标和堆栈窗格的平移 x 和 y 来做到这一点。然后,当我开始拖动堆栈窗格时,我将堆栈窗格的平移 x 和 y 设置为按下堆栈窗格时的鼠标坐标 + 新鼠标坐标和旧鼠标坐标的差异。

我的问题是在拖动 StackPane 后,布局 x 和 y 保持不变,我想更新它,因为我在其他地方使用了它。

当您按下 StackPane 时我的事件处理程序:

EventHandler<MouseEvent> circleOnMousePressedEventHandler = 
            new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent t) {

                currentStackPane  = ((StackPane)(t.getSource()));
                orgSceneX = t.getSceneX();
                orgSceneY = t.getSceneY();
                layoutX =  currentStackPane.getLayoutX();
                layoutY =  currentStackPane.getLayoutY();

            }
        };

我拖动 StackPane 时的事件处理程序:

EventHandler<MouseEvent> circleOnMouseDraggedEventHandler = 
            new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent t) {


                double offsetX = t.getSceneX() - orgSceneX;
                double offsetY = t.getSceneY() - orgSceneY;
                currentStackPane.setTranslateX(offsetX);
                currentStackPane.setTranslateY(offsetY);
             }
        };

拖动完成后,我尝试制作一个事件处理程序:

EventHandler<MouseEvent> circleOnMouseReleasedEventHandler = 
            new EventHandler<MouseEvent>() {

            @Override
            public void handle(MouseEvent t) {

                currentStackPane.setLayoutX(layoutX + ((StackPane)(t.getSource())).getTranslateX());
                currentStackPane.setLayoutY(layoutY + ((StackPane)(t.getSource())).getTranslateY());
                currentStackPane.setTranslateX(0);
                currentStackPane.setTranslateY(0);
        }
};

但这似乎不起作用。任何帮助将不胜感激谢谢!

编辑:

我改变了我的事件处理程序。它似乎在我第一次拖动堆栈窗格时正确更新了布局 x 和 y,但是当我第一次拖动堆栈窗格然后释放鼠标时,堆栈窗格移动到不同的位置,然后每次我在它完全混乱后拖动. 不知道为什么,任何帮助表示赞赏!

EDIT2:我意识到我在鼠标释放事件中将 translate x 设置为 0,但没有将 translate y 设置为 0。现在一切正常!

标签: javafx

解决方案


要了解这个问题,我首先建议查看 Node.js 的 layoutX/layoutY 属性的文档。

public final DoubleProperty layoutXProperty

定义为布局目的添加到此节点变换的平移的 x 坐标。该值应计算为将节点位置从其当前 layoutBounds minX 位置(可能不是 0)调整到所需位置所需的偏移量。

例如,如果 textnode 应该定位在 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 最初根据其父布局策略进行更新。出于这个原因,如果它的父节点(例如,.StackPane、HBox、VBox、..etc)管理它的位置,那么更新/依赖节点的 layoutX/Y 值是没有意义的。

窗格不会管理/决定其子布局。因此,其子项的默认 layoutX/Y 值始终为 0。

从上面的信息来看,如果我们现在查看您的代码,您正在更新翻译值并错误地设置布局值。相反,您实际上必须做的是:

  1. 取 layoutX/Y 的初始值。
  2. 拖动时更新 translateX/Y。
  3. 并在鼠标释放时重新计算 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 并查看行为差异。


推荐阅读