Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX Opening one dialog from another

I have the following workflow in my application that is causing a problem:

Click Button to Open Dialog > Open Dialog > Click Button From Dialog > Display Confirmation Alert > Upon Confirmation close the first dialog and open a new dialog

The second dialog does not allow input into the TextField. I have included a SSCE that displays the problem. One additional weird thing is that if you try to close the second dialog by clicking the 'X', and then close the Alert then I am able to type into the field.

public class DialogTest extends Application {

  @Override
  public void start(Stage primaryStage) {
    Button button = new Button("Show Dialog");

    VBox root = new VBox(10, button);
    root.setAlignment(Pos.CENTER);

    Scene scene = new Scene(root, 350, 120);
    primaryStage.setScene(scene);
    primaryStage.show();

    button.setOnAction(event -> {
      Dialog<Pair<String, String>> dialog = getDialog(scene.getWindow(), "Dialog 1", true);
      dialog.showAndWait();
    });
  }

  public static void main(String[] args) {
    launch(args);
  }

  public Dialog<Pair<String, String>> getDialog(Window owner, String title, boolean addButton) {
    Dialog<Pair<String, String>> dialog = new Dialog<>();
    dialog.setTitle(title);
    dialog.initOwner(owner);
    dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);

    if(addButton) {
      Button button = new Button("Show Dialog");
      dialog.getDialogPane().setContent(button);
      button.setOnAction(event -> {
        Alert alert = new Alert(AlertType.CONFIRMATION, "Are you sure?", ButtonType.YES, ButtonType.NO);
        alert.initOwner(owner);
        if(alert.showAndWait().get() == ButtonType.YES) {
          dialog.close();
          Dialog<Pair<String, String>> dialog2 = getDialog(owner, "Dialog 2", false);
          TextField textField = new TextField();
          dialog2.getDialogPane().setContent(textField);
          dialog2.getDialogPane().getScene().getWindow().setOnCloseRequest(closeEvent -> {
            closeEvent.consume();
            if(textField.getText().trim().isEmpty()) {
              Alert alert2 = new Alert(AlertType.ERROR, "Please enter a value", ButtonType.OK);
              alert2.initOwner(dialog2.getDialogPane().getScene().getWindow());
              alert2.showAndWait();
            }
          });
          dialog2.showAndWait();
        }
      });
    }

    return dialog;
  }
}
like image 292
Tommo Avatar asked Sep 17 '15 16:09

Tommo


1 Answers

Problem

As explained, you have a modality problem.

Solution

The following code will demonstrate a solution where the user is asked if he really wants to print and after printing, if the ending number is correct.

(Note, that I use a class IntField from here)

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ButtonBar.ButtonData;
import javafx.scene.control.ButtonType;
import javafx.scene.control.Dialog;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.Window;

public class DialogTest extends Application {

    Region veil;
    ProgressIndicator indicator;

    IntField startingNumber = new IntField(0, 999999, 0);
    IntField endingNumber = new IntField(startingNumber.getValue(), 999999, startingNumber.getValue() + 1);
    ButtonType printButtonType = new ButtonType("Print", ButtonData.OK_DONE);
    Stage stage;

    @Override
    public void start(Stage primaryStage) {
        stage = primaryStage;
        Button button = new Button("Print Checks");

        VBox box = new VBox(10, button);
        box.setAlignment(Pos.CENTER);

        veil = new Region();
        veil.setStyle("-fx-background-color: rgba(0, 0, 0, 0.3);");
        veil.setVisible(false);

        indicator = new ProgressIndicator();
        indicator.setMaxHeight(60);
        indicator.setMinWidth(60);
        indicator.setVisible(false);

        StackPane root = new StackPane(box, veil, indicator);

        root.setAlignment(Pos.CENTER);

        Scene scene = new Scene(root, 400, 400);
        primaryStage.setScene(scene);
        primaryStage.show();

        button.setOnAction((event) -> {
            Dialog<ButtonType> dialog
                    = getCheckPrintDialog(primaryStage, "Enter starting check number");
            dialog.showAndWait()
                    .filter(result -> result == printButtonType)
                    .ifPresent(result -> {
                        // this is for this example only, normaly you already have this value
                        endingNumber.setValue(startingNumber.getValue() + 1);
                        printChecks(startingNumber.getValue(), endingNumber.getValue());
                    });
        });
    }

    public static void main(String[] args) {
        launch(args);
    }

    public <R extends ButtonType> Dialog getCheckPrintDialog(Window owner, String title) {
        Dialog<R> dialog = new Dialog<>();
        dialog.initOwner(owner);
        dialog.setTitle(title);
        dialog.getDialogPane().getButtonTypes().addAll(printButtonType, ButtonType.CANCEL);

        Button btOk = (Button) dialog.getDialogPane().lookupButton(printButtonType);
        btOk.addEventFilter(ActionEvent.ACTION, event -> {
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Print Checks? Are you sure?", ButtonType.YES, ButtonType.NO);
            alert.showAndWait()
                    .filter(result -> result == ButtonType.NO)
                    .ifPresent(result -> event.consume());
        });

        GridPane grid = new GridPane();
        grid.setHgap(10);
        grid.setVgap(10);

        Text from = new Text("Starting Number:");
        grid.add(from, 0, 0);

        grid.add(startingNumber, 1, 0);

        dialog.getDialogPane().setContent(grid);
        return dialog;
    }

    private void printChecks(int from, int to) {

        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                Thread.sleep(5000);
                return null;
            }
        };

        task.setOnSucceeded((event) -> {
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION, "Has the last check, the number: " + endingNumber.getValue() + "?", ButtonType.YES, ButtonType.NO);
            alert.initOwner(stage);
            Button btnNo = (Button) alert.getDialogPane().lookupButton(ButtonType.NO);
            btnNo.addEventFilter(ActionEvent.ACTION, e -> {
                Dialog<ButtonType> newEndNum = new Dialog<>();
                newEndNum.setTitle("Enter the ending check number");
                newEndNum.initOwner(stage);
                newEndNum.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
                GridPane grid = new GridPane();
                grid.setHgap(10);
                grid.setVgap(10);

                Text toUser = new Text("Ending Number:");
                grid.add(toUser, 0, 0);

                grid.add(endingNumber, 1, 0);

                newEndNum.getDialogPane().setContent(grid);
                newEndNum.showAndWait().filter(result -> result == ButtonType.CANCEL)
                        .ifPresent(result -> e.consume());
            });
            alert.showAndWait();
        });
        veil.visibleProperty().bind(task.runningProperty());
        indicator.visibleProperty().bind(task.runningProperty());
        new Thread(task).start();
    }

}

Working Application

  1. The main Window:

Main

  1. The Print Dialog:

PrintDialog

  1. After a click on Print (Alerts are localized, for me in german):

Confirm

  1. After a click on Yes the Print Dialog closes and a progress will be visible (for 5 sec. in this example)

Progress

  1. After the Printing finishes a Dialog comes up which is asking for the correct ending number

Confirm2

  1. If you click Yes all is done, if you click No another dialog opens to enter the correct ending value

EndingNumber

like image 88
aw-think Avatar answered Sep 20 '22 02:09

aw-think