在屏幕右侧滑动 in/out JavaFX 舞台 from/to

Slide in/out JavaFX stage from/to right side of the screen

我的任务是制作 JavaFX 应用程序。当我启动它时,window 应该从屏幕右侧平滑地滑动,当我点击 "x" 按钮时,它应该滑出到右侧然后完成。

我发现可以为此使用简单的时间轴动画。当我 运行 应用程序时,我让 window 滑入,但不知道如何滑出 window。

我尝试通过阶段的 setOnCloseRequest() 方法来处理这个定义处理程序,但遇到了两个问题:

  1. 无法实现动画
  2. 即使我使用 Window 事件
  3. 的 consume() 方法,单击 "x" 应用程序也会立即关闭

代码:

public class Main extends Application {

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

    @Override
    public void start(Stage stage) {
        stage.setTitle("Main");
        Group root = new Group();
        Scene scene = new Scene(root, 300, 250);
        stage.setScene(scene);


        Rectangle2D primScreenBounds = Screen.getPrimary().getVisualBounds();
        stage.setX(primScreenBounds.getMinX() + primScreenBounds.getWidth());
        System.out.println(primScreenBounds.getWidth());
        stage.setY(primScreenBounds.getMinY());
        stage.setWidth(0);
        stage.setHeight(primScreenBounds.getHeight());

        Timeline timeline = new Timeline();
        timeline.setAutoReverse(true);

        WritableValue<Double> writableWidth = new WritableValue<Double>() {
            @Override
            public Double getValue() {
                return stage.getWidth();
            }

            @Override
            public void setValue(Double value) {
                stage.setWidth(value);
            }
        };

        KeyValue kv = new KeyValue(writableWidth, 600d);
        KeyFrame kf = new KeyFrame(Duration.millis(3000), kv);
        timeline.getKeyFrames().addAll(kf);
        timeline.play();
        stage.show();
        stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent event) {
                event.consume();

            }
        });

    }
}

这对我有用(有点,不是很流畅):

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.value.WritableValue;
import javafx.event.EventHandler;
import javafx.geometry.Rectangle2D;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import javafx.util.Duration;

public class SlidingWindow extends Application {

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

    @Override
    public void start(Stage stage) {

        stage.setTitle("Main");
        Group root = new Group();
        Scene scene = new Scene(root);
        stage.setScene(scene);


        Rectangle2D primScreenBounds = Screen.getPrimary().getVisualBounds();
        double screenRightEdge = primScreenBounds.getMaxX() ;
        stage.setX(screenRightEdge);
        System.out.println(primScreenBounds.getWidth());
        stage.setY(primScreenBounds.getMinY());
        stage.setWidth(0);
        stage.setHeight(primScreenBounds.getHeight());

        Timeline timeline = new Timeline();


        WritableValue<Double> writableWidth = new WritableValue<Double>() {
            @Override
            public Double getValue() {
                return stage.getWidth();
            }

            @Override
            public void setValue(Double value) {
                stage.setX(screenRightEdge - value);
                stage.setWidth(value);
            }
        };


        KeyValue kv = new KeyValue(writableWidth, 600d);
        KeyFrame kf = new KeyFrame(Duration.millis(3000), kv);
        timeline.getKeyFrames().addAll(kf);
        timeline.play();
        stage.show();
        stage.setOnCloseRequest(new EventHandler<WindowEvent>() {
            @Override
            public void handle(WindowEvent event) {
                Timeline timeline = new Timeline();
                KeyFrame endFrame = new KeyFrame(Duration.millis(3000), new KeyValue(writableWidth, 0.0));
                timeline.getKeyFrames().add(endFrame);
                timeline.setOnFinished(e -> Platform.runLater(() -> stage.hide()));
                timeline.play();
                event.consume();
            }
        });

    }
}

当 window 被隐藏时,Platform.runLater(...) 似乎是防止大量 NullPointerException 的必要条件,可能是因为动画导致某些系统尝试访问一个没有的阶段不再存在。