How to use JFXAlerts?
There's no place for JFXAlerts in the demo, yet! Allow me to take the first step.
Here, now they have a place—all the boilerplate is done. #634
But there's nothing "demonstrated" yet. Can anyone help out with that?
Use JFXDialog instead of alerts.
Just for clarification, @XlintXms this issue is a request for JFXAlert documentation.
@jfoenixadmin, I saw that you added an example of how to use a JFXAlert; thanks :+1: .
You mentioned in #634 that "unlike java Alerts, JFXAlert doesn't support return type."
It'll be important to make it clear in the documentation how users should go about getting a result after a JFXAlert closes.
If one tries to use a JFXAlert like a Dialog things don't work the same. It's quite confusing.
While
Optional<String> result = dialog.showAndWait();
result.ifPresent(string -> System.out.println(string));
would give you back the right result when using a Dialog, with a JFXAlert you'll always get back a ButtonData.CANCEL_CLOSE.
If I understand correctly, the reason for this is because JFXAlert doesn't use ButtonTypes. Through a series of events native to Dialog, the ButtonData.CANCEL_CLOSE is returned because no result is specified.
I may have found a way to work around this. Say we don't use ButtonTypes, still. But we do set the result in the setOnAction method of the buttons we add to the actions section.
An example:
JFXTextField usernameTextField = new JFXTextField();
addUserButton.setOnAction(event -> {
// Ensure that the user can't close the alert.
JFXAlert<String> alert = new JFXAlert<>((Stage) addUserButton.getScene().getWindow());
alert.initModality(Modality.APPLICATION_MODAL);
alert.setOverlayClose(false);
// Create the content of the JFXAlert with JFXDialogLayout
JFXDialogLayout layout = new JFXDialogLayout();
layout.setHeading(new Label("Enter Username"));
layout.setBody(new VBox(new Label("Please enter the username of the person you would like to add."),
usernameTextField));
// Buttons get added into the actions section of the layout.
JFXButton addButton = new JFXButton("ADD");
addButton.setDefaultButton(true);
addButton.setOnAction(addEvent -> {
// When the button is clicked, we set the result accordingly
alert.setResult(usernameTextField.getText());
alert.hideWithAnimation();
});
JFXButton cancelButton = new JFXButton("CANCEL");
cancelButton.setCancelButton(true);
cancelButton.setOnAction(closeEvent -> alert.hideWithAnimation());
layout.setActions(addButton, cancelButton);
alert.setContent(layout);
Optional<String> result = alert.showAndWait();
if (result.isPresent()){
System.out.println("Your choice: " + result.get());
}
});
The sticky part of it is what happens if the result is never set (like in the case of the cancel button): Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: javafx.scene.control.ButtonType cannot be cast to java.lang.String
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Recently I discovered a way to avoid the ClassCastException that occurs if the user enters/clicks nothing (the one I mentioned in my last comment).
The default result converter returns a result of type ButtonType, even if the result is never set and no buttons are ever pressed, and that causes the ClassCastException. If we override it like this
alert.setResultConverter(buttonType -> {
// We don't want to use a result converter,
// if there is no result set explicitly, then return null.
return null;
});
then it will no longer try to return a ButtonType when no result is set. The result will be null if the user chooses nothing the first time—but that's what an Optional is for.
With this strategy, if we reuse the dialog, it's important to reset the result after you use it. If you don't, the same result sticks around for next time you use the dialog.
Optional<String> result = alert.showAndWait();
if (result.isPresent()){
System.out.println("Your choice: " + result.get());
alert.setResult(null); // reset the result for next time
}
If I understand correctly, the reason for this is because
JFXAlertdoesn't useButtonTypes. Through a series of events native toDialog, theButtonData.CANCEL_CLOSEis returned because no result is specified.I may have found a way to work around this. Say we don't use
ButtonTypes, still. But we do set the result in thesetOnActionmethod of the buttons we add to theactionssection.An example:
JFXTextField usernameTextField = new JFXTextField(); addUserButton.setOnAction(event -> { // Ensure that the user can't close the alert. JFXAlert<String> alert = new JFXAlert<>((Stage) addUserButton.getScene().getWindow()); alert.initModality(Modality.APPLICATION_MODAL); alert.setOverlayClose(false); // Create the content of the JFXAlert with JFXDialogLayout JFXDialogLayout layout = new JFXDialogLayout(); layout.setHeading(new Label("Enter Username")); layout.setBody(new VBox(new Label("Please enter the username of the person you would like to add."), usernameTextField)); // Buttons get added into the actions section of the layout. JFXButton addButton = new JFXButton("ADD"); addButton.setDefaultButton(true); addButton.setOnAction(addEvent -> { // When the button is clicked, we set the result accordingly alert.setResult(usernameTextField.getText()); alert.hideWithAnimation(); }); JFXButton cancelButton = new JFXButton("CANCEL"); cancelButton.setCancelButton(true); cancelButton.setOnAction(closeEvent -> alert.hideWithAnimation()); layout.setActions(addButton, cancelButton); alert.setContent(layout); Optional<String> result = alert.showAndWait(); if (result.isPresent()){ System.out.println("Your choice: " + result.get()); } });The sticky part of it is what happens if the result is never set (like in the case of the cancel button):
Exception in thread "JavaFX Application Thread" java.lang.ClassCastException: javafx.scene.control.ButtonType cannot be cast to java.lang.String
thanks.it works! I want to put your codes to generate a DialogBuilder which is the same as theAlertDiglogBuilder in Android delevopment