Working with Dialogs
Dialogs are popup windows that appear over your main application window to display information, ask for confirmation, or collect user input. In JavaFX, the Alert class provides pre-built dialog types for common use cases. In the Jukebox project, dialogs are used in the Admin Panel for delete confirmation and error messages. This cookbook section explains how to work with dialogs.
- Different types of Alert dialogs
- Creating and showing confirmation dialogs
- Creating and showing information dialogs
- Getting user response from dialogs
- Dialog structure and customization
- When and how to use dialogs effectively
Dialog Overview
JavaFX provides the javafx.scene.control.Alert class which is a specialized dialog for displaying alerts, confirmations, warnings, and errors. Alerts are modal by default, meaning they block interaction with the rest of the application until the user responds.
| Type | Description | Buttons | Use Case |
|---|---|---|---|
AlertType.INFORMATION |
Shows information to the user | OK | Displaying success messages, notifications |
AlertType.CONFIRMATION |
Asks the user to confirm an action | OK, Cancel | Deleting items, important decisions |
AlertType.WARNING |
Warns the user about potential issues | OK | Non-critical warnings |
AlertType.ERROR |
Indicates an error has occurred | OK | Error messages, failed operations |
AlertType.NONE |
No predefined buttons | None | Custom button configurations |
Alert Structure
An Alert dialog has the following parts:
- Title: Displayed in the window's title bar
- Header: Displayed at the top of the dialog (can be null to hide)
- Content: The main message content
- Buttons: Action buttons (OK, Cancel, Yes, No - depending on type)
- Graphic: Optional icon displayed next to the header
Using Alerts in Jukebox: Admin Panel
The AdminPanelController uses two types of dialogs:
// In AdminPanelController.java
// Helper method for confirmation dialogs
private boolean showConfirmation(String title, String message) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle(title);
alert.setHeaderText(null);
alert.setContentText(message);
Optional<ButtonType> result = alert.showAndWait();
return result.isPresent() && result.get() == ButtonType.YES;
}
// Helper method for information dialogs
private void showAlert(String title, String message) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle(title);
alert.setHeaderText(null);
alert.setContentText(message);
alert.showAndWait();
}
Confirmation Dialog in Delete Operations
The confirmation dialog is used before deleting albums or songs:
// In onDeleteAlbumClicked method
public void onDeleteAlbumClicked(ActionEvent actionEvent) {
Album selected = albumsList.getSelectionModel().getSelectedItem();
if (selected == null) {
showAlert("Error", "Please select an album to delete");
return;
}
// Show confirmation dialog
if (showConfirmation("Delete Album", "Are you sure you want to delete '" + selected + "'?")) {
// User clicked Yes - perform deletion
albums.remove(selected);
Jukebox.database.albums.remove(selected);
// ... rest of deletion logic
}
// If user clicked Cancel or closed the dialog, nothing happens
}
// In onDeleteSongClicked method
public void onDeleteSongClicked(ActionEvent actionEvent) {
Song selected = songsList.getSelectionModel().getSelectedItem();
if (selected == null || selectedAlbum == null) {
showAlert("Error", "Please select a song to delete");
return;
}
// Show confirmation dialog
if (showConfirmation("Delete Song", "Are you sure you want to delete '" + selected.title + "'?")) {
// User clicked Yes - perform deletion
selectedAlbum.songs.remove(selected);
songs.setAll(selectedAlbum.songs);
// ... rest of deletion logic
}
}
- User clicks Delete button for an album or song
showConfirmation()is called with title and message- Alert dialog appears with Yes and Cancel buttons
- User clicks Yes or Cancel
showAndWait()returns anOptional<ButtonType>- If user clicked Yes, deletion proceeds; if Cancel or closed, nothing happens
- Prevents Accidental Deletion: Users must explicitly confirm destructive actions
- Clear Intent: Users understand the consequence of their action
- Undo Protection: Provides a moment for users to reconsider
- User Experience: Standard pattern that users expect for important actions
Error/Information Dialogs
Information dialogs are used to display error messages when users try to delete without selecting an item:
// When no album is selected
if (selected == null) {
showAlert("Error", "Please select an album to delete");
return;
}
// When no song or album is selected
if (selected == null || selectedAlbum == null) {
showAlert("Error", "Please select a song to delete");
return;
}
- Clear Feedback: Users immediately know what went wrong
- Guides Users: Explains what the user needs to do
- Prevents Confusion: Users don't wonder why nothing happened
- Non-Blocking Workflow: Simple OK button allows users to continue
Creating Confirmation Dialogs
Confirmation dialogs return a boolean indicating whether the user confirmed the action:
// Step 1: Create the Alert
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
// Step 2: Set dialog properties
alert.setTitle("Confirm Action");
alert.setHeaderText("Are you sure?"); // Optional
alert.setContentText("This action cannot be undone.");
// Step 3: Show the dialog and wait for response
Optional<ButtonType> result = alert.showAndWait();
// Step 4: Check the response
if (result.isPresent() && result.get() == ButtonType.OK) {
// User clicked OK/Yes - perform the action
performAction();
} else {
// User clicked Cancel or closed the dialog
// Do nothing or handle cancellation
}
showAndWait()displays the dialog and blocks the calling thread until the user responds- It returns an
Optional<ButtonType>which may be empty if the user closed the dialog without clicking a button isPresent()checks if the user clicked a button- For Confirmation dialogs, check for
ButtonType.OK(some systems use YES/NO instead of OK/Cancel) - Always call from the JavaFX Application Thread (which Jukebox does for event handlers)
Creating Information Dialogs
Information dialogs are simpler - they just display a message and wait for the user to acknowledge:
// Simple information dialog
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle("Success");
alert.setHeaderText(null); // Hide header for simple messages
alert.setContentText("Your changes have been saved successfully!");
alert.showAndWait();
// Warning dialog
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("Warning");
alert.setHeaderText("Low Disk Space");
alert.setContentText("Your application may not work correctly with limited disk space.");
alert.showAndWait();
// Error dialog
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Error");
alert.setHeaderText("Connection Failed");
alert.setContentText("Could not connect to the server. Please check your network connection.");
alert.showAndWait();
Customizing Alerts
You can customize various aspects of Alert dialogs:
Setting Header Text
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle("Confirm");
alert.setHeaderText("Please confirm your action"); // Appears below title, above content
alert.setContentText("This will delete all selected items.");
Using Custom Graphics
You can add icons or graphics to your alerts:
Alert alert = new Alert(Alert.AlertType.WARNING);
alert.setTitle("Warning");
alert.setContentText("This action cannot be undone!");
// Set a custom graphic (could be an ImageView with your icon)
ImageView icon = new ImageView(new Image("warning.png"));
icon.setFitWidth(48);
icon.setFitHeight(48);
alert.setGraphic(icon);
alert.showAndWait();
Custom Button Types
You can customize the buttons in an Alert:
Alert alert = new Alert(Alert.AlertType.NONE);
alert.setTitle("Custom Dialog");
alert.setContentText("Choose your action:");
// Create custom buttons
ButtonType button1 = new ButtonType("Save and Continue");
ButtonType button2 = new ButtonType("Save and Quit");
ButtonType button3 = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
// Set the button types
alert.getButtonTypes().setAll(button1, button2, button3);
// Show the dialog
Optional<ButtonType> result = alert.showAndWait();
// Handle the response
if (result.get() == button1) {
saveAndContinue();
} else if (result.get() == button2) {
saveAndQuit();
} else if (result.get() == button3) {
// Cancel - do nothing
}
When creating custom buttons, you can specify button behavior:
ButtonBar.ButtonData.OK_DONE- Default action buttonButtonBar.ButtonData.CANCEL_CLOSE- Cancel/close buttonButtonBar.ButtonData.YES- Yes buttonButtonBar.ButtonData.NO- No buttonButtonBar.ButtonData.APPLY- Apply buttonButtonBar.ButtonData.NEXT_FORWARD- Next buttonButtonBar.ButtonData.PREVIOUS_BACK- Previous button
Alert Styling with CSS
Alert dialogs can be styled with CSS. In Jukebox, they inherit the application's theme:
/* Style all dialogs */
.dialog-pane {
-fx-background-color: #121212;
}
/* Style dialog content */
.dialog-pane > *.label.content {
-fx-text-fill: #e0e0e0;
-fx-font-family: 'Courier New';
-fx-font-size: 14;
}
/* Style dialog header */
.dialog-pane > *.button-bar > *.container {
-fx-background-color: #1e1e1e;
}
/* Style dialog buttons */
.dialog-pane > *.button-bar > *.container > *.button {
-fx-background-color: linear-gradient(to bottom, #ff8c00, #e67e22);
-fx-text-fill: #121212;
-fx-font-family: 'Courier New';
-fx-font-weight: bold;
}
/* Style specific button types */
.dialog-pane > *.button-bar > *.container > *.button:cancel {
-fx-background-color: linear-gradient(to bottom, #f44336, #d32f2f);
-fx-text-fill: #ffffff;
}
.dialog-pane- The main dialog container.dialog-pane > *.label.title- The title label.dialog-pane > *.label.content- The content text.dialog-pane > *.button-bar- The button bar container.button:ok- The OK button.button:cancel- The Cancel button.button:yes- The Yes button.button:no- The No button
Dialog Best Practices
- Confirmation: Before destructive actions (delete, overwrite, etc.)
- Information: To notify users of success or important information
- Warning: To alert users about potential issues
- Error: When an operation fails and you need to inform the user
- Frequent Actions: Don't use dialogs for actions users perform repeatedly (add, edit with confirmation)
- Simple Notifications: Consider using status bars or labels for non-critical notifications
- Complex Input: For complex data entry, consider a custom dialog or a new view/scene
- Non-Modal Feedback: If the user needs to interact with the main window while the message is visible
- Clear Titles: Use descriptive titles that indicate the dialog's purpose
- Concise Messages: Keep content text short and to the point
- Clear Actions: Button labels should clearly indicate the action ("Delete", "Cancel")
- Default Button: The most common/safe action should be the default
- Consistent Placement: Use the same dialog type for similar situations
Alternative: Custom Dialogs
For more complex dialogs, you can create custom dialogs using Dialog class (parent of Alert):
// Create a custom dialog
Dialog<Pair<String, String>> dialog = new Dialog<>();
dialog.setTitle("Add New Item");
dialog.setHeaderText("Enter item details");
// Set the button types
dialog.getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
// Create custom content
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
TextField nameField = new TextField();
nameField.setPromptText("Name");
TextField valueField = new TextField();
valueField.setPromptText("Value");
grid.add(new Label("Name:"), 0, 0);
grid.add(nameField, 1, 0);
grid.add(new Label("Value:"), 0, 1);
grid.add(valueField, 1, 1);
dialog.getDialogPane().setContent(grid);
// Convert the result when OK is clicked
dialog.setResultConverter(dialogButton -> {
if (dialogButton == ButtonType.OK) {
return new Pair<>(nameField.getText(), valueField.getText());
}
return null;
});
// Show the dialog
Optional<Pair<String, String>> result = dialog.showAndWait();
// Process the result
if (result.isPresent()) {
Pair<String, String> data = result.get();
System.out.println("Name: " + data.getKey() + ", Value: " + data.getValue());
}
- Can contain any JavaFX nodes as content
- Can return complex data types
- Full control over layout and validation
- Use
setResultConverterto convert dialog content to a result value
Creating Your Own Helper Methods
Following Jukebox's pattern, create reusable dialog helper methods in your controllers:
Step 1: Add Helper Methods to Your Controller
public class MyController {
// Confirmation dialog helper
protected boolean showConfirmation(String title, String message) {
Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
alert.setTitle(title);
alert.setHeaderText(null);
alert.setContentText(message);
Optional<ButtonType> result = alert.showAndWait();
return result.isPresent() && result.get() == ButtonType.OK;
}
// Information dialog helper
protected void showInfo(String title, String message) {
Alert alert = new Alert(Alert.AlertType.INFORMATION);
alert.setTitle(title);
alert.setHeaderText(null);
alert.setContentText(message);
alert.showAndWait();
}
// Error dialog helper
protected void showError(String title, String message) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle(title);
alert.setHeaderText(null);
alert.setContentText(message);
alert.showAndWait();
}
}
Step 2: Use the Helpers in Your Code
// Using confirmation
if (showConfirmation("Delete", "Are you sure?")) {
deleteItem();
}
// Using information
showInfo("Success", "Item deleted successfully!");
// Using error
if (item == null) {
showError("Error", "Please select an item first");
return;
}
Try This:
- Run the Jukebox application and open the Admin Panel
- Try to delete an album without selecting one first - notice the error dialog
- Select an album and click Delete - notice the confirmation dialog
- Click Yes and see the album is deleted
- Click Cancel and see nothing happens
- Try the same with songs
- Open
AdminPanelController.javaand find theshowConfirmationandshowAlertmethods - Find where these methods are called in the delete handlers
- Try modifying the confirmation message to something different and see the change
Common Pitfalls
showAndWait() blocks the JavaFX Application Thread. Never call it from a background thread. All event handlers in Jukebox run on the JavaFX thread, so this is safe there, but be careful in other contexts.
Always check result.isPresent() before accessing the ButtonType. The user might close the dialog without clicking a button.
Don't perform long-running operations while showing a dialog. The UI will freeze until the operation completes. Use Task/Service for background operations.
Always set at least a title and content text. A dialog with no text is confusing to users.
Too many confirmation dialogs can frustrate users. Only use them for truly important or destructive actions.
Key Takeaways
- Use
Alertclass for standard dialog types (INFORMATION, CONFIRMATION, WARNING, ERROR) showAndWait()displays the dialog and blocks until user respondsOptional<ButtonType>is returned - always checkisPresent()- In Jukebox,
showConfirmation()returns boolean for Yes/No decisions showAlert()displays information/errors without expecting a decision- Dialogs are used in Admin Panel for delete confirmation and error messages
- Confirmation dialogs prevent accidental deletions
- Information dialogs guide users when they make mistakes
- Alerts can be styled with CSS
- For complex input, use custom
Dialogclass