动画添加组件到窗格
Animate adding components to a pane
我想在我的应用程序中实现某种通知系统,但我在计算通知的实际位置时遇到了问题。所有通知都应该出现在一个单独的阶段,每个通知应该相互对齐,每个通知都是一个带有两个标签(标题和消息)的简单 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;
}
}
我用 ScenicView 工具验证高度,它说高度是 79,但 System.out 告诉我高度是 10.4。 79 值似乎是正确的,但我如何在我的应用程序中获取此值?
简短的回答是使用 applyCss()
:
contentPane.applyCss();
contentPane.layout();
来自文档:
If required, apply styles to this Node and its children, if any. This
method does not normally need to be invoked directly but may be used
in conjunction with Parent.layout() to size a Node before the next
pulse
长而更好的答案是使用 VBox
或 ListView
。
要添加布局动画,请使用 LayoutAnimator.java. You can find more details here。
编辑: 使用 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);
}
}
我想在我的应用程序中实现某种通知系统,但我在计算通知的实际位置时遇到了问题。所有通知都应该出现在一个单独的阶段,每个通知应该相互对齐,每个通知都是一个带有两个标签(标题和消息)的简单 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;
}
}
我用 ScenicView 工具验证高度,它说高度是 79,但 System.out 告诉我高度是 10.4。 79 值似乎是正确的,但我如何在我的应用程序中获取此值?
简短的回答是使用 applyCss()
:
contentPane.applyCss();
contentPane.layout();
来自文档:
If required, apply styles to this Node and its children, if any. This method does not normally need to be invoked directly but may be used in conjunction with Parent.layout() to size a Node before the next pulse
长而更好的答案是使用 VBox
或 ListView
。
要添加布局动画,请使用 LayoutAnimator.java. You can find more details here。
编辑: 使用 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);
}
}