为什么有些节点有 ax 和 y 位置而其他节点没有

Hel*_*orm 0 java javafx

我正在尝试了解 JavaFX 的坐标系。

对于某些节点(形状?),例如LineRectangle我可以(或应该)在坐标系中指定 ax 和 y 值。

这究竟是什么?这是稍后附加到节点或其他东西的平移和拉伸吗?其他节点只有一个setLayoutX()方法,而例如Line具有setLayoutX()setStartX()

谢谢!

Sla*_*law 5

每个Node都有两个不同的边界属性(忽略Node#layoutBounds)与两个不同的坐标空间 - 本地和父坐标空间相关。

  1. Node#boundsInLocal

    Node节点未变换的局部坐标空间中 this 的矩形边界。对于扩展的节点,Shape局部边界还将包括可能落在由位置和大小属性定义的形状几何之外的非零笔划所需的空间。本地边界还将包括使用 设置的任何剪辑clip以及使用 设置的效果effect

    [...]

  2. Node#boundsInParent

    this 的矩形边界Node,包括它的变换。boundsInParent通过获取局部边界(由 定义boundsInLocal)并应用通过设置以下附加变量创建的变换来计算

    1. transforms 可观察列表
    2. scaleX, scaleY,scaleZ
    3. rotate
    4. layoutX, layoutY
    5. translateX, translateY,translateZ


    结果边界在概念上将在Node的父节点的坐标空间中,但是节点不需要有父节点来计算这些边界。

    [...]

这意味着诸如layoutXtranslateX仅影响bounds-in-parent 之类的属性。基本上,边界只是应用了各种变换的局部边界。但是当涉及到“特殊”Shape属性时,例如 的xy属性Rectangle,它们会直接影响bounds-in-local。我无法找到解释这一点的文档,但也许我只是错过了它,或者这种行为对于那些“知情人士”来说应该是显而易见的。不幸的是,我无法向您解释为什么这些Shape属性会直接影响局部边界,因为我缺乏这方面的基础知识。

也就是说,我可以通过以下示例直观地演示有关本地边界的差异:

应用程序.java

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class App extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {
        var root = FXMLLoader.<Parent>load(getClass().getResource("App.fxml"));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

}
Run Code Online (Sandbox Code Playgroud)

控制器.java

import javafx.fxml.FXML;
import javafx.geometry.Point2D;
import javafx.scene.Node;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Rectangle;

public class Controller {

    @FXML
    private void handleMousePressed(MouseEvent event) {
        event.consume();

        var source = (Node) event.getSource();
        source.setUserData(source.localToParent(event.getX(), event.getY()));
    }

    @FXML
    private void handleMouseDragged(MouseEvent event) {
        event.consume();

        var source = (Node) event.getSource();
        var lastPoint = (Point2D) source.getUserData();
        var nextPoint = source.localToParent(event.getX(), event.getY());

        source.setTranslateX(source.getTranslateX() + nextPoint.getX() - lastPoint.getX());
        source.setTranslateY(source.getTranslateY() + nextPoint.getY() - lastPoint.getY());

        source.setUserData(nextPoint);
    }

    @FXML
    private void handleMouseReleased(MouseEvent event) {
        event.consume();

        var source = (Node) event.getSource();
        if (source instanceof Rectangle) {
            var rectangle = (Rectangle) source;
            rectangle.setX(rectangle.getX() + rectangle.getTranslateX());
            rectangle.setTranslateX(0);
            rectangle.setY(rectangle.getY() + rectangle.getTranslateY());
            rectangle.setTranslateY(0);
        }
        source.setUserData(null);
    }

}
Run Code Online (Sandbox Code Playgroud)

应用程序文件

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

import java.io.IOException;

public class App extends Application {

    @Override
    public void start(Stage primaryStage) throws IOException {
        var root = FXMLLoader.<Parent>load(getClass().getResource("App.fxml"));
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

}
Run Code Online (Sandbox Code Playgroud)

运行上述结果:

示例应用的 GIF

红色轮廓是节点的父节点边界,而绿色轮廓是节点的局部边界。拖动节点时,位置通过translate[X|Y]属性更新,无论是形状还是非形状,都不会影响bounds-in-local。但是对于形状,当释放鼠标时,平移变换将复制到“形状属性”(即Rectangle.xRectangle.y),然后将平移属性重置为0。这显示了对于形状,局部边界可能具有与 不同的原点(0,0)

aShape改变其局部边界这一事实对诸如变换之类的事情有影响。例如,如果您想使用 a 围绕其中心旋转节点Rotate,则形状与非形状的枢轴点将不同:

  • 形状(例如Rectangle):(x + width / 2, y + height / 2)1

  • 非形状(例如Region):(width / 2, height / 2)2

另一件受影响的事情是您从MouseEvent.


1. 注意形状,如Circle您可以简单地使用centerXcenterY。一个有趣的结果Circle是,局部边界将具有负的最小值。
2. 从技术上讲,这里唯一的区别是xy已知为0