gpt4 book ai didi

java - 为什么有些节点有 x 和 y 位置而其他节点没有

转载 作者:行者123 更新时间:2023-12-01 17:43:56 26 4
gpt4 key购买 nike

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

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

这到底是什么?这是稍后附加到节点的平移和拉伸(stretch)还是其他内容?其他节点只有一个 setLayoutX() 方法,而例如Line 具有 setLayoutX()setStartX()

谢谢!

最佳答案

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

  1. Node#boundsInLocal

    The rectangular bounds of this Node in the node's untransformed local coordinate space. For nodes that extend Shape, the local bounds will also include space required for a non-zero stroke that may fall outside the shape's geometry that is defined by position and size attributes. The local bounds will also include any clipping set with clip as well as effects set with effect.

    [...]

  2. Node#boundsInParent

    The rectangular bounds of this Node which include its transforms. boundsInParent is calculated by taking the local bounds (defined by boundsInLocal) and applying the transform created by setting the following additional variables

    1. transforms ObservableList
    2. scaleX, scaleY, scaleZ
    3. rotate
    4. layoutX, layoutY
    5. translateX, translateY, translateZ


    The resulting bounds will be conceptually in the coordinate space of the Node's parent, however the node need not have a parent to calculate these bounds.

    [...]

这意味着诸如layoutX之类的属性和translateX只影响父级边界。基本上,父级边界只是应用了各种转换的本地边界。但说到“特别”Shape属性,例如 xy Rectangle的属性,它们直接影响本地边界。我无法找到解释这一点的文档,尽管也许我只是错过了它,或者这种行为对于那些“知情者”来说应该是显而易见的。不幸的是,我无法向您解释为什么这些 Shape属性直接影响本地边界,因为我缺乏这方面的基础知识。

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

App.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();
}

}

Controller.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);
}

}

App.fxml

<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Separator?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.Region?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.paint.Color?>
<?import javafx.scene.shape.Rectangle?>
<?import javafx.scene.text.Font?>

<HBox xmlns="http://javafx.com/javafx/12.0.2" xmlns:fx="http://javafx.com/fxml/1" fx:controller="Controller"
prefWidth="1000" prefHeight="600" spacing="15">

<fx:define>
<Font fx:id="titleFont" name="Impact" size="24"/>
<Color fx:id="inLocalColor" fx:value="LIME"/>
<Color fx:id="inParentColor" fx:value="RED"/>
</fx:define>

<padding>
<Insets topRightBottomLeft="25"/>
</padding>

<VBox HBox.hgrow="ALWAYS" spacing="10" alignment="CENTER">
<Label text="SHAPE" font="$titleFont"/>
<Separator/>
<Pane fx:id="shapePane" VBox.vgrow="ALWAYS">
<clip>
<Rectangle x="-5" y="-5" width="${shapePane.width}" height="${shapePane.height}"/>
</clip>
<Pane managed="false">
<Rectangle fx:id="shape" width="100" height="100" managed="false" onMousePressed="#handleMousePressed"
onMouseDragged="#handleMouseDragged" onMouseReleased="#handleMouseReleased"/>
<Rectangle fill="TRANSPARENT" stroke="$inLocalColor" strokeType="INSIDE" strokeWidth="2"
mouseTransparent="true" x="${shape.boundsInLocal.minX}" y="${shape.boundsInLocal.minY}"
width="${shape.boundsInLocal.width}" height="${shape.boundsInLocal.height}"/>
<Rectangle fill="TRANSPARENT" stroke="$inParentColor" strokeType="OUTSIDE" strokeWidth="2"
mouseTransparent="true" x="${shape.boundsInParent.minX}" y="${shape.boundsInParent.minY}"
width="${shape.boundsInParent.width}" height="${shape.boundsInParent.height}"/>
</Pane>
</Pane>
</VBox>

<Separator orientation="VERTICAL"/>

<VBox HBox.hgrow="ALWAYS" spacing="10" alignment="CENTER">
<Label text="NON-SHAPE" font="$titleFont"/>
<Separator/>
<Pane fx:id="nonShapePane" VBox.vgrow="ALWAYS">
<clip>
<Rectangle x="-5" y="-5" width="${nonShapePane.width}" height="${nonShapePane.height}"/>
</clip>
<Pane managed="false">
<Region fx:id="nonShape" prefWidth="100" prefHeight="100" style="-fx-background-color: black;"
onMousePressed="#handleMousePressed" onMouseDragged="#handleMouseDragged"
onMouseReleased="#handleMouseReleased"/>
<Rectangle fill="TRANSPARENT" stroke="$inLocalColor" strokeType="INSIDE" strokeWidth="2"
mouseTransparent="true" x="${nonShape.boundsInLocal.minX}" y="${nonShape.boundsInLocal.minY}"
width="${nonShape.boundsInLocal.width}" height="${nonShape.boundsInLocal.height}"/>
<Rectangle fill="TRANSPARENT" stroke="$inParentColor" strokeType="OUTSIDE" strokeWidth="2"
mouseTransparent="true" x="${nonShape.boundsInParent.minX}"
y="${nonShape.boundsInParent.minY}" width="${nonShape.boundsInParent.width}"
height="${nonShape.boundsInParent.height}"/>
</Pane>
</Pane>
</VBox>
</HBox>

运行上述结果:

GIF of example application

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

事实是Shape改变其本地边界会对诸如转换之类的事情产生影响。例如,如果您想使用 Rotate 绕其中心旋转节点。 ,那么形状的枢轴点与非形状的枢轴点将不同:

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

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

受影响的另一件事是您从 MouseEvent 获得的本地鼠标坐标。 .

<小时/>

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

关于java - 为什么有些节点有 x 和 y 位置而其他节点没有,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57751706/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com