以动画方式将组件添加到窗格

Hau*_*uke 4 java javafx

我想在我的应用程序中实现某种通知系统,但在计算通知的实际位置时遇到问题。所有通知都应出现在单独的阶段中,并且每个通知应相互对齐,并且每个通知都是一个带有两个标签(标题和消息)的简单 VBox。

我创建了一个小的独立应用程序来解决我遇到的问题。

一旦您按下主舞台上的按钮,就会创建一个 VBox 并将其添加到第二个通知舞台。一旦需要添加秒通知,第二个通知应位于第一个通知下方,依此类推。因此,我需要找到第一个通知的高度,以便将第二个通知放置在下面。

我知道我可以使用 VBox,但在我的应用程序中,通知应该制作平滑的动画,并将其他通知进一步向下推。我删除了整个动画并删除了部分通知,以便示例保持尽可能小。

问题是所有通知框都具有相同的高度 - 但它们并非如此(如果您修改文本并使其更长/更小)。

package whatever;

import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class NotificationTest {

    private Stage notificationStage;

    private Pane contentPane;

    private static final Integer NOTIFICATION_WIDTH = 250;

    private Double notificationOffset = 0.0;

    private static final Integer SPACING_BETWEEN_NOTIFICATIONS = 20;

    public void start() {
        Stage mainStage = new Stage();
        TextField textField = new TextField("Some long text for testing purpose with even more letters in oder to create at least one linebreak...");
        Button button = new Button("Add Notification");
        button.setOnAction(actionEvent -> {
            addNotification(textField.getText());
        });

        VBox vBox = new VBox(10);
        vBox.getChildren().addAll(textField, button);
        mainStage.setScene(new Scene(vBox, 300, 300));
        mainStage.show();
    }

    private void addNotification(String text) {
        if(notificationStage == null) {
            notificationStage = new Stage();
            notificationStage.setWidth(NOTIFICATION_WIDTH);
            notificationStage.setHeight(Screen.getPrimary().getVisualBounds().getHeight() - 50);
            notificationStage.setX(Screen.getPrimary().getVisualBounds().getWidth() - 260);
            notificationStage.setY(50);
            contentPane = new Pane();
            contentPane.setStyle("-fx-background-color: transparent");
            notificationStage.setScene(new Scene(contentPane));
            notificationStage.initStyle(StageStyle.TRANSPARENT);
            notificationStage.getScene().setFill(Color.TRANSPARENT);
            notificationStage.show();
        }

        VBox notificationBox = new VBox(10);
        notificationBox.setMaxWidth(NOTIFICATION_WIDTH);
        notificationBox.setMinWidth(NOTIFICATION_WIDTH);
        notificationBox.setStyle("-fx-background-radius: 10; -fx-background-color: red");
        notificationBox.getChildren().add(new Label("Title of Notification"));
        Label message = new Label(text);
        message.setWrapText(true);
        notificationBox.getChildren().add(message);
        notificationBox.setLayoutY(notificationOffset);

        contentPane.getChildren().add(notificationBox);

        // Needs to be done - otherwise the height would be 0
        contentPane.layout();
        System.out.println(notificationBox.getHeight());

        notificationOffset += notificationBox.getHeight() + SPACING_BETWEEN_NOTIFICATIONS;
    }

}
Run Code Online (Sandbox Code Playgroud)

我使用ScenicView工具验证高度,它说高度是79,但System.out告诉我高度是10.4。79 值似乎是正确的,但如何在我的应用程序中获取该值?

在此输入图像描述

c0d*_*der 6

简短的答案是使用applyCss()

    contentPane.applyCss();
    contentPane.layout();
Run Code Online (Sandbox Code Playgroud)

从文档中:

如果需要,请将样式应用于此节点及其子节点(如果有)。该方法通常不需要直接调用,但可以与 Parent.layout() 结合使用,以在下一个脉冲之前调整节点的大小

长且更好的答案是使用 aVBox或 a ListView

要添加布局动画,请使用LayoutAnimator.java您可以在这里找到更多详细信息。

编辑:LayoutAnimator使用动画新添加的通知的更多信息:

import javafx.application.Application;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.stage.*;

public class NotificationTest extends Application {

    private Stage notificationStage;
    private Pane contentPane;
    private static final int NOTIFICATION_WIDTH = 250, SPACING_BETWEEN_NOTIFICATIONS = 20;
    private static final String LONG_TEXT = "Some long text for testing purpose with even more letters in oder to create "
                                            + "at least one linebreak...";
    private int counter = 0;

    @Override
    public void start(Stage mainStage) throws Exception {
        mainStage = new Stage();
        TextField textField = new TextField(LONG_TEXT);
        Button button = new Button("Add Notification");
        button.setOnAction(actionEvent -> {
            addNotification(textField.getText());
        });

        VBox vBox = new VBox(10, textField, button);
        mainStage.setScene(new Scene(vBox, 300, 300));
        mainStage.show();
    }

    private void addNotification(String text) {
        if(notificationStage == null) {
            notificationStage = new Stage();
            notificationStage.setWidth(NOTIFICATION_WIDTH);
            notificationStage.setX(Screen.getPrimary().getVisualBounds().getWidth() - 260);
            notificationStage.setY(50);
            contentPane = new VBox(SPACING_BETWEEN_NOTIFICATIONS);
            contentPane.setStyle("-fx-background-color: transparent");
            notificationStage.setScene(new Scene(contentPane));
            notificationStage.initStyle(StageStyle.TRANSPARENT);
            //animate using LayoutAnimator  https://gist.github.com/jewelsea/5683558
            LayoutAnimator ly = new LayoutAnimator();
            ly.observe(contentPane.getChildren());
            notificationStage.show();
        }

        VBox notificationBox = new VBox(10);
        notificationBox.setMaxWidth(NOTIFICATION_WIDTH);
        notificationBox.setMinWidth(NOTIFICATION_WIDTH);
        notificationBox.setStyle("-fx-border-color: black");
        notificationBox.getChildren().add(new Label("Title of Notification"));
        Label message = new Label(counter++ + ": " +text);
        message.setWrapText(true);
        notificationBox.getChildren().add(message);

        contentPane.getChildren().add(0, notificationBox);
    }

    public static void main(String[] args) {
        launch(null);
    }
}
Run Code Online (Sandbox Code Playgroud)