So I'm running a little test application to see if this possible and then move it to my main project. The main idea is that the dialog box come from the top of the screen to the center and waits for a response from the the user. If they click no, the program terminates. If they click yes, the dialog box goes from the center to the top screen and is out of sight from the user.
package test;
import java.util.Optional;
import javafx.animation.PathTransition;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.control.ButtonType;
import javafx.scene.layout.VBox;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.shape.VLineTo;
import javafx.stage.Stage;
import javafx.util.Duration;
public class Test extends Application
{
@Override
public void start(Stage stage) throws Exception
{
VBox root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Confirmation Dialog");
alert.setHeaderText("Look, a Confirmation Dialog");
alert.setContentText("Are you ok with this?");
Path path = new Path();
path.getElements().add(new MoveTo(300, -25));
path.getElements().add(new VLineTo(200));
PathTransition pathTransition = new PathTransition();
pathTransition.setDuration(Duration.millis(1500));
pathTransition.setPath(path);
pathTransition.setNode(alert); // This is where the problem lies.
pathTransition.setCycleCount(1);
pathTransition.play();
Scene scene = new Scene(root, 640, 480);
stage.setScene(scene);
stage.show();
Optional<ButtonType> result = alert.showAndWait();
if (result.get() == ButtonType.OK)
{
Path path2 = new Path();
path2.getElements().add(new MoveTo(300, 200));
path2.getElements().add(new VLineTo(-25));
PathTransition pathTransition2 = new PathTransition();
pathTransition.setDuration(Duration.millis(1500));
pathTransition.setPath(path);
pathTransition.setNode(alert);
pathTransition.setCycleCount(1);
pathTransition.play();
}
else
{
stage.close();
}
}
public static void main(String[] args)
{
launch(args);
}
}
There's a way that you can move the alert dialog, by means of its yProperty()
. Instead of a path transition we'll use a timeline to set this property. But since this is a read only property, we havet to use a DoubleProperty
within the transition instead and use Alert.setY()
.
The first part of your question, sliding in the dialog, is easy. The second, sliding out, is more complex, since the dialog is closed inmediately once a button is clicked.
Solution 1. Just sliding in
We need the dialog dimensions and position, and for that we need to show it. This means it will be shown, and inmediately moved to the top of the screen.
So I'll change alert.showAndWait()
for alert.show()
.
@Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Show Sliding In Alert Dialog");
btn.setOnAction(event -> {
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Confirmation Dialog");
alert.setHeaderText("Look, a Confirmation Dialog");
alert.setContentText("Are you ok with this?");
ButtonBar buttonBar=(ButtonBar)alert.getDialogPane().lookup(".button-bar");
buttonBar.setDisable(true);
alert.initModality(Modality.APPLICATION_MODAL);
alert.show();
// now we can retrive alert bounds:
double yIni=-alert.getHeight();
double yEnd=alert.getY();
// and move alert to the top of the screen
alert.setY(yIni);
final DoubleProperty yProperty = new SimpleDoubleProperty();
yProperty.addListener((ob,n,n1)->alert.setY(n1.doubleValue()));
Timeline timeIn = new Timeline();
timeIn.getKeyFrames().add(
new KeyFrame(Duration.seconds(1.5),
e->buttonBar.setDisable(false),
new KeyValue(yProperty, yEnd,Interpolator.EASE_BOTH)));
timeIn.play();
alert.resultProperty().addListener((ob,r,r1)->{
if (r1 == ButtonType.OK){
// alert is closed and hidden in its final position
}
else{
primaryStage.close();
}
});
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
The listener in yProperty()
allow us to set the position to the dialog within all the different positions interpolated during the transition.
Solution 2. Slide In and Out
This is a bit of a dirty solution, since involves using a second Alert
dialog, given the original one is closed once the buttons are clicked. We'll add this second dialog behind the first one, and use it to create the slide out effect once the first one is closed.
The only side effect you will notice is a fast blink in the phase of showing the second and putting the first one on top of it.
@Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Show Sliding In Alert Dialog");
btn.setOnAction(event -> {
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Confirmation Dialog");
alert.setHeaderText("Look, a Confirmation Dialog");
alert.setContentText("Are you ok with this?");
Alert alertOut = new Alert(AlertType.CONFIRMATION);
alertOut.setTitle("Confirmation Dialog");
alertOut.setHeaderText("Look, a Confirmation Dialog");
alertOut.setContentText("Are you ok with this?");
alertOut.initModality(Modality.NONE);
((Stage)alertOut.getDialogPane().getScene().getWindow()).setOpacity(0);
ButtonBar buttonBar=(ButtonBar)alert.getDialogPane().lookup(".button-bar");
buttonBar.setDisable(true);
alert.initModality(Modality.APPLICATION_MODAL);
alert.show();
// now we can retrive alert bounds:
double yIni=-alert.getHeight();
double yEnd=alert.getY();
// and move alert to the top of the screen
alert.setY(yIni);
final DoubleProperty yProperty = new SimpleDoubleProperty();
yProperty.addListener((ob,n,n1)->alert.setY(n1.doubleValue()));
Timeline timeIn = new Timeline();
timeIn.getKeyFrames().add(
new KeyFrame(Duration.seconds(1.5),
e->{
buttonBar.setDisable(false);
// show second dialog
alertOut.show();
// move to front the first one
((Stage)alert.getDialogPane().getScene().
getWindow()).toFront();
}, new KeyValue(yProperty, yEnd,Interpolator.EASE_BOTH)));
timeIn.play();
alert.resultProperty().addListener((ob,r,r1)->{
if (r1 == ButtonType.OK){
// show second dialog
((Stage)alertOut.getDialogPane().getScene().getWindow()).setOpacity(1);
ButtonBar buttonBarOut=(ButtonBar)alertOut.getDialogPane().lookup(".button-bar");
buttonBarOut.setDisable(true);
final DoubleProperty yPropertyOut = new SimpleDoubleProperty(yEnd);
yPropertyOut.addListener((ov,n,n1)->alertOut.setY(n1.doubleValue()));
// Create slide out transition
Timeline timeOut = new Timeline();
timeOut.getKeyFrames().add(
new KeyFrame(Duration.seconds(1.5),
e->alertOut.close(),
new KeyValue(yPropertyOut, yIni,Interpolator.EASE_BOTH)));
timeOut.play();
}
else{
alertOut.close();
primaryStage.close();
}
});
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
EDIT
Solution 2. Improved Slide In and Out
I've found the way to use one single dialog, and provide the slide out effect too.
All it takes is trap the click action on the selected button, consume the event, add the slide out transition there, and hide the dialog on finished.
@Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("Show Sliding In Alert Dialog");
btn.setOnAction(event -> {
Alert alert = new Alert(AlertType.CONFIRMATION);
alert.setTitle("Confirmation Dialog");
alert.setHeaderText("Look, a Confirmation Dialog");
alert.setContentText("Are you ok with this?");
ButtonBar buttonBar=(ButtonBar)alert.getDialogPane().lookup(".button-bar");
buttonBar.setDisable(true);
alert.initModality(Modality.APPLICATION_MODAL);
alert.show();
// now we can retrive alert bounds:
double yIni=-alert.getHeight();
double yEnd=alert.getY();
// and move alert to the top of the screen
alert.setY(yIni);
buttonBar.getButtons().stream().filter(b->((Button)b).isDefaultButton()).findFirst()
.ifPresent(b->((Button)b).addEventFilter(EventType.ROOT,
e->{
if(e.getEventType().equals(ActionEvent.ACTION)){
e.consume();
final DoubleProperty yPropertyOut = new SimpleDoubleProperty(yEnd);
yPropertyOut.addListener((ov,n,n1)->alert.setY(n1.doubleValue()));
Timeline timeOut = new Timeline();
timeOut.getKeyFrames().add(new KeyFrame(Duration.seconds(1.5), t->alert.close(),
new KeyValue(yPropertyOut, yIni,Interpolator.EASE_BOTH)));
timeOut.play();
}
}));
final DoubleProperty yProperty = new SimpleDoubleProperty();
yProperty.addListener((ob,n,n1)->alert.setY(n1.doubleValue()));
Timeline timeIn = new Timeline();
timeIn.getKeyFrames().add(new KeyFrame(Duration.seconds(1.5), e->{
buttonBar.setDisable(false);
},new KeyValue(yProperty, yEnd,Interpolator.EASE_BOTH)));
timeIn.play();
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("Hello World!");
primaryStage.setScene(scene);
primaryStage.show();
}
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments