1Modalidad y formas de crear un diálogo

Un diálogo es una ventana secundaria que se utiliza para mostrar información, solicitar datos o confirmar acciones, con sus propios elementos interactivos. La modalidad controla la forma en que el diálogo mantiene el foco respecto a los demás diálogos o ventanas.

ModalityComportamiento
NONENo modal
WINDOW_MODALModal respecto a una ventana concreta
APPLICATION_MODALModal respecto a toda la aplicación

Dos métodos de visualización: show() (no bloquea la ejecución) y showAndWait() (bloquea hasta que el usuario cierra el diálogo).

Dos formas de crear un diálogo: usando las clases de alto nivel (Alert, TextInputDialog, ChoiceDialog, Dialog<T>) o creando un Stage secundario como ventana de diálogo.

ModalNo modal
Interacción con la ventana propietariaBloqueadaPermitida
Obliga a responder antes de continuarSíNo
Usos típicosConfirmación, errores, formularios pequeñosHerramientas, ayuda, visores

2Diálogos modales: Alert, TextInputDialog y Dialog<T>

java
Button btn = new Button("Mostrar diálogo modal");
btn.setOnAction(e -> {
    Alert alerta = new Alert(AlertType.CONFIRMATION);
    alerta.setTitle("Confirmación");
    alerta.setHeaderText("Eliminar archivo");
    alerta.setContentText("¿Estás seguro de que quieres eliminar el archivo?");
    alerta.initModality(Modality.APPLICATION_MODAL);
    alerta.initOwner(primaryStage);
    alerta.showAndWait().ifPresent(respuesta -> {
        if (respuesta == ButtonType.OK) {
            System.out.println("Usuario ha confirmado la eliminación.");
        } else {
            System.out.println("Usuario ha cancelado la operación.");
        }
    });
});

Variantes rápidas de Alert para los tres tipos de aviso más comunes:

java
// Información
Alert info = new Alert(AlertType.INFORMATION);
info.setTitle("Información");
info.setHeaderText("Operación completada");
info.setContentText("La tarea se ha realizado correctamente.");
info.showAndWait();

// Advertencia
Alert warning = new Alert(AlertType.WARNING);
warning.setTitle("Advertencia");
warning.setHeaderText("Campos incompletos");
warning.setContentText("Debes rellenar todos los campos antes de continuar.");
warning.showAndWait();

// Error
Alert error = new Alert(AlertType.ERROR);
error.setTitle("Error");
error.setHeaderText("Error al guardar");
error.setContentText("No se ha podido guardar el archivo.");
error.showAndWait();

TextInputDialog, para pedir un dato de texto simple:

java
TextInputDialog dialog = new TextInputDialog();
dialog.setTitle("Nombre de usuario");
dialog.setHeaderText("Introduce tu nombre");
dialog.setContentText("Nombre:");
Optional<String> resultado = dialog.showAndWait();
resultado.ifPresent(nombre -> {
    System.out.println("El usuario ha escrito: " + nombre);
});

Dialog<T> genérico, para formularios más complejos (aquí, un login con usuario y contraseña):

java
Dialog<Pair<String, String>> loginDialog = new Dialog<>();
loginDialog.setTitle("Login");
loginDialog.setHeaderText("Introduce tus credenciales");

ButtonType loginButtonType = new ButtonType("Entrar", ButtonBar.ButtonData.OK_DONE);
loginDialog.getDialogPane().getButtonTypes().addAll(loginButtonType, ButtonType.CANCEL);

GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
TextField txtUsuario = new TextField();
txtUsuario.setPromptText("Usuario");
PasswordField txtPassword = new PasswordField();
txtPassword.setPromptText("Contraseña");
grid.add(new Label("Usuario:"), 0, 0);
grid.add(txtUsuario, 1, 0);
grid.add(new Label("Contraseña:"), 0, 1);
grid.add(txtPassword, 1, 1);
loginDialog.getDialogPane().setContent(grid);

loginDialog.setResultConverter(dialogButton -> {
    if (dialogButton == loginButtonType) {
        return new Pair<>(txtUsuario.getText(), txtPassword.getText());
    }
    return null;
});

loginDialog.showAndWait().ifPresent(credenciales -> {
    String usuario = credenciales.getKey();
    String password = credenciales.getValue();
    System.out.println("Usuario: " + usuario + ", Password: " + password);
});

3Diálogos no modales con Stage secundario

java
Button btn = new Button("Abrir ventana de ayuda");
btn.setOnAction(e -> {
    Stage ventanaAyuda = new Stage();
    ventanaAyuda.setTitle("Ayuda");
    Label lbl = new Label(
        "Esta es una ventana de ayuda.\n" +
        "Puedes seguir usando la ventana principal."
    );
    VBox rootAyuda = new VBox(10, lbl);
    rootAyuda.setStyle("-fx-padding: 10;");
    ventanaAyuda.setScene(new Scene(rootAyuda, 250, 120));
    ventanaAyuda.initModality(Modality.NONE);
    ventanaAyuda.initOwner(primaryStage);
    ventanaAyuda.show();
});

Otro ejemplo, con un botón para cerrar el propio diálogo:

java
Button btnAbrir = new Button("Abrir diálogo");
btnAbrir.setOnAction(e -> {
    Stage dialogo = new Stage();
    dialogo.setTitle("Ventana de diálogo");
    Label lblMensaje = new Label("Este es un diálogo con otro Stage.");
    Button btnCerrar = new Button("Cerrar");
    btnCerrar.setOnAction(ev -> dialogo.close());
    VBox rootDialogo = new VBox(10, lblMensaje, btnCerrar);
    rootDialogo.setStyle("-fx-padding: 10; -fx-alignment: center;");
    Scene sceneDialogo = new Scene(rootDialogo, 250, 120);
    dialogo.setScene(sceneDialogo);
    dialogo.initModality(Modality.NONE);
    dialogo.initOwner(primaryStage);
    dialogo.show();
});

✓Ideas clave que debes dominar

  • Modal bloquea la ventana propietaria; no modal permite seguir trabajando.
  • show() = no bloqueante · showAndWait() = bloqueante.
  • Alert, TextInputDialog, Dialog<T> = clases de alto nivel · Stage secundario = control total.

Adaptado de Diálogos modales y no modales.