java - Javafx 中的选择性子变换

标签 java javafx transformation

我想知道是否可以有选择地将父级转换应用于 javafx 中的子节点。

据我了解,当一个节点被转换时,该节点的所有子节点也会被转换。

我的问题是:是否可以在子级中禁用父级转换类型,以便在转换父级时仅传递选定类型的转换。

与此类似: enter image description here

我想旋转组节点而不旋转文本,但我希望文本位置受到旋转的影响。

希望我已经解释清楚了。

<小时/>

目前,我只是在转换组时对文本应用相反的旋转,但扩展场景图会使事情变得更加复杂。

最佳答案

简而言之,不会:组的变换总是传播到其所有子项。

但是,我认为这里您只是希望文本的旋转属性是组的旋转属性的负数:

text.rotateProperty().bind(group.rotateProperty().multiply(-1));

由于rotateProperty定义了围绕节点中心的旋转,当组旋转时,它(及其所有子节点)将围绕其中心旋转,然后绑定(bind)确保文本绕其中心沿相反方向旋转。

如果你想要更通用的东西,那就有点棘手了。一种可能的方法是观察要保持水平的文本的父级的 localToSceneTransform。该属性表示将父级中的坐标映射到场景中的坐标的累积变换。然后,您可以在父级的局部坐标空间中取一条水平线,将其转换到场景中,并查看它创建的角度。然后,您希望将文本旋转该角度的负值。

这是一个演示:

import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.geometry.Point2D;
import javafx.scene.Group;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.Spinner;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;

public class RotateGroupKeepTextAligned extends Application {   

    @Override
    public void start(Stage primaryStage) {
        BorderPane root = new BorderPane();
        StackPane container = new StackPane();
        Group outer = new Group();
        Rectangle outerRect = new Rectangle(0, 0, 400, 400);
        outerRect.setFill(Color.ANTIQUEWHITE);
        outer.getChildren().add(outerRect);

        Text outerText = new Text(5,  5, "Outer Group");
        Group inner = new Group();
        inner.relocate(10, 25);
        Text innerText = new Text(5, 5, "Inner Group");
        Rectangle rect = new Rectangle(50, 50, 150, 150);
        rect.setFill(Color.CORNFLOWERBLUE);
        Text fixedAlignmentText = new Text(100, 220, "Horizontal Text");

        inner.localToSceneTransformProperty().addListener((obs, oldT, newT) -> {
            // figure overall rotation angle of inner:
            Point2D leftScene = newT.transform(new Point2D(0, 0));
            Point2D rightScene = newT.transform(new Point2D(1, 0));

            double angle = Math.toDegrees(Math.atan2(rightScene.getY() - leftScene.getY(), rightScene.getX() - leftScene.getX()));

            fixedAlignmentText.setRotate(-angle);
        });

        outer.setStyle("-fx-background-color: antiquewhite;");
        outer.getChildren().addAll(outerText, inner);

        inner.setStyle("-fx-background-color: white;");
        inner.getChildren().addAll(innerText, rect, fixedAlignmentText);

        container.getChildren().add(outer);
        root.setCenter(container);

        VBox controls = new VBox(5,
                makeControls("Outer Group", outer),
                makeControls("Inner Group", inner));

        root.setBottom(controls);

        Scene scene = new Scene(root, 600, 600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private Node makeControls(String title, Node node) {
        GridPane grid = new GridPane();

        Label label = new Label(title);
        Spinner<Double> rotateSpinner = new Spinner<>(0, 360, 0, 5);
        node.rotateProperty().bind(rotateSpinner.getValueFactory().valueProperty());
        rotateSpinner.getValueFactory().setWrapAround(true);

        Button up = createTranslateButton(node, Node::translateYProperty, -2, "^");
        Button down = createTranslateButton(node, Node::translateYProperty, 2, "v");
        Button left = createTranslateButton(node, Node::translateXProperty, -2, "<");
        Button right = createTranslateButton(node, Node::translateXProperty, 2, ">");

        grid.add(label, 0, 0, 3, 1);
        grid.add(new Label("Rotation:"), 0, 1, 1 ,2);
        grid.add(rotateSpinner, 1, 1, 1, 2);
        grid.add(up, 3, 1);
        grid.add(down, 3, 2);
        grid.add(left, 2, 1, 1, 2);
        grid.add(right, 4, 1, 1, 2);

        grid.setHgap(5);
        grid.setVgap(5);

        return grid ;
    }

    private Button createTranslateButton(Node node, Function<Node, DoubleProperty> property, double delta, String text) {
        Button button = new Button(text);
        button.setOnAction(e -> {
            DoubleProperty prop = property.apply(node);
            prop.set(prop.get() + delta);
        });
        return button ;
    }

    public static void main(String[] args) {
        launch(args);
    }
}

关于java - Javafx 中的选择性子变换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34899143/

相关文章:

java - 使用 for 循环生成 30 个 lambda 表达式

ios - 如何根据相机的位置变换图像

matrix - VR中变换矩阵的问题

java - 使用 Java Collat​​or 区分大小写的顺序

java - 使用 Cloud Firestore (Android) 上的数组字段监听某些查询的更新

从命令行运行应用程序时 JavaFX 8 视频播放卡住

ios - 像标准功能 ios objective c 中那样旋转图像

java - 仅当按下按键时动画出现,不按下任何按键时图像消失

java - 从堆栈中删除一个元素

java - 打开窗口/阶段JavaFX时调用代码