2025/12/29

JavaFX 06 tranformation, transition

javafx 可套用 transformation 在單一或一組 nodes,也可以針對某一個 node,同時套用多個 transformations。

transformation

transformation 有以下這幾種

  • Rotation:旋轉
  • Scaling:縮放
  • Translation:平移
  • Shearing(斜切):用仿射變換實現
package javafx.transformation;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.transform.*;
import javafx.stage.Stage;

//Rotation:旋轉
//Scaling:縮放
//Translation:平移
//Shearing(斜切):用仿射變換實現
public class TransformDemo extends Application {

    @Override
    public void start(Stage primaryStage) {
        // === 建立形狀 ===
        Rectangle rect = new Rectangle(100, 60, Color.CORNFLOWERBLUE);
        rect.setArcWidth(15);
        rect.setArcHeight(15);

        // === 各種變換按鈕 ===
        Button btnTranslate = new Button("Translate (+100, +50)");
        btnTranslate.setOnAction(e -> {
            rect.getTransforms().add(new Translate(100, 50));
        });

        Button btnRotate = new Button("Rotate 45°");
        btnRotate.setOnAction(e -> {
            rect.getTransforms().add(new Rotate(45, rect.getX() + rect.getWidth() / 2, rect.getY() + rect.getHeight() / 2));
        });

        Button btnScale = new Button("Scale x1.5");
        btnScale.setOnAction(e -> {
            rect.getTransforms().add(new Scale(1.5, 1.5, rect.getX() + rect.getWidth() / 2, rect.getY() + rect.getHeight() / 2));
        });

        Button btnShear = new Button("Shear x=0.5, y=0");
        btnShear.setOnAction(e -> {
            rect.getTransforms().add(new Shear(0.5, 0));
        });

        // === Reset 按鈕 ===
        Button btnReset = new Button("Reset Transforms");
        btnReset.setStyle("-fx-background-color: tomato; -fx-text-fill: white;");
        btnReset.setOnAction(e -> {
            rect.getTransforms().clear(); // 移除所有變換
        });

        // === 佈局 ===
        VBox root = new VBox(15,
                rect,
                btnTranslate,
                btnRotate,
                btnScale,
                btnShear,
                btnReset
        );
        root.setPadding(new Insets(20));

        Scene scene = new Scene(root, 500, 400);
        primaryStage.setTitle("JavaFX Transformations with Reset");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

transition

transform 是一種即時的直接的轉換,會直接改變 node 的屬性,立刻生效。用作 node 的幾何變換。

transition 是一種動畫,需要一段時間,才會轉換到結果的動畫,可以 delay, repeat,有移動、縮放、旋轉、淡入淡出、路徑移動、視覺強化這些動態轉換的效果。

package javafx.transition;

import javafx.animation.*;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.*;
import javafx.stage.Stage;
import javafx.util.Duration;

public class AllTransitionsDemo extends Application {

    private Rectangle rect;

    // 紀錄狀態
    private double currentTranslateX = 0;
    private double currentTranslateY = 0;
    private double currentRotate = 0;
    private double currentScaleX = 1;
    private double currentScaleY = 1;

    @Override
    public void start(Stage primaryStage) {
        rect = new Rectangle(100, 60, Color.CORNFLOWERBLUE);
        rect.setArcWidth(15);
        rect.setArcHeight(15);
        rect.setStroke(Color.DARKBLUE);
        rect.setStrokeWidth(3);

        // RotateTransition
        Button btnRotate = new Button("Rotate +45°");
        btnRotate.setOnAction(e -> {
            currentRotate += 45;
            RotateTransition rt = new RotateTransition(Duration.seconds(1), rect);
            rt.setToAngle(currentRotate);
            rt.play();
        });

        // ScaleTransition
        Button btnScale = new Button("Scale x1.5");
        btnScale.setOnAction(e -> {
            currentScaleX *= 1.5;
            currentScaleY *= 1.5;
            ScaleTransition st = new ScaleTransition(Duration.seconds(1), rect);
            st.setToX(currentScaleX);
            st.setToY(currentScaleY);
            st.play();
        });

        // TranslateTransition
        Button btnTranslate = new Button("Translate (+100, +50)");
        btnTranslate.setOnAction(e -> {
            currentTranslateX += 100;
            currentTranslateY += 50;
            TranslateTransition tt = new TranslateTransition(Duration.seconds(1), rect);
            tt.setToX(currentTranslateX);
            tt.setToY(currentTranslateY);
            tt.play();
        });

        // FadeTransition
        Button btnFade = new Button("Fade Out / In");
        btnFade.setOnAction(e -> {
            FadeTransition ft = new FadeTransition(Duration.seconds(1), rect);
            ft.setFromValue(1.0);
            ft.setToValue(0.2);
            ft.setAutoReverse(true);
            ft.setCycleCount(2);
            ft.play();
        });

        // FillTransition (填充色)
        Button btnFill = new Button("Fill Color Change");
        btnFill.setOnAction(e -> {
            FillTransition fillTransition = new FillTransition(Duration.seconds(2), rect);
            fillTransition.setFromValue((Color) rect.getFill());
            fillTransition.setToValue(Color.ORANGERED);
            fillTransition.setAutoReverse(true);
            fillTransition.setCycleCount(2);
            fillTransition.play();
        });

        // StrokeTransition (邊框色)
        Button btnStroke = new Button("Stroke Color Change");
        btnStroke.setOnAction(e -> {
            StrokeTransition strokeTransition = new StrokeTransition(Duration.seconds(2), rect);
            strokeTransition.setFromValue((Color) rect.getStroke());
            strokeTransition.setToValue(Color.GREEN);
            strokeTransition.setAutoReverse(true);
            strokeTransition.setCycleCount(2);
            strokeTransition.play();
        });

        // SequentialTransition
        Button btnSequential = new Button("Sequential Animation");
        btnSequential.setOnAction(e -> {
            RotateTransition rotate = new RotateTransition(Duration.seconds(1), rect);
            rotate.setByAngle(90);

            TranslateTransition translate = new TranslateTransition(Duration.seconds(1), rect);
            translate.setByX(100);
            translate.setByY(50);

            ScaleTransition scale = new ScaleTransition(Duration.seconds(1), rect);
            scale.setToX(1);
            scale.setToY(1);

            SequentialTransition seq = new SequentialTransition(rect, rotate, translate, scale);
            seq.play();
        });

        // ParallelTransition
        Button btnParallel = new Button("Parallel Animation");
        btnParallel.setOnAction(e -> {
            RotateTransition rotate = new RotateTransition(Duration.seconds(2), rect);
            rotate.setByAngle(180);

            FadeTransition fade = new FadeTransition(Duration.seconds(2), rect);
            fade.setFromValue(1);
            fade.setToValue(0.3);

            ParallelTransition parallel = new ParallelTransition(rect, rotate, fade);
            parallel.play();
        });

        // PauseTransition
        Button btnPause = new Button("Pause 2 Seconds");
        btnPause.setOnAction(e -> {
            PauseTransition pause = new PauseTransition(Duration.seconds(2));
            pause.setOnFinished(ev -> System.out.println("Pause finished"));
            pause.play();
        });

        // PathTransition
        Button btnPath = new Button("Path Animation");
        btnPath.setOnAction(e -> {
            Path path = new Path();
            path.getElements().add(new MoveTo(0, 0));
            path.getElements().add(new CubicCurveTo(150, 100, 300, 0, 400, 100));

            PathTransition pathTransition = new PathTransition(Duration.seconds(3), path, rect);
            pathTransition.setCycleCount(1);
            pathTransition.play();
        });

        // Reset 按鈕
        Button btnReset = new Button("Reset All");
        btnReset.setStyle("-fx-background-color: tomato; -fx-text-fill: white;");
        btnReset.setOnAction(e -> {
            rect.getTransforms().clear();
            rect.setTranslateX(0);
            rect.setTranslateY(0);
            rect.setRotate(0);
            rect.setScaleX(1);
            rect.setScaleY(1);
            rect.setOpacity(1);
            rect.setFill(Color.CORNFLOWERBLUE);
            rect.setStroke(Color.DARKBLUE);

            currentTranslateX = 0;
            currentTranslateY = 0;
            currentRotate = 0;
            currentScaleX = 1;
            currentScaleY = 1;
        });

        VBox root = new VBox(10,
                rect,
                btnRotate,
                btnScale,
                btnTranslate,
                btnFade,
                btnFill,
                btnStroke,
                btnSequential,
                btnParallel,
                btnPause,
                btnPath,
                btnReset
        );
        root.setPadding(new Insets(15));

        Scene scene = new Scene(root, 600, 700);
        primaryStage.setTitle("JavaFX All Transitions Demo");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

沒有留言:

張貼留言