Diálogos modales y no modales
Ventanas secundarias para mostrar información, pedir datos o confirmar acciones, y cómo controlar si bloquean o no el resto de la aplicación.
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.
| Modality | Comportamiento |
|---|---|
NONE | No modal |
WINDOW_MODAL | Modal respecto a una ventana concreta |
APPLICATION_MODAL | Modal 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.
| Modal | No modal | |
|---|---|---|
| Interacción con la ventana propietaria | Bloqueada | Permitida |
| Obliga a responder antes de continuar | Sí | No |
| Usos típicos | Confirmación, errores, formularios pequeños | Herramientas, ayuda, visores |
2Diálogos modales: Alert, TextInputDialog y Dialog<T>
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:
// 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:
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):
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
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:
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 ·Stagesecundario = control total.
Adaptado de Diálogos modales y no modales.