< prev index next >

modules/javafx.controls/src/main/java/javafx/scene/control/Dialog.java

Print this page




  84  * properties are simply forwarding API onto the respective properties on the
  85  * {@link DialogPane} stored in the {@link #dialogPaneProperty() dialog pane}
  86  * property. These three properties are forwarded from DialogPane for developer
  87  * convenience. For developers wanting to configure their dialog, they will in many
  88  * cases be required to use code along the lines of
  89  * {@code dialog.getDialogPane().setExpandableContent(node)}.
  90  *
  91  * <p>After configuring these properties, all that remains is to consider whether
  92  * the buttons (created using {@link ButtonType} and the
  93  * {@link DialogPane#createButton(ButtonType)} method) are fully configured.
  94  * Developers will quickly find that the amount of configurability offered
  95  * via the {@link ButtonType} class is minimal. This is intentional, but does not
  96  * mean that developers can not modify the buttons created by the {@link ButtonType}
  97  * that have been specified. To do this, developers simply call the
  98  * {@link DialogPane#lookupButton(ButtonType)} method with the ButtonType
  99  * (assuming it has already been set in the {@link DialogPane#getButtonTypes()}
 100  * list. The returned Node is typically of type {@link Button}, but this depends
 101  * on if the {@link DialogPane#createButton(ButtonType)} method has been overridden. A
 102  * typical approach is therefore along the following lines:
 103  *
 104  * <pre>{@code ButtonType loginButtonType = new ButtonType("Login", ButtonData.OK_DONE);
 105  * Dialog<String> dialog = new Dialog<>();
 106  * dialog.getDialogPane().getButtonTypes().add(loginButtonType);
 107  * boolean disabled = false; // computed based on content of text fields, for example
 108  * dialog.getDialogPane().lookupButton(loginButtonType).setDisable(disabled);}</pre>

 109  *
 110  * <p>Once a Dialog is instantiated and fully configured, the next step is to
 111  * show it. More often than not, dialogs are shown in a modal and blocking
 112  * fashion. 'Modal' means that the dialog prevents user interaction with the
 113  * owning application whilst it is showing, and 'blocking' means that code
 114  * execution stops at the point in which the dialog is shown. This means that
 115  * you can show a dialog, await the user response, and then continue running the
 116  * code that directly follows the show call, giving developers the ability to
 117  * immediately deal with the user input from the dialog (if relevant).
 118  *
 119  * <p>JavaFX dialogs are modal by default (you can change this via the
 120  * {@link #initModality(javafx.stage.Modality)} API). To specify whether you want
 121  * blocking or non-blocking dialogs, developers simply choose to call
 122  * {@link #showAndWait()} or {@link #show()} (respectively). By default most
 123  * developers should choose to use {@link #showAndWait()}, given the ease of
 124  * coding in these situations. Shown below is three code snippets, showing three
 125  * equally valid ways of showing a dialog:
 126  *
 127  * <p><strong>Option 1: The 'traditional' approach</strong>
 128  * <pre>{@code Optional<ButtonType> result = dialog.showAndWait();

 129  * if (result.isPresent() && result.get() == ButtonType.OK) {
 130  *     formatSystem();
 131  * }}</pre>
 132  *
 133  * <p><strong>Option 2: The traditional + Optional approach</strong>
 134  * <pre>{@code dialog.showAndWait().ifPresent(response -> {

 135  *     if (response == ButtonType.OK) {
 136  *         formatSystem();
 137  *     }
 138  * });}</pre>
 139  *
 140  * <p><strong>Option 3: The fully lambda approach</strong>
 141  * <pre>{@code dialog.showAndWait()

 142  *      .filter(response -> response == ButtonType.OK)
 143  *      .ifPresent(response -> formatSystem());}</pre>
 144  *
 145  * <p>There is no better or worse option of the three listed above, so developers
 146  * are encouraged to work to their own style preferences. The purpose of showing
 147  * the above is to help introduce developers to the {@link Optional} API, which
 148  * is new in Java 8 and may be foreign to many developers.
 149  *
 150  * <h3>Dialog Validation / Intercepting Button Actions</h3>
 151  *
 152  * <p>In some circumstances it is desirable to prevent a dialog from closing
 153  * until some aspect of the dialog becomes internally consistent (e.g. a form
 154  * inside the dialog has all fields in a valid state). To do this, users of the
 155  * dialogs API should become familiar with the
 156  * {@link DialogPane#lookupButton(ButtonType)} method. By passing in a
 157  * {@link javafx.scene.control.ButtonType ButtonType} (that has already been set
 158  * in the {@link DialogPane#getButtonTypes() button types} list), users will be
 159  * returned a Node that is typically of type {@link Button} (but this depends
 160  * on if the {@link DialogPane#createButton(ButtonType)} method has been
 161  * overridden). With this button, users may add an event filter that is called


 991         if (onCloseRequest == null) {
 992             onCloseRequest = new SimpleObjectProperty<EventHandler<DialogEvent>>(this, "onCloseRequest") {
 993                 @Override protected void invalidated() {
 994                     eventHandlerManager.setEventHandler(DialogEvent.DIALOG_CLOSE_REQUEST, get());
 995                 }
 996             };
 997         }
 998         return onCloseRequest;
 999     }
1000 
1001 
1002 
1003     /***************************************************************************
1004      *
1005      * Private implementation
1006      *
1007      **************************************************************************/
1008 
1009     // This code is called both in the normal and in the abnormal case (i.e.
1010     // both when a button is clicked and when the user forces a window closed
1011     // with keyboard OS-specific shortchuts or OS-native titlebar buttons).
1012     @SuppressWarnings("unchecked")
1013     void setResultAndClose(ButtonType cmd, boolean close) {
1014         Callback<ButtonType, R> resultConverter = getResultConverter();
1015 
1016         R priorResultValue = getResult();
1017         R newResultValue = null;
1018 
1019         if (resultConverter == null) {
1020             // The choice to cast cmd to R here was a conscious decision, taking
1021             // into account the choices available to us. Firstly, to summarise the
1022             // issue, at this point here we have a null result converter, and no
1023             // idea how to convert the given ButtonType to R. Our options are:
1024             //
1025             // 1) We could throw an exception here, but this requires that all
1026             // developers who create a dialog set a result converter (at least
1027             // setResultConverter(buttonType -> (R) buttonType)). This is
1028             // non-intuitive and depends on the developer reading documentation.
1029             //
1030             // 2) We could set a default result converter in the resultConverter
1031             // property that does the identity conversion. This saves people from




  84  * properties are simply forwarding API onto the respective properties on the
  85  * {@link DialogPane} stored in the {@link #dialogPaneProperty() dialog pane}
  86  * property. These three properties are forwarded from DialogPane for developer
  87  * convenience. For developers wanting to configure their dialog, they will in many
  88  * cases be required to use code along the lines of
  89  * {@code dialog.getDialogPane().setExpandableContent(node)}.
  90  *
  91  * <p>After configuring these properties, all that remains is to consider whether
  92  * the buttons (created using {@link ButtonType} and the
  93  * {@link DialogPane#createButton(ButtonType)} method) are fully configured.
  94  * Developers will quickly find that the amount of configurability offered
  95  * via the {@link ButtonType} class is minimal. This is intentional, but does not
  96  * mean that developers can not modify the buttons created by the {@link ButtonType}
  97  * that have been specified. To do this, developers simply call the
  98  * {@link DialogPane#lookupButton(ButtonType)} method with the ButtonType
  99  * (assuming it has already been set in the {@link DialogPane#getButtonTypes()}
 100  * list. The returned Node is typically of type {@link Button}, but this depends
 101  * on if the {@link DialogPane#createButton(ButtonType)} method has been overridden. A
 102  * typical approach is therefore along the following lines:
 103  *
 104  * <pre>{@code
 105  *     ButtonType loginButtonType = new ButtonType("Login", ButtonData.OK_DONE);
 106  *     Dialog<String> dialog = new Dialog<>();
 107  *     dialog.getDialogPane().getButtonTypes().add(loginButtonType);
 108  *     boolean disabled = false; // computed based on content of text fields, for example
 109  *     dialog.getDialogPane().lookupButton(loginButtonType).setDisable(disabled);}</pre>
 110  *
 111  * <p>Once a Dialog is instantiated and fully configured, the next step is to
 112  * show it. More often than not, dialogs are shown in a modal and blocking
 113  * fashion. 'Modal' means that the dialog prevents user interaction with the
 114  * owning application whilst it is showing, and 'blocking' means that code
 115  * execution stops at the point in which the dialog is shown. This means that
 116  * you can show a dialog, await the user response, and then continue running the
 117  * code that directly follows the show call, giving developers the ability to
 118  * immediately deal with the user input from the dialog (if relevant).
 119  *
 120  * <p>JavaFX dialogs are modal by default (you can change this via the
 121  * {@link #initModality(javafx.stage.Modality)} API). To specify whether you want
 122  * blocking or non-blocking dialogs, developers simply choose to call
 123  * {@link #showAndWait()} or {@link #show()} (respectively). By default most
 124  * developers should choose to use {@link #showAndWait()}, given the ease of
 125  * coding in these situations. Shown below is three code snippets, showing three
 126  * equally valid ways of showing a dialog:
 127  *
 128  * <p><strong>Option 1: The 'traditional' approach</strong>
 129  * <pre>{@code
 130  * Optional<ButtonType> result = dialog.showAndWait();
 131  * if (result.isPresent() && result.get() == ButtonType.OK) {
 132  *     formatSystem();
 133  * }}</pre>
 134  *
 135  * <p><strong>Option 2: The traditional + Optional approach</strong>
 136  * <pre>{@code
 137  * dialog.showAndWait().ifPresent(response -> {
 138  *     if (response == ButtonType.OK) {
 139  *         formatSystem();
 140  *     }
 141  * });}</pre>
 142  *
 143  * <p><strong>Option 3: The fully lambda approach</strong>
 144  * <pre>{@code
 145  * dialog.showAndWait()
 146  *      .filter(response -> response == ButtonType.OK)
 147  *      .ifPresent(response -> formatSystem());}</pre>
 148  *
 149  * <p>There is no better or worse option of the three listed above, so developers
 150  * are encouraged to work to their own style preferences. The purpose of showing
 151  * the above is to help introduce developers to the {@link Optional} API, which
 152  * is new in Java 8 and may be foreign to many developers.
 153  *
 154  * <h3>Dialog Validation / Intercepting Button Actions</h3>
 155  *
 156  * <p>In some circumstances it is desirable to prevent a dialog from closing
 157  * until some aspect of the dialog becomes internally consistent (e.g. a form
 158  * inside the dialog has all fields in a valid state). To do this, users of the
 159  * dialogs API should become familiar with the
 160  * {@link DialogPane#lookupButton(ButtonType)} method. By passing in a
 161  * {@link javafx.scene.control.ButtonType ButtonType} (that has already been set
 162  * in the {@link DialogPane#getButtonTypes() button types} list), users will be
 163  * returned a Node that is typically of type {@link Button} (but this depends
 164  * on if the {@link DialogPane#createButton(ButtonType)} method has been
 165  * overridden). With this button, users may add an event filter that is called


 995         if (onCloseRequest == null) {
 996             onCloseRequest = new SimpleObjectProperty<EventHandler<DialogEvent>>(this, "onCloseRequest") {
 997                 @Override protected void invalidated() {
 998                     eventHandlerManager.setEventHandler(DialogEvent.DIALOG_CLOSE_REQUEST, get());
 999                 }
1000             };
1001         }
1002         return onCloseRequest;
1003     }
1004 
1005 
1006 
1007     /***************************************************************************
1008      *
1009      * Private implementation
1010      *
1011      **************************************************************************/
1012 
1013     // This code is called both in the normal and in the abnormal case (i.e.
1014     // both when a button is clicked and when the user forces a window closed
1015     // with keyboard OS-specific shortcuts or OS-native titlebar buttons).
1016     @SuppressWarnings("unchecked")
1017     void setResultAndClose(ButtonType cmd, boolean close) {
1018         Callback<ButtonType, R> resultConverter = getResultConverter();
1019 
1020         R priorResultValue = getResult();
1021         R newResultValue = null;
1022 
1023         if (resultConverter == null) {
1024             // The choice to cast cmd to R here was a conscious decision, taking
1025             // into account the choices available to us. Firstly, to summarise the
1026             // issue, at this point here we have a null result converter, and no
1027             // idea how to convert the given ButtonType to R. Our options are:
1028             //
1029             // 1) We could throw an exception here, but this requires that all
1030             // developers who create a dialog set a result converter (at least
1031             // setResultConverter(buttonType -> (R) buttonType)). This is
1032             // non-intuitive and depends on the developer reading documentation.
1033             //
1034             // 2) We could set a default result converter in the resultConverter
1035             // property that does the identity conversion. This saves people from


< prev index next >