Is it possible to use to use a path transition on a dialog box in javafx?

Luis Averhoff

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);
    }

}
José Pereda

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.

edited at
0

Comments

0 comments
Login to comment

Related

how to use shared element transition in a dialog fragment

Use variable in path, is this possible?

Using JavaFX: Is It Possible to Put A GridPane in an Alert Dialog Box?

JavaFX dialog Box

how to use JComboBox using Enum in Dialog Box

How to use two confirm dialog box?

How to use intent in a custom dialog box button?

JavaFx path transition in gridPane

Is it possible to use path module in browser?

Is it possible to use computer path in Node?

Is it possible to use property in the src path

Is it possible to use the Windows icon picker dialog?

Is it possible to use variables with the 'DIALOG' and 'CONVERSATION' commands?

Is it possible to use formulas in a text box in Excel?

Is it possible in JavaFX to not use the parent StyleSheet of a Node?

How should I use a window.confirm dialog box with a form?

Is there a way to use tabs.saveAsPDF() without dialog box in firefox quantum?

How to use View Binding in Custom Dialog box layout?

How to use ASP Controls inside a jQuery Dialog box ?

Is possible use prefix or const in a path of the route in symfony

Is it possible to use an image in place of the stroke of an SVG path?

Is it possible to use variable in path with lineinfile ansible module?

JavaFX: alert closing the dialog box automatically

improper use of Vue transition?

Libgdx use transition sprites

JavaFX Use Chart Legend to toggle show/hide Series possible?

Is it possible to use JavaFX's PerspectiveTransform with the new Canvas class?

JavaFX Dialog Box (confirmation box) which is user can't skip

Javafx: Close alert box (or, any dialog box) programatically