JavaFx 如何使用时间轴移动 window 位置

JavaFx how to move the window position with Timeline

我有这个舞台,当我展示它的时候。我希望它显示在屏幕底部,然后上升到中央屏幕。 就像一个通知。

我的代码

try {          
        Stage window = new Stage();
        window.initModality(Modality.APPLICATION_MODAL);
        window.setTitle(Message);
        AnchorPane layout = (AnchorPane) FXMLLoader.load(Notification.class.getResource("window.fxml"));
        Scene scene = new Scene(layout);
        window.setScene(scene);
        window.showAndWait();
} catch (Exception e) {
        System.out.println(e);
}

您需要在 window 移动的地方添加一个计时器。这是因为 Window/Stage 只有 X 和 Y 值的 ReadOnlyProperties,因此您不能使用关键帧制作简单的时间轴动画。

您需要稍微调整一下 primaryScreenBounds 的高度和宽度,这样它就能满足您的需要。

import javafx.animation.AnimationTimer;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.BorderPane;
import javafx.stage.Screen;
import javafx.stage.Stage;

public class TimelineEvents extends Application {

    private AnimationTimer timer;
    Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();
    double x = primaryScreenBounds.getMaxX() - 180;
    double y = primaryScreenBounds.getMaxY() - 180;
    double centerX = primaryScreenBounds.getWidth() / 2;
    double centerY = primaryScreenBounds.getHeight() / 2;
    double tickX = (x - centerX) / primaryScreenBounds.getWidth() * 10;
    double tickY = (y - centerY) / primaryScreenBounds.getHeight() * 10;

    @Override
    public void start(Stage stage) {
        Button btn = new Button();
        btn.setText("Show Message");
        btn.setOnAction((ActionEvent event) -> {
            Label l = new Label("Message");
            BorderPane root = new BorderPane(l);
            Scene s = new Scene(root, 100, 100);
            Stage window = new Stage();
            window.setX(x);
            window.setY(y);

            timer = new AnimationTimer() {

                @Override
                public void handle(long l) {
                    x = x - tickX;
                    y = y - tickY;
                    if (x >= centerX) {
                        window.setX(x);
                        window.setY(y);
                    } else {
                       stop();
                    }
                }
            };

            timer.start();
            window.setScene(s);
            window.showAndWait();
        });

        BorderPane pane = new BorderPane(btn);
        Scene scene = new Scene(pane, 200, 200);
        stage.setScene(scene);
        stage.show();

    }

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

专门为 Timeline 创建一个 属性,然后向其添加一个侦听器:

double startPos = ... ;
double endPos = ... ;
DoubleProperty y = new SimpleDoubleProperty(startPos);
Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new KeyValue(y, endPos)));
y.addListener((obs, oldValue, newValue) ->
    window.setY(newValue.doubleValue()));
timeline.play();

SSCCE:

import javafx.animation.KeyFrame;
import javafx.animation.KeyValue;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Popup;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.util.Duration;

public class SlidingNotificationWindow extends Application {

    @Override
    public void start(Stage primaryStage) {
        Button button = new Button("Show notification");
        button.setOnAction(e -> {
            Popup window = new Popup();
            StackPane content = new StackPane(new Label("Notification"));
            content.setStyle("-fx-background-color: aquamarine; -fx-padding: 40;");
            content.setOnMouseClicked(evt -> window.hide());
            window.getContent().add(content);
            window.setWidth(120);
            window.setHeight(75);

            Rectangle2D primaryScreenBounds = Screen.getPrimary().getVisualBounds();

            double startPos = primaryScreenBounds.getMaxY();
            double endPos = 2*primaryScreenBounds.getMinY()/3 + primaryScreenBounds.getMaxY() / 3 ;
            DoubleProperty y = new SimpleDoubleProperty(startPos);
            Timeline timeline = new Timeline(new KeyFrame(Duration.seconds(1), new KeyValue(y, endPos)));
            y.addListener((obs, oldValue, newValue) ->
                window.setY(newValue.doubleValue()));
            timeline.play();
            window.setX(primaryScreenBounds.getMaxX() - 120);
            window.show(primaryStage);
        });

        StackPane root = new StackPane(button);
        primaryStage.setScene(new Scene(root, 350, 120));
        primaryStage.show();
    }

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