是否可以在javafx中的对话框上使用路径转换?

时间:2015-04-25 15:40:10

标签: java animation javafx dialog

所以我正在运行一个小测试应用程序,看看是否可能,然后将其移动到我的主项目。主要思想是对话框从屏幕顶部到中心,等待用户的响应。如果他们单击否,程序将终止。如果他们单击是,则对话框将从中心移动到顶部屏幕,并且不在用户的视线范围内。

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

}

1 个答案:

答案 0 :(得分:1)

您可以通过yProperty()移动警报对话框。我们将使用时间轴来设置此属性,而不是路径转换。但由于这是一个只读属性,我们不得不在转换中使用DoubleProperty而是使用Alert.setY()

问题的第一部分,在对话框中滑动很容易。第二个,滑出,更复杂,因为一旦点击一个按钮,对话框就会立即关闭。

解决方案1.只需滑入

即可

我们需要对话框的尺寸和位置,为此我们需要展示它。这意味着它将被显示,并立即移动到屏幕顶部。

所以我将alert.showAndWait()改为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();
}

yProperty()中的监听器允许我们在转换过程中插入的所有不同位置内设置对话框的位置。

解决方案2.滑入和滑出

这是一个肮脏的解决方案,因为涉及使用第二个Alert对话框,因为一旦单击按钮,原始对话框就会关闭。我们将第二个对话框添加到第一个对话框后面,并在第一个对话框关闭后使用它来创建滑出效果。

您将注意到的唯一副作用是在显示第二个并将第一个放在其上的阶段快速闪烁。

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

修改

解决方案2.改进了幻灯片放入

我找到了使用单个对话框的方法,并提供了滑出效果。

所需要的只是捕获所选按钮上的单击操作,使用该事件,在那里添加滑出转换,并在完成后隐藏对话框。

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