JDK-8097791 : Add javafx.scene.control.Alert class
  • Type: Enhancement
  • Component: javafx
  • Sub-Component: controls
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2011-04-18
  • Updated: 2022-06-24
  • Resolved: 2014-08-17
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8
8u40Fixed
Related Reports
Blocks :  
Blocks :  
Blocks :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
The existing javafx.stage.Alert class will be removed. See RT-12638 for a description of the problem.

If we want an Alert class, then we should implement it as a control.

Comments
@Jonathan Although "the race is run" and the comment comes too late: v6 looks good, I'm looking forward to JavaFX 8u40.
22-08-2014

Dialogs are now in the repo! Future work will fall to other jira issues, many of which have been filed (and linked to this issue), with many more yet to be filed (presumably)...Thanks everyone for contributing to this jira discussion. Changeset: http://hg.openjdk.java.net/openjfx/8u-dev/rt/rev/4d239b9d4e31
17-08-2014

@David: Thanks for the pointer about changing px to em sizes - I've made the change. Regarding adding css to caspian, there is a separate issue for that (which also includes improving the modena styling beyond my simple efforts). There is also another jira issue to replace my placeholder graphics with proper graphics. See RT-38299 and RT-38271. @Kevin: Thanks for the pointers - I've made these changes too. To respond to your comments: 1) Regarding needing both Dialog.close() and Dialog.hide(), I only added the hide() method as it was requested by Steve in an API review meeting to be equivalent to Stage. I am quite comfortable leaving them both in, and equally comfortable taking one of them out. For now I will leave both in, but feel free to discuss whether you would like to remove one (most probably hide(), if anything). 2) The issue with CANCEL not being returned in the confirmation dialog abnormal case was due to our recent change where the resultConverter went from being non-null by default to null by default. This meant we couldn't translate CANCEL to an expected value. I have fixed that locally already so that we have the correct functionality from the get-go. 3) Layout issues are already captured in RT-38321. There are layout issues because I rewrote the layout code last week to make extending DialogPane better, but I have not had the time to complete the layout code. This will be resolved ASAP. 4) Missing ButtonBar images: I have created rt\modules\controls\src\main\docs\javafx\scene\control\doc-files and added the files there. I have confirmed that the images now load in the javadoc. 5) I have tidied up the ButtonBar references to the term 'type' in all places, but there exists a ButtonData.getType() method that should now be renamed. I've left it as-is for the initial check-in, but we should rename it as soon as possible with an agreed name. 6) I will push your HelloAlert patch today. I will work as soon as possible to get my samples into the repo as well (currently tracked via RT-38318)
17-08-2014

If you get a chance, can you please push the attached "HelloAlert.patch" for me after you push your changes (you should be able to simply "hg import" it)? That way we will at least get a round of sanity testing on the new Alert class during Monday's (in)sanity test. If not, then no problem...I'll just do it on Monday.
15-08-2014

+1 on the API (pending fixing the @since tags and removing the redundant constructor)
15-08-2014

Here is my feedback. The ones in the first section titled "API ISSUES" should be fixed prior to pushing the code. The rest can be done later. API ISSUES ========== Alert.java ---------- * The following named arg parameter: public Alert(@NamedArg("AlertType") AlertType alertType) should be: public Alert(@NamedArg("alertType") AlertType alertType) in all constructors. * The following constructor is redundant and should be removed: 238 public Alert(@NamedArg("AlertType") AlertType alertType, 239 @NamedArg("contentText") String contentText) { 240 this(alertType, contentText, (ButtonType[])null); 241 } It provides no additional capability over the subsequent constructor with the varargs list of buttons. * Add an "@since JavaFX 8u40" tag on the AlertType enum (since it is a separate class that shows up in a separate page in the API docs, it needs its own tag) ButtonBar.java -------------- * Add an "@since JavaFX 8u40" tag on the ButtonData class DialogEvent.java ---------------- * The following is an incorrect @since tag (copy / paste error) and must be removed: 127 * @since JavaFX 8.0 ... 129 public DialogEvent copyFor(Object newSource, EventTarget newTarget, EventType<DialogEvent> type) DialogPane.java --------------- * The following is an incorrect @since tag (copy / paste error) and must be removed: 1055 * @since JavaFX 8.0 ... 1057 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() API QUESTIONS ============= Dialog.java ----------- * Do we need both close() and hide() methods? (I know Stage has both...just asking) IMPLEMENTATION ISSUES ===================== Bugs should be filed for each of these * A confirmation alert (with OK / CANCEL) will return Optional.empty() if the window is closed (e.g., with the red 'X'), which is not whatis specified. It should instead return CANCEL in that case. * Layout issues: 1) some of the text is truncated and replaced with elipses; 2) The minimum size of DialogPane seems too small to accommodate even a reasonably short title JAVADOC ISSUES ============== Here are a couple javadoc issues, which can be addressed later, but I noticed them so wanted to capture them. ButtonBar.java -------------- The following images are missing (broken links) : 71 * <strong>Windows:</strong><br/><img src="buttonBar-windows.png" /><br> 72 * <strong>Mac OS:</strong><br/><img src="buttonBar-mac.png" /><br> 73 * <strong>Linux:</strong><br/><img src="buttonBar-linux.png" /><br> 179 * An enumeration of all available button types... ... 186 public static enum ButtonData { You should probably avoid referring to them as "button types" to avoid confusion with the ButtonType class.
15-08-2014

+1 for the API
15-08-2014

Just a note about the styles in modena.css, which are also needed in caspian.css. The fixed sizes, like '-fx-padding: 8 8 8 8;' should be expressed in 'em' values. For example '-fx-padding: 0.615em;'
15-08-2014

Thanks to Kevin, we now have the 'final' webrev available for review here: http://cr.openjdk.java.net/~kcr/RT-12643/webrev.00/ This webrev is based on the ButtonType V6 API. I invite any feedback you may have, although at this stage it is really about bugs and mistakes in the API. Thanks!
14-08-2014

No worries, in the end we will try to adapt to what will be put in the JDK... or find another library or make one that suits our needs better than the default one ^^.
14-08-2014

Thanks for the feedback. I've been in the action camp since the beginning, so I hear you, but as I noted in an earlier comment, the V6, non-action approach is currently sitting with probably greater than 99% odds of winning between the two approaches.
14-08-2014

And tha'ts exactly why I am against this: too limited compared to v5, trying to hard to be "too simple", does not allow any improvement or expansion of the rest of the button based API.
14-08-2014

@Fabrice: I'm ok with people double-voting, especially because I've been shifting the goal posts as the API is refined. Out of interest, have you taken a look at the V6 ButtonType class in the latest javadoc? Like I said earlier, it is 'action-lite' (as in, really, really, really, _really_ 'lite').
14-08-2014

I've already voiced my opinion and voted : action is the way to go, buttonType is not!
14-08-2014

The silence is deafening! :-) The only thing I can assume is that everyone has looked at the v6 documentation [1] and have accepted that it is perfectly suited to all of their use cases. In which case - excellent! :-) If I'm mistaken, time is nearly out - that is, we're down to the last few days until the code moves into the repo, and from that point more people will be working with the API (e.g. SQE will be writing tests, documentation may start working on documents, I'll be writing more javadoc and unit tests) - and therefore the API starts to become more and more concrete as each day goes by. Now is by far the best time for you to register your feedback, be it positive or negative. [1] http://jonathangiles.net/javafx/dialogs/v6
14-08-2014

Just a quick note: as time permits I am refreshing the v6 javadoc [1] to include improved documentation. Certainly what is in there now is much better than what was posted this morning (but still a long way from being complete). Hopefully it may be a little more useful to people now. I'd appreciate any comments on the javadoc, or any recommended code examples. [1] http://jonathangiles.net/javafx/dialogs/v6
12-08-2014

Hi all. It's been a while since I gave an update. The summary is that I've been revising both the v5 and v6 API based on feedback. Both API are now at their 'final' stages where we don't intend to make major overhauls, and any changes to the API now would only be driven by bugs or missing features that _must_ be accommodated. Therefore, now is your last chance to review and comment on the V5 and V6 API before the code enters the OpenJFX repo and starts its long journey to being included in JavaFX 8u40. If you have a use case that fails, now is the time to make it clear. V6 has changed quite considerably over the past few weeks. The general, high-level summary is that V6 has moved towards being an 'actions-lite' approach, whilst V5 has remained roughly where it was originally (although both APIs have seen significant tweaks). If you want to review the API, you should assume that 98% of the API (and implementation) is the same between V5 and V6, and focus on the main difference: V5 has DialogAction, and V6 has ButtonType. If you compare the API on these two classes (and note that DialogAction extends Action), you'll understand the primary difference between the two options: ButtonType provides no API to configure the dialog button beyond the display text and ButtonData, whereas V5 has the API available on Action/DialogAction to configure the dialog button. If you want to configure the button beyond what the V6 and V5 API permit, you need to call dialogPane.lookupButton(action / buttonType), and do what you want to do directly on the node. As of right now, the odds are looking really likely that V6 will be the chosen option. The onus is now on you, the community, to voice your opinion. It would be great if you could focus on your use cases, and how they would work in these two APIs. We want to hear what does and does not work - it isn't time to talk about restructuring the API. As always, I have uploaded the latest javadoc onto my webserver (but note that I have still not updated the javadoc - it has been left to rot until the API is signed off, and then I will start the task of writing javadoc). Here are the links: http://jonathangiles.net/javafx/dialogs/v5 http://jonathangiles.net/javafx/dialogs/v6 And I have uploaded the latest code to this jira issue, in case you want to download and test the actual code. Thanks - I look forward to your feedback!
11-08-2014

The Window.onCloseRequest already allows an application (trusted or not) to override the default behavior and actually not close the window when user clicks the X button. I agree that we might want to add more restrictions for the untrusted case. However, I don't agree that adding this feature would be "a mistake" in general case.
05-08-2014

I think it would be a mistake to add non-closeable windows to the API, irrespective of whether or not they might be useful for dialogs (for one thing we could / would not do this in an untrusted context, so we would still have to deal with it).
05-08-2014

> In regards to removing the X button - this isn't the only problem, so removing it isn't going to help. People can still alt-F4, etc to hide the dialog, and in doing so we have exactly the same problem being discussed here. The X (CLOSE) button in a window titlebar can be hidden and/or deactivated. Glass supports this already: the Window.CLOSABLE style controls that. If you make a window *not* closable, then neither the X button nor Alt+F4 will close the window.
05-08-2014

Mikael, Thanks for giving your feedback on wizards. I'll work through it in more detail in the coming days. I should note that quite some time back Eugene and I prototyped two different Wizard APIs in ControlsFX, based on the dialogs API there. You can see it in the wizard branch, but also you can see a fair amount of discussion in Eugene's pull request (which essentially throws out my very simple API and replaces it with a more complete API), here: https://bitbucket.org/controlsfx/controlsfx/pull-request/365/first-prototype-of-wizardflow-based-api/diff The general concept was the user passed in a list of pages to a Wizard instance, and a means of progressing through them (typically linear, but also with support for branching). There was code inside Wizard that would collect all the user input and store it into a map, so that the developer doesn't have to do anything at the end other than pull values out of a map. I think this is your point 9), but I'm not sure I fully comprehend what you're saying. If you have the bandwidth, please take the time to look at the code linked above - it would be interesting to hear your thoughts.
03-08-2014

I have now (last night) created a Wizard API based on my own slightly modified version of a Dialog API as presented in the beginning of this thread. I thought I'd check in to share some findings along the way. I had to modify the Dialog API slightly to accommodate for the Wizards API. If I hadn't then the wizard's API would not have been as good (IMO). Just a heads up that it might be a good idea to at least model a Wizard API before finalising the Dialog API. Some requirements I had and general API comments. 1) The WizardController is a DialogPane. It has a number of WizardPanes which it controls. 2) WizardPane (an interface) has an ID so that it can reference next and previous in a decoupled and dynamic way. 3) WizardPane has ReadOnly properties with Optional<String> nextId/prevId. The optional part is so that a wizardPane can hinder Next if a branch has not been selected or if there is a requirement to fill out the current form before proceeding. It's a property so that the WizardController can listen to it. The value Optional.of("") is used to denote: "just take the next pane in the list" and is the default. 4) WizardPane implements DialogPane 5) Dialog (my DialogPane controller) now has an add/removeDialogButtonActionListener so that DialogPanes don't have to interact with the buttons directly if all they want is to know which one gets pressed and the Dialog doesn't have to pass the pressed button around explicitly. 6) DialogPane now has onShowSet(Optional<v> value) and Optional<V> onHideGet() to make it easier to manage the sequence of adding and removing panes, which was necessary for the Wizard API. 7) DialogPane has an init(Dialog) that is called by the Dialog so that DialogPane has a clear entry point where it can append things to the Dialog. When the init(..) method is called, and how, is clearly defined. For instance the whole UI of the Dialog should be created, but not shown and it is only called once. 8) Dialog has a .initialValue(V value) (setInitialValue(V value) for you) that takes the value and passed it to the DialogPane and thus also the WizardController (which use it as a star value for the first WizardPane). This way the initial value doesn't have to be set in the DialogPane/WizardPane constructors. 9) WizardPanes can work BOTH with a common value that is passed back and forth when the panes is showing/hiding AND a collector that collects all values in a Map indexed by the WizardPane ID. I think it is important to support both WizardPanes that knows how to collaborate (made for one wizard flow) and WizardPanes that does one specific thing and returns a value that is not in any way depending on the panes around. This part was the most tricky one to solve..\ 10) WizardPane has a name (might be extended to provide som more info) so that a progress Pane (west or north) can be created automatically. Cheers, Mikael
02-08-2014

I agree with Scott. +1 for switching showAndWait() to Optional<R>
01-08-2014

+1 for switching showAndWait() to Optional<R> Optional.empty() seems to be the logical result of *not* choosing anything, and we agree closing the window is different from making a normal choice. It's slightly more overhead, but nothing crazy. We could always make a couple helper methods to simplify our typical use-cases if it got to that.
31-07-2014

@Jonathan Don't we just need a pair of results? The first element is true/false indicating whether the dialog was closed via the X button, the second element containing the result of type R if the first element is true. Its basically an optional of an optional. In other words the Dialog result type shouldn't be R, but a pair of boolean with R.
31-07-2014

If people are against the X button being CANCEL (and having this passed into the resultConverter where the dialog developer can handle the situation and convert to a value or null / Optional.empty()), then the only option that leaves is to return null / Optional.empty() from showAndWait() in these cases: 1) If people would rather have the result of a forced closing on a dialog be null, then showAndWait() can return null. This prevents any subclass of Dialog<R> (where R is the result type) to be defined as DialogSubclass<Optional<T>>. This is because the user has specified that they return Optional<T> as their result type, but showAndWait() can return null. We are breaking the contract of Optional by returning null in exceptional circumstances. I don't think Jira can handle the number of bug reports that will rain down on it if this is the way we go. 2) The other option is to have showAndWait() return Optional<R>, and to change TextInputDialog<Optional<String>> to TextInputDialog<String> (and the same with ChoiceDialog). This then affords us two options: 2.1) In the case where the dialog is force closed, we can return Optional.empty() to indicate that no option was selected. We will not even ask the dialog creator if they want to override this (so we won't call the resultConverter). 2.2) We can continue to do what we currently do, which is to pass CANCEL to the resultConverter, and let this have the ultimate say on what the result type is. Personally, my preference is to either stick with what we have, or to switch showAndWait() to Optional<R>. The downside of this approach is that there is slightly more overhead for users. In regards to removing the X button - this isn't the only problem, so removing it isn't going to help. People can still alt-F4, etc to hide the dialog, and in doing so we have exactly the same problem being discussed here.
31-07-2014

What would a user expect on using the close button on a dialog? Usually my assumption would be take no action. If the user is required to select an action then removing the close button from the title would be appropriate. If cancel isn't appropriate for close - what would the user assume? I would assume the negative action when a choice is presented or ok if only one button is presented. Ideally I would prefer the option to not have a close button on the dialog a require the user to interact with an action (button) directly. More than likely if I could remove that option from the user, I'd never have them on a dialog. The more I think about it, i want to change my vote to -1 on Cancel = Close.
31-07-2014

-1 on Close=Cancel too. This kind of non-explicit API eventually comes around to bite you.
31-07-2014

-1 on Close = Cancel. I am probably being pendantic about this, but here is my reasoning: In any GUI only ever have one element doing any one thing (redundent menus excluded). I have so often wondered in software what the title bar's close button does -- and I click it with some degree of trepidation. That is why you do not see such buttons in title bars of most commercial software. I would prefer being explicit and not attaching any semantic meaning to that button, and Cancel is a semantic designation.
31-07-2014

+ 1 on Close = CANCEL + 1 on the API to hide the close button in cases where it is not appropriate
31-07-2014

@Jonathan Yes, when I think a bit longer about it, I would usually assume CANCEL when the user presses CLOSE, so I'm coming around to CANCEL being appropriate for a close. I was initially thinking that it might not be clear if CANCEL wasn't even among the actions configured for the dialog in the first place. E.g. what if the dialog only allows YES/NO? But then you still would need to handle empty or null if the user pressed close anyway, so I suppose that isn't different from having to still handle CANCEL. If there was API available to hide the close button that would be even better.
31-07-2014

@Jonathan I've managed to use Dialog (but without any actions) in FXML and it worked well :-) The dialog content had its own buttons that I wired, in the FXML controller, to set the result and close the dialog. There are two things I noticed: 1. To set the result I had to use resultProperty because setResult() is protected, so should it not maybe be public ? 2. Initially I had Dialog<Reference> but found that when the dialog is cancelled I get a cast exception, which makes sense as dialog is returning ACTION_CANCEL. This had two implications: a. I HAD to change the dialog's return type to <Optional<Reference>> and b. I HAD to make sure that resultProperty was initialized with Optional.empty() You suggested an option to change the return type of showAndWait to Optional<R> which it would seem is supported by my experience above.
31-07-2014

Scott - personally I don't mind this approach (of returning Optional<R> from showAndWait()). The only thing missing is what to pass in to the resultConverter in this case - the result is more than likely null (there would have to be some non-blocking / threading code interactions for it to be non-null), so we're still back at the fundamental problem that we're trying to avoid (that is, passing CANCEL into the resultConverter), and in the meantime we've potentially polluted the API with Optional<R>, instead of R (although only marginally). My initial suggestion was to not use the resultConverter in this case, and just return the empty Optional, but as I said this short-changes the dialog creator from being able to modify the result. API design is fun, huh? :-) For this reason, I still tend to lean towards my current approach of showAndWait returning R, but having code that calls the resultConverter with CANCEL if the dialog was closed abnormally. With regard to hiding the close button - it's tough to say. I'm hamstrung by the fact that I either only offer the cross platform style (in which case I can control the titlebar controls and just hide them all), or else I offer the native chrome, but then live with the limitations of the API, which in this case is to have the X button in the titlebar. My gut feeling is that we need to agree on what the X button means in any case (as either we'll have the native chrome, or else we'll eventually have API to show / hide the X button anyway), so we might as well standardise. I think having the X button mean CANCEL makes sense for me, as opposed to any other existing type, and I don't like the confusion that would come in if we defined an action / DialogButtons enum for representing the forced closed concept. It would actually be interesting to step back and understand why knowing how the dialog was shut is important. To me I can't immediately think of a use case where I, as a dialog API consumer, would need to know this - can you? One option is to encode this information in the DialogEvent class, so that you may be informed via the Dialog onShowing / onShown / onHiding / onCloseRequest / OnHidden events that are fired. Thoughts?
31-07-2014

Yes I agree that if the API is using Optional then null would be rather silly :-). But I like this: "change the return type of showAndWait to Optional<R>, such that we can at least check if the result is null, and in those cases return Optional.empty()." So how about doing that and making the result converter return the same Optional<R> so it can decide to return Optional.empty() ? I do think it is important to be able to tell the difference between closing the dialog with the close button vs. cancel. Though I suppose one could argue for not having a close button at all. On OS X for example, the close button on a File Open dialog is disabled - you either click Cancel or Open, but that would be a non-standard thing to do for other platforms.
31-07-2014

Scott, currently null is not a good return type. This is because Dialog is typed as Dialog<R>, where R is the return type, and in some cases (e.g. TextInputDialog, ChoiceDialog), the R is Optional<String> or Optional<T>, respectively. Returning null when the return type is Optional is really bad form (such bad form that I joked about doing it on Twitter a few months back [1]):-) There are a few options, but all feel worse than what is there now (in my opinion). One option is to call the resultConverter with null, rather than CANCEL, and have that indicate that the dialog has been force-closed. Passing in null smells a little to me. Another option is to change the return type of showAndWait to Optional<R>, such that we can at least check if the result is null, and in those cases return Optional.empty(). The problem with this approach is that it short-changes the dialog developer - they might want to do something else when the dialog is cancelled, but by not calling the resultConverter, there is no way for them to do this. Yet another option is to have a special Action / DialogButton for a forced close, and to pass that into the resultConverter. This would at least answer your question of how should you know the difference, although I'm not overly keen on having a DialogButtons.FORCED_CLOSE enum item, as it hardly seems relevant on the other side of the fence (when defining the buttons to show). [1] https://twitter.com/JonathanGiles/status/463956139785216001
31-07-2014

Would a null result in the case of closing the window without actually clicking one of the action buttons make more sense than returning CANCEL? After all they *didn't* pick Cancel, how will we tell the difference should we need to?
31-07-2014

@Scott: Good questions. Regarding the resultConverter and the default action - sorry, I was unclear. What is currently happening in the code is that we always pass in ACTION_CANCEL or DialogButtons.CANCEL. In other words, the top-right X is equivalent to the cancel action. Part of me wonders whether this is accurate - there may be circumstances where the developer does not have a cancel button in their dialog and would be confused (or unprepared) to accept a cancel input button being pushed. However, I think for the sake of cleanliness and consistency, using cancel here seems best. The best I can do from here is to javadoc it really well. The reason why expanded / expandedContent are currently in the API is because whilst it is indeed something that can be handled externally by developers, it could probably be handled better internally. There are a lot of small details around dialog and content resizing correctly, dialog repositioning, possibly animating the dialog resizing, etc. I'm happy to remove it, although I imagine that before long it will be requested by the masses :-) Regarding DialogPane: 1) Correct - this is the primary use case (until such time that a sheet StageStyle was supported). 2) The layout code for a dialog is currently in DialogPane. In past revisions of the code, when DialogPane didn't exist, all that code existed in Dialog. It was simply moved from one class to the other (and slightly tweaked where necessary). So yes, all the code is the same, and the concept of a root dialog pane has been more formalised, but I doubt that many people will create a DialogPane instance and mess with its children and their layout, or subclass DialogPane and offer new API (DialogPane extends Region, so things can be made as different as you want....). I guess my question is - have people who asked for DialogPane actually looked at the API and decided it works for them? If not, what needs to change?
30-07-2014

"This resultConverter is also used in the case where dialogs are closed using the X button (where the default action / button is passed into the resultConverter (i.e. ACTION_CANCEL or DialogButtons.CANCEL)." Forgive me for not having time to look in detail, but is the "default" action really what we want here? E.g. if the default action was OK, I would still want the close to do a CANCEL. Is "expandable content" something we want in the core dialog API? That seems like a special-case that would make more sense to handle with custom content. The two uses of DialogPane would be: 1) to get a panel that could be used in a different context than a normal Stage. E.g. a panel that slides down from the top of the window like a "sheet" on OS X. That being said - proper support for hosting the panel in a real Sheet on OS X would be great! This would be a new StageStyle - a conditional feature similar to StageStyle.UNIFIED. 2) when you want to get a "standard-looking" dialog, with the buttons placed in the platform specific locations, with standard images etc, and then tweak it for some reason - for those unforeseen customizations that the API doesn't handle. Setting a custom content property is different. Presumably there will always be a DialogPane of some sort under the hood anyway to handle the standard dialog layout. But when you say you don't think it has value, I'm confused. How are you doing the dialog layout in the case where you don't have this?
30-07-2014

I've done a small refresh of the v5 and v6 APIs, which are in their normal places: http://jonathangiles.net/javafx/dialogs/v5/ http://jonathangiles.net/javafx/dialogs/v6/ I've also updated the attachments to this jira issue, for those keen to play along at home. The main changes since last refresh: 1) Cleaned up constructors throughout the API 2) Introduced resultConverter to DialogPane, to convert from Action (V5) and Node/DialogButtons (V6) to the result type R. This replaces the previously used 'convertActionToResult' method that could be overridden. This resultConverter is also used in the case where dialogs are closed using the X button (where the default action / button is passed into the resultConverter (i.e. ACTION_CANCEL or DialogButtons.CANCEL). 3) Action now has a selected property for use in applicable controls (Radio / Toggle controls mostly). 4) DialogPane now has a protected method createDetailsButton. This method is called in the case where a dialog has a non-null expandableContent property, and is used to create the button to expand / collapse the expandable content. The default implementation works fine, so in almost all cases I expect people will not override this method. 5) It is now possible to set the dialog x/y position. 6) I removed the Dialog.shake() API - which is probably something no one ever noticed. All it did was shake the dialog window gently a few times to get the users attention. It was something I threw into controlsFX as a fun way to tell the user they entered the wrong username / password into a login dialog. It isn't something I think we need in JavaFX though :-) As should be becoming clear, the changes are getting smaller and more focused. Your feedback on the API is, as always, critical to getting things right, so please do take the time to offer your feedback. I have two questions: 1) Should Dialog have an expanded property? In my opinion yes - there is one on DialogPane and it feels weird not having it on Dialog. 2) I'll repeat my question from the other day: is there really any value in DialogPane. I am becoming increasingly tempted to take it away again. Thanks!
30-07-2014

@Jonathan Unfortunately I didn't get to work some more with this today, but will try again tomorrow. My inclination at this stage is that DialogPane can go, as one can set a custom pane with either setHeader, setContent, or setGraphic (or even some combination?). I think that if alertType is supplied as null then the user probably doesn't want an icon. If specifying null for this is a problem then maybe there should be a Alert.AlertType.NONE or something like that ?
29-07-2014

@Jurgen: I've resolved (locally) some of your concerns: 1) I've added an Alert(AlertType) constructor 2) I've added a check in the Alert constructor for a null alertType, and if so, I set it to be AlertType.INFORMATION. 3) I've made a big change to deal with the issue you raised around TextInputDialog and ChoiceDialog returning null when the top-right X is clicked. The implementation code now discerns between normal and non-normal closing of the dialog. Currently the only non-normal is clicking the X (but in the future maybe I'll need to support alt-F4, etc). When a dialog is closed in a non-normal way, and the result property is null, I essentially call the resultConverter with an argument of ACTION_CANCEL, and I return the result from this from showAndWait. This new result is then set as the result on the dialog, and return from showAndWait() With regard to there not being a minimise button - this is purposeful for now.
28-07-2014

@Jurgen: Dialog is like a Window (or Stage), and DialogPane is its root node. So no, what is being done here isn't really comparable to Control and Skin. However, the thing I do wonder about (still) is whether DialogPane really is worth keeping around. The only benefit it offers is to create a node that looks like a dialog without being in a separate window. My impression is that this use case is relatively unimportant for most people. The other argument for DialogPane is that it allows for complete customisation of a Dialog by essentially putting whatever you want in there - but this is already doable by users by creating a Dialog and then setting a Node of their choosing into the Dialog.content property. If the user does not set a header, or any buttons / actions, then the node that they pass in will be the only thing showing.
28-07-2014

@Jurgen: Thanks for taking things for a spin! I'm ok with taking bug reports now, but if the inflow gets to be too great I might suggest actually filing new jira issues rather than going in depth in this jira issue. I'll take on board your API suggestions and feedback, and will work on them as time permits. Regarding your comment about examples in javadoc: absolutely! This is the plan, but as I noted elsewhere I'm not placing too much emphasis on javadoc yet as the API is still in flux, so I'd probably end up rewriting it three times :-) Definitely once the API is locked down I plan to go crazy with javadoc, including examples. Regarding the ChoiceDialog - for one there has been no UI design done - but for two this was my preference, and I've done it for no other reason than that. I'm sure once someone with more design skills gets a chance to review that it will be tweaked to look more appropriate.
28-07-2014

@Jonathan Thanks for the source code. Here are some comments: I think it'll be important to have an actual example in the java docs to show and emphasize how to access and use the built in actions. I was inclined to try and access them as static objects and took a while to get it that they must be accessed through my own variable, which feels weird for some reason. Alert API note: It would be nice if Alert had a constructor Alert( AlertType ) I realize we are focusing on API at the moment and am not sure as to how relevant bugs are, but here are a few glitches: Alert needs to check for alertType != null Can't minimize when STYLE_CLASS_CROSS_PLATFORM Closing ChoiceDialog and TextInputDialog with X returns null instead of Optional. ChoiceDialog and TextInputDialog should use confirm.image instead of info.image Personally I don't like that the choiceControl stretches all the way across the ChoiceDialog. (Was this done to hide / circumvent ChoiceBox's width issues ?) Anyway I think only ComboBox should be used in ChoiceDialog, and setMaxWidth removed. Thanks for all the effort you've put into this so far Jonathan.
28-07-2014

@Jonathan Maybe the Dialog<DialogAction> class isn't really needed ? What about only having AbstractDialog<R> and no Dialog class (i.e. Dialog becomes AbstractDialog) then we won't have any additional classes. Would that remove the confusion you see new users might have ? On a side note: Is Dialog like a control and DialogPane is then it's skin ? If that is the case shouldn't Dialog and DialogPane be refactored into the control and skin way of doing things ?
28-07-2014

Hi all. I wanted to briefly summarise the concerns / findings Eugene and I have had regarding our 'button type' (i.e. V6) prototype. The list below is not exhaustive, but it does present our biggest concerns. Ideally we would refine the V6 API to resolve these (or alternatively, resolve that the button type approach is flawed and progress in another direction (or proceed with the actions approach)). I look forward to your feedback. 1) There is a disconnect between pre-built 'DialogButtons' and the actual Buttons: 1a) Dialog / DialogPane have getButtons() method, so people are expected to set the buttons they want to show in the dialog. To use DialogButtons (the 'pre-built' buttons), the user needs to call Dialog.createButton(Dialog, ButtonType). 1b) The default result type of Dialog / DialogPane is DialogButtons. This is only handled automatically for the user when they create a button from the DialogButtons enum. In all other cases (where the user passes a Button instance to the getButtons() method), it is the users responsibility to have an event handler in the button to do the necessary work (At the very least, to call setResult). In the Action approach, the Action itself is returned by default, so there is no need for the user to specify an event handler and to call setResult unless they want to do something custom. This means that creating a dialog with custom buttons is handled much more simply. 1c) To support the pre-built buttons requirement in the button type approach, the DialogPane class has a resultConverter property to convert the clicked button / the DialogButtons type into a result of type R. This API is not called in any other circumstance (i.e. when the user provides their own buttons). In the Action approach, the resultConverter is always called (the default resultConverter is just the identity method returning back the Action). This provides a good place for developers to convert from Action to R in a consistent and reliable way. 1d) There is no way to intercept the button press event and to veto the closing before the result is set, as the user has set the button event handler. In the Action approach, a private, implementation-only Button is created from the Action. The Button calls the Action.onAction event handler, and then only calls setResult(...) if the action was not consumed. This lets developers veto closing events before any result is set. 1e) Customising the buttons list is more difficult. In the Actions approach, the use could simply getActions().remove(dlg.ACTION_CANCEL). In the DialogButtons case, the obvious approach is to do the following: iterate through getButtons(), cast each item from Node to Button, find the Button with the text equal to DialogButtons.OK.getDisplayText(), store a reference to this button, break out of the iteration, and then remove the Button from the buttons list. Unfortunately, this may not be sufficient, as the display text may be internationalised. Unless we are careful, we might iterate through and not find the intended button. Again, this approach could be simplified if we added a ButtonBar.getButtonType(Node) method, but it still requires iteration compared to the Action approach. 2) One of our test dialog types is the CommandLinksDialog. This creates a Windows-specific dialog with big, wide buttons stacked vertically. In the Actions case creating this custom dialog is easy, as we simply take the list of actions, and create our custom buttons from this. In the DialogButtonType approach, we're stuck - we only have getButtons(), which is a list of Node. This means that we have lost control over the buttons before we begin, and there is no guarantee that the buttons will be able to be styled to fit into the expected Command Links style. We could of course add additional API to the CommandLinksDialog to handle this, but we are always stuck with getButtons(), and users will expect this API to work. 3) I don't know that there is any way to specify the button type on the buttons in FXML (as there is no buttonType property on Button, like there is for the actions API), so I've fallen back to just doing this in the controller. Unless we add buttonType as a property to button, I have a feeling that this is the best we can do (and I am definitely not advocating to adding buttonType to Button).
28-07-2014

Hi all, I've just done a refresh on the V5 (Actions) and V6 (ButtonType) APIs (and common underlying implementation). You can refer to the API online here: http://jonathangiles.net/javafx/dialogs/v5/ http://jonathangiles.net/javafx/dialogs/v6/ I've also attached to this jira the source code for both V5 and V6. Please have a look around and give your feedback. We're into the last two weeks of API design, after which we are set in stone. Now is the time to very carefully consider both approaches proposed, and to try to center discussions around these API. Even better would be if people took both implementations for a spin in their software, so that they can get a feel for what works and what doesn't, in real-world settings. As always, the javadoc is very primitive - with such rapid change it makes no sense to put much time and effort into the javadoc. If you have a question about something, ask in this jira and I'll do my best to respond here. Thanks!
27-07-2014

@Jurgen: Some variation of your suggestion will work, but it will come at the cost of additional classes. Personally I question whether the increased class count will lead to a better API - it might help prevent a CCE in a somewhat rare occasion, but it will almost certainly confuse new users of the API of how to proceed. One thing I will likely do is change the convertActionToResult method into a Callback property that can be set. This is more in line with JavaFX API elsewhere. It doesn't fix the problem any further however, so I'm still open to suggestions on that :-)
27-07-2014

@Jonathan Thank you very much for your comments! As for the UI designer's problems: IMO the described approach not necessarily interferes with the UI designer's job too much, At present, I use the actions to define the text, the tooltip, and the graphic. Style class and styles are left to FXML. I don't think, styling should be tied to actions, because it is only about presentation. When I use this approach in my applications, state-specific styling is left to CSS, style classes are left to FXML and CSS. The controller should not have to know anything about it. The "disabled" state is controlled via a property in the FXAbstractAction API (sorry, I didn't mention that before), and all control's disabled properties are bound to the actions disabled property. So the controller only needs to take care of enabling and disablin the action - not the controls. You are right, I cannot see the actual action text and the icon in the FXML at design time in SceneBuilder. As for the text, I saw no problem here. At design time for me it is o.k. to use dummy text ("Blindtext"), and (as far as I could observe that in projects) many ui designers would do so. Also for the action graphic, I at present would need to work with a placeholder or surrogate in SceneBuilder. IMO that is the main drawback of this approach, but it applies to all concept that try to encapsulate action logic and common action properties for the presentation (AbstractAction in Swing, other toolkits, too.) Your questions: "1) It seems to require that all controls with actions need to be field instances in the class so that they can be annotated. This seems unfortunate but unavoidable." That is right, For large UIs with many contrlos and many actions, you have to get used to what the controller code looks like. A benefit: you get a good overview of what control is bound to which action. "2) It requires runtime annotation processing. My understanding is that generally we try out best to avoid annotation processing at runtime to avoid performance concerns. Of course this isn't a concern for third party libraries, so go crazy! :-) " :-) I know, and many developers that I had the chance to discuss that idea disliked the use of annocation processing and especially *reflection*. I thought about it, too. However, it seemed arguable to me for the following reasons: - annocation processing and reflection is only needed when the UI gets initialized - as far as I see in my projects, perceived performance does not really suffer from this approach. But I understand your point - in your situation, I would say the same. "3) Are you really running the onAction event asynchronously, or are you just saying that you can run whatever code you want in there, even a separate off-gui thread?" Yes, by default the actions are executed asynchronously in Tasks spawned from the Service. It seemd to be a reasonable default behaviour because I needed this in most of my use cases - and it makes progress tracking very comfortable (using the JavaFX Task API). But this behaviour can be overridden/turned off, and my actions can also be executed synchronously. "4) What happens when multiple actions are assigned to a single control? Which action takes precedence for all of the properties, and are multiple event handlers fired?" Assigning multiple actions to one control is meant for "composition of behaviour", i.e., the actions should be executed in the order they are annotated. In general, I would use this feature very carefully, because I would need to think about sync/async. execution, text, tooltips etc. Concerning text and tooltip, up to now it seemed reasonable to have the actions overwrite each others text and tooltip info, but that might be not the only one solution one might think of. Thank you very much for your comments!
25-07-2014

Thanks Jonathan for the convertActionToResult code, I understand the problem much better now. To me it seems as though the problem is that Dialog doesn't know when it is being customized, so it is impossible to test. Could a possible solution be the following: 1. Have an AbstractDialog<R> 2. Move convertActionToResult from DialogPane to AbstractDialog<R> as: abstract R convertActionToResult( Action ); 3. Dialog<R> becomes Dialog<DialogAction> This will solve the problem of having a CCE in Dialog and force the developer who wants a custom R to implement convertActionToResult correctly.
25-07-2014

I have a few comments: 1) The Action case is nice as we have the ability to support the Action onAction event handler, and this can veto the closing as I mentioned. This functionality is not available in the ButtonType approach when the pre-built DialogButtonTypes are used - the generated Button will have the default event handler set on it, which takes care of setting the result. Users have no way to interject here, unless they get the event handler out of the button, and wrap it in their own code. We can do this in the Action case as we translate Action into a Button with its own event handler for calling the action event handler and setting the result. 2) Moving this code into the event handler of the Action seems unwise, as it is then effectively removing that API from the end-users grasp (or else, if they do use it, they break the dialog as the button will no longer set the result). It is also breaking the benefit outlined in 1). 3) It does make it more difficult for users of dialogs, in the instances where they want to provide their own actions - they must now take care of setting the result themselves. In the case where they use pre-defined dialogs then all is good (but that was also the case in the current approach too). In other words, the issue remains, it's just shifted back to the creator of the action rather than the creator of the dialog. I would venture to say that more people are likely to create custom actions, and will just expect these actions back as the result, than people creating subclasses of Dialog<R> where R is not Action. In other words, my gut feeling is that making this change is likely to be burdensome for the common case.
25-07-2014

@Jonathan Ok, so what happens if 4b), 4c) and 5) are placed in the event handler inside the action -- i.e setting the result, consuming events and closing the window is all left up the event handler of the action (or the event handler sets a property of the dialog that says close me, and the dialog has a listener on it). It makes it more complicated for Dialog implementers, but not for users of Dialogs, as long as the different sub-dialog classes have specific actions. So for example class TextInputDialog has an ACTION_OK that has an event handler that grabs the text and sets the result to that text.
25-07-2014

Graham - good question - I've updated my previous comment to clarify how the action event handler is taken into consideration.
25-07-2014

Graham, you're correct, the TextInputDialog has pre-built actions. It can do this exactly because of the fact that there is the convertActionToResult method - when either (or any) action is clicked, the convertActionToResult method takes the action, and determines the appropriate result (in this case, if it is OK, the TextField.text, otherwise null). The general flow of events is this: 1) A dialog is constructed from a series of Actions (or DialogButtonTypes) 2) Internally, we convert these actions / button types to Buttons. The event handler of the button is specified to setResult(...) 3) A button is clicked by the user. 4) The event handler of the button is entered. 4a) At this stage we know what button / action has been clicked (we're in its event handler!), but we don't know what the result should be. 4b) Firstly, we call the event handler on the action, if it is not null. If the action event handler is consumed (i.e. the user supplied an event handler in Action that calls event.consume()) we stop at this point. We do not set the result and we therefore do not close the dialog. The user has essentially vetoed the closing action, and has told us that they will take care of setting the result (if that is indeed necessary - perhaps they want to open a subdialog or do something else). 4c) If the action event was either null or not consumed, we then call setResult(convertActionToResult(action). This allows the code to convert ACTION_OK to textField.text, and anything else to null. The default implementation is simply the identity method, returning the action straight back. 5) This result is then set in the result property, and the dialog closes as expected. I'll add that Eugene and I are exploring another approach, which is a slight twist on this approach. I'll post about this if we manage to get something that works well.
25-07-2014

@Jonathan: There is an event handler inside the Action (you can set it via setOnAction). Where in the chain above is this called? And what are you expecting it to do?
25-07-2014

@Jonathan You wrote that "The problem is that Action (and Button in the ButtonType approach) cannot know how to set the result when using the pre-built buttons, so you will always need to override the event handler if you aren't using the default buttons and the return type isn't Action (or DialogButtonType)." The TextInputDialog is using a pre-built action correct? What exactly does the pre-built action it uses do?
25-07-2014

To be clear, you as a user of TextInputDialog (or ChoiceDialog) never needs to be concerned with the convertActionToResult method, because this method has been implemented already. The only time you might be interested (in the case of TextInputDialog) is if you want to modify the behavior (where currently it returns the value if OK is clicked, and null if any other button is clicked). Other than this, the only time you would override convertActionToResult is when you are creating a subclass of Dialog that has a type other than Action (i.e. Dialog<String> or Dialog<Font>), and of course this would need to be documented very well (in a series of steps) so that people developing custom dialogs know what they need to do.
25-07-2014

@Graham: The person writing the converter from Action to R is the person creating the dialog implementation, and this may or may not be the same people who are actually using the dialog. Your proposal is to burden everyone so that this relatively infrequent use case never gets encountered. To demonstrate, the current approach works well in the following cases: * The very simple case of using the pre-defined actions in an alert dialog * The case of pre-defined actions in a normal dialog (where the Dialog is typed as Dialog<Action>) * The case of users who are consuming a TextInputDialog without specifying the implementation. The current approach requires more work from the developer of a dialog implementation _if_ the return type of the Dialog is not an Action, to convert the Action to a result value. At present, exactly the same issue exists in the ButtonType approach, to convert from the clicked button to the result type. One way around this is to 1) not offer pre-defined types (either action or button type) and 2) require all users to set event handlers for all buttons in the dialog to set the result to the applicable value. The bulk of the time this is simply setting the Action / Button into the result property, but in some instances they will need to write code that reaches into the dialog, possibly cast it to a specific type (i.e. TextInputDialog), retrieve the relevant information from the dialog (e.g. the TextField text), and then set that into the result. This places a huge amount more burden onto all users of dialogs in my opinion, where it can be hidden almost entirely with the current approach. I can appreciate that this approach might not seem obvious, and I am really keen to hear alternatives, but I do not want to swing too far in the opposite direction and force people to do more work in defining their dialogs. Ideally I would like to avoid people having to specify event handlers on their actions/buttons.
25-07-2014

@Jonathan >I think what you are actually proposing is that the event handler code should not call setResult(convertActionToResult(action)). This would >be unfortunate as it would force more work on all end-users of the dialogs API. I guess that is what I am suggesting. Instead of someone writing a convertAction() method that is called from some generic event handler, simply let users specify (type) specific event handlers. You avoid the casting issues. The whole approach sort of seems backwards to me -- the V5 API is designed to work one way (to make simple cases easy), but then we have to have a kind of hack to make it work more for more general cases. The hack says to me that the the API is over-specified in the name of "simplicity".
24-07-2014

@Jurgen: Regarding Node as the owner - seems like an interesting idea that is future-proof for lightweight and heavyweight windows. I might make that change (the alternative is to have two initOwner(...) methods, one for Window, and one for Node). I don't agree about setting owner in show / showAndWait - this suggests to the user that this can be changed every time these methods are called, which is not permitted. It also clutters the API in a way I don't think is very user friendly. You wanted to see what the convertActionToResult code looks like, here it is: /** * Converts the user-selected action to the result. This method is a placeholder! */ protected R convertActionToResult(Action action) { // FIXME ideally we'd give users feedback when this fails.... // Ideally we would test here to ensure that R is action, but type erasure // pretty much ruins that idea. return (R) action; }
24-07-2014

@Robert: Actions are only being discussed in relation to dialogs as this is the first time a new API has been specified that could use actions, and it is a one-off chance to build a dialogs API with actions built in. Ideally we would discuss these two concepts separately, preferably with actions having been implemented and integrated in a separate (and earlier) release. The use of Actions in FXML does not suggest that the logic is being included in the FXML - the logic continues to be contained within the controller, as the onAction event handler is still implemented there. I had a look over your proposal, and the I like how you are able to create Button, MenuItem, etc from an action directly in FXML by specifying the fx:id and then having your implementation link the action to the control. This is a nice feature on one hand, but on the other it kind of makes FXML seem a bit more magic, as the text, graphic, style class, style, disabled state, etc are all hidden in the controller code inside the action (where FXML and Scene Builder cannot access them). This makes the UI designers job almost impossible, as they won't see anything of value beside unlabeled buttons, menus, etc inside Scene Builder / FXML. Stepping back, in general I wonder how useful actions would be in an FXML / Scene Builder world. It seems to me that actions are more beneficial to people either inside the controller, or in applications that don't use FXML. In other words, they are more useful when interacted with via Java, rather than FXML. However, defining DialogActions as shown in the FXML I posted earlier seems to work fine, for the purposes of defining the content of a Dialog. In terms of your suggested approach, I have a few questions / comments: 1) It seems to require that all controls with actions need to be field instances in the class so that they can be annotated. This seems unfortunate but unavoidable. 2) It requires runtime annotation processing. My understanding is that generally we try out best to avoid annotation processing at runtime to avoid performance concerns. Of course this isn't a concern for third party libraries, so go crazy! :-) 3) Are you really running the onAction event asynchronously, or are you just saying that you can run whatever code you want in there, even a separate off-gui thread? 4) What happens when multiple actions are assigned to a single control? Which action takes precedence for all of the properties, and are multiple event handlers fired?
24-07-2014

Hi all, just my thoughts on actions: 1) Following the discussion here, I wonder why the action topic is so strongly tied to the dialog topic. IMO, it's just as Jonathan said: "Firstly, an action is just the command pattern ..." - actions let us separate and encapsulate logic away from the view, so that it is easily reusable. So, it concerns everything what we do with JavaFX. The RAD approach with SceneBuilder is really great, but we (addidionally) urgently need something like actions to create maintainable applications. 2) I wonder, whether actions really have a place in FXML. In my understanding, FXML is about the structure of the UI - not presentation in the sense of styling (that is CSS), and not logic and behaviour (that is the controller). Also, up to now I very much like to code in a way where everything concerning behaviour is *not* part if my FXML - in order to keep my FXML UIs more versatile and reusable, separated from everything belonging to behaviour and logic. Well, exactly this leads to the same propblems mentioned above: behaviour, logic - and all the wiring - go into the controller, having us writing lots of glue code. Ugly. That lead me to a somehow different approach. Goals were: a) Keep behaviour and logic (and the binding of controls to behaviour/logic) out of FXML b) Get rid of glue code like imeratively creating and/or assigning event handlers c) Rather bind behaviour and logic to controls in a declarive manner I currently work on and with a little "framework" that (roughly described) works like this: The FXML UI: Most important - and the only important thing for action binding - are the fx:IDs. <?xml version="1.0" encoding="UTF-8"?> <?import... ?> <AnchorPane fx:controller="FXMLDocumentController"> <children> <MenuBar> <menus> <Menu mnemonicParsing="false" text="Test"> <items> <MenuItem fx:id="miAction" /> </items> </Menu> </menus> </MenuBar> <Button fx:id="button" /> <Label fx:id="label" /> <Button fx:id="meTooButton" /> </children> ... </AnchorPane> The controller: Binding actions to the controls takes place in the controller - declaratively. No imperative code, no event handlers. public class FXMLDocumentController implements Initializable { // Wiring controls to logic is done solely with annotations - for Button, MenuItem, Label etc. alike: @FXML @FXAction(action = MyAction.class) private Label label; @FXML @FXAction(action = MyAction.class) private MenuItem miAction; @FXML @FXAction(action = MyAction.class) private Button button; // Details of the binding may be defined individually, e.g. whether to use the action's caption or icon for this control or not @FXML @FXAction(action = MyAction.class, doShowText = false, doShowGraphic = true) private Button button1; @FXML @FXAction(action = MySecondAction.class) private Button meTooButton; // Also, multiple binding are possible, in order to compose the behaviour of a control with several actions @FXML @FXAction(action = MyAction.class) @FXAction(action = MySecondAction.class) private Button doubleActionButton; ... } The action classes look like this: public class MyAction extends FXAbstractAction{ // Define public MyAction() { this.setText("The first action ..."); this.setTooltip(new Tooltip("Click here to invoke the first action")); this.setImage(new Image("my/icon.png")); } // The simple approach: just implement the onAction method @Override public void onAction(Event event){ // do something - asynchronously! } } Important for the actions and the base class: FXAbstractAction extends Service, and the onAction method actually is executed asynchronously in a Task. IMO, asynchronous execution is not an essential of actions, but in most of the situations, we do not want the logic to interfere with the user experience, i.e., we need to place time-consuming logic into separate threads. So, it would be very nice if an abstract action base class automatically takes care of this. (Maybe this should not be always so, but at least optionally, And if: also progress tracking would matter ...). The actual wiring is done in a controller factory (which is also the annotations processor) when the FXML gets loaded: ... // The controller factory: myActionControllerFactory = new FXActionManager(); FXMLLoader fxmlLoader = new FXMLLoader(); fxmlLoader.setLocation(getClass().getResource("FXMLDocument.fxml")); fxmlLoader.setControllerFactory(myActionControllerFactory); Parent root = (Parent) fxmlLoader.load(); So far for the main ideas of this approach. It has some rough edges, but for me it works quite well. I do not know whether I want to see something like the "controller factory as annotations processor" in JavaFX in the future, but the binding of actions to controls outside of the FXML only by annoations up tp now feels very good. It reduces my code very much, eliminates glue code almost totally. Finally, back to the actual discussion, my main point is: maybe it would make things a little bit easier, if the action topic is not bound to FXML at all (or, at least, much less). This would provide us with an even better separation of UI and logic. And a declarative approach could reduce the necessary amount of code very much, eliminating all imperative wiring. What are your thoughts about this? P.S.: I am about to make the framework available on github within the next days.
24-07-2014

@Jonathan With regards to convertActionToResult you said that "One problem with this approach is that the default implementation does an unchecked cast to R", could you please show that.
24-07-2014

@Jonathan Thanks, I was merely suggesting Node in terms of the future possibility of there maybe one day being lightweights, since Window can be extracted from Node. Don't you think that setting owner with showAndWait and show is more intuitive than having to remember/know that it must be done with initOwner ? In terms of Stage's owner not being allowed to change, if the Stage is created late as part of show... then it cannot be changed.
24-07-2014

@Jonathan I notice that both DialogPane and Dialog have a field for result. Is there a particular reason for this ? What if result is removed from DialogPane and is instead typed for method convertActionToResult(action) ? public class DialogPane<C> { public C convertActionToResult( Action act ) }
24-07-2014

@Jurgen: Changing the owner of a Stage after it is shown is not allowed, so for the same reason I won't be supporting this in dialogs (heavyweight or lightweight). It doesn't seem like too much of a burden to recreate a dialog in the (rare) instance where the owner changes. Lightweight dialogs will not be part of the initial release of dialogs, for the reason I mentioned earlier - there is no proper way to have lightweight dialogs implemented which is not hacky and bad. What is needed is proper glasspane support, and proper semantics around glasspane - can you have more than one glasspane? If yes, how do you deal with multiple dialogs? etc, etc. As I said in my earlier response to you - presently the API for owner is Window, as this works with what is expected in the heavyweight implementation, but this API will need to be revisited before we finalise so as to not prevent future support for lightweight dialogs. The reason why it used to be Object (e.g. in ControlsFX and earlier API versions) was because there is no common ancestor between Node (for lightweight) and Window (for heavyweight), so Object is the best I can do. Frankly it doesn't bother me much to have the owner be Object - it would be nice for the API to be more restrictive - but it isn't hard to throw exceptions when the developer uses the wrong object, and presuming that they do any modicum of testing, it will be picked up on very quickly in development.
24-07-2014

Also I've had a rethink with regards to owner and believe that not having it in the constructor is a good thing for two reasons: 1. When defining a Dialog through FXML you're going to have to specify an owner separately in any case, after you've loaded the FXML file. 2. If the owner is set in the constructor then the Dialog cannot be reused on another owner. (This is also a problem with initOwner). What is the feasibility of providing the owner with showAndWait( owner ) and show( consumer, owner ) so as to be able to reuse a (lightweight) Dialog multiple times on different Nodes. Also shouldn't owner be of type Node so that lightweight Dialogs can be accommodated on a specific Node ?
24-07-2014

@Jurgen: This is because DialogPane does not know about Dialog, as it is not always true that a DialogPane is within a Dialog. Because of this, both Dialog and DialogPane have the result property, with Dialog simply forwarding the DialogPane result property. Additionally, Dialog observes the result property so that it knows when it has been set, and therefore when to close the dialog (assuming the conditions are such that it should).
24-07-2014

@Graham: In fact, it is possible to specify Action without an event handler. The default result of this is that the action closes the dialog and is set as the result on the Dialog / DialogPane (which may be converted to a result of R as per the current API). This seems reasonable as for many users of dialogs they just want to put in a series of buttons, and then be told which button is pressed (in fact, I would say that this is the main use case). The current approach makes this very easy. I think what you are actually proposing is that the event handler code should not call setResult(convertActionToResult(action)). This would be unfortunate as it would force more work on all end-users of the dialogs API.
24-07-2014

@Jonathan: Ok, I see. So then I have a question. What happens if you don't provide the pre-built actions (I am not saying this is a good idea, just exploring the design space). You leave action specification/provision up the user. Then the problem goes away right?
24-07-2014

@Graham: The problem is that Action (and Button in the ButtonType approach) cannot know how to set the result when using the pre-built buttons, so you will always need to override the event handler if you aren't using the default buttons and the return type isn't Action (or DialogButtonType). This is entirely non-obvious to end users. On the other hand, using the approach I outlined above (convertActionToResult), the end developer (i.e. the one using the dialog) never needs to know about the conversion - it is up to the developer of the dialog to map the pressed button to the result. It generally comes down to who is responsible - the dialog developer or the specifier of the buttons in the dialog?
24-07-2014

@Jonathan Ok, so I was thinking that the action sets the result. No conversion needed. The two choices are that user either writes a converter or has to write an event handler, so either way they have to write a code snippet. The event handler approach is clean -- no casts. If the user actually wants the action as the result then just write the "identity" event handler. Standard dialogs could do that for you. Ah, I didn't realize that OK_ACTION was a field inside Dialog. Clever, if weird :-)
24-07-2014

Graham, no, as shown in the V5 docs it is non-static for exactly the reason you state. We don't want people mucking with static actions and breaking dialogs throughout their application! :-)
24-07-2014

@Jonathan Isn't ACTION_OK some kind of static variable. So if I call setOnAction and use it for one dialog, then the NEXT time I use ACTION_OK with another dialog I won't have the standard behavior, I will have the changed behavior from the first dialog. If that next time is in some library I call ...
24-07-2014

Graham, the result of Dialog (and DialogPane) are both R, which means that it may be an Action, or it may be something more useful to developers, such as the previously mentioned Optional<String> for text input dialogs. The issue is that we have actions (or buttons), and these are not the result that we want to return to the user in certain cases. If we want the action / button to directly set the result (to prevent the conversion), then users would have to implement the event handler for each button to setResult with the expected end result. In essence, you either handle it in each button, or you handle it in a step after the button is clicked (which is the current approach in my implementation). I don't quite follow you on your "Or alternately the action should set some result type property when it is invoked" statement. Could you please clarify? Regarding your request for an example of ACTION_OK by with a different action, that is simple (again, excuse jira coding, I might have subtle typos): Dialog dlg = ....; dlg.ACTION_OK.setOnAction(e -> { System.out.println("new handler!"); // if you don't want to hide the dialog when the button is pressed, do the following: e.consume(); }); The thing to note is that realistically, this is pretty much the same as defining a new action - it'll definitely look the same as the ok action, so the only difference by modifying ACTION_OK is that you get pre-loaded with the default internationalised text and closing behaviors.
24-07-2014

@Jonathan I am confused. Doesn't this example tell you that the result of a dialog should not be an action or a button type? The result type should be specified by the user and no conversion should be necessary. Or alternately the action should set some result type property when it is invoked. On this topic can you show how one defines an action that looks just like ACTION_OK (so same text, long text, etc), but does something different when it invoked.
24-07-2014

Folks, there is a piece of advice I'm keen to seek from you all. It relates to the situation where a Dialog / DialogPane is used to show a dialog whose return type is not Action (or DialogButtonType - the issue exists for both approaches). For example, a TextInputDialog or ChoiceDialog (where the return type is Optional<String> or Optional<T>). In the case of TextInputDialog, the creator of this dialog (i.e. me in this case, but end-developers in general) has to create a Dialog<Optional<String>> that makes use of a non-discussed piece of the DialogPane. Firstly, here is what the developer has to do in the constructor: public TextInputDialog() { // ....miscellaneous initialisation code.... setDialogPane(new DialogPane<Optional<String>>() { @Override public Optional<String> convertActionToResult(Action action) { return Optional.ofNullable(action == ACTION_OK ? textField.getText() : null); } }); } What you see here is code that tells the DialogPane how to convert the button press into a result that can be returned to the user. This is required because DialogPane has a series of buttons, and when one of these is clicked needs to know what to return up the chain to the Dialog. By default the convertActionToResult method simply returns the Action back again, as this is what is the returned in most instances. What the code above is doing is checking that the user clicked OK, and if so, gets the text out of the textfield and returns it up the chain (the code that calls convertActionToResult is literally setResult(convertActionToResult(action))). I'm keen to hear what people think. One problem with this approach is that the default implementation does an unchecked cast to R (where R is the result type). Unless I ask people in the API to provide a Class<R>, I can not type check, and so the CCE that results is relatively confusing (because it isn't clear what the user needs to do to resolve it). One option is to of course write lots of javadoc. Another option is to replace the convertActionToResult method with a callback property, but this is largely just reshuffling the deck chairs on the Titanic. What I'm wondering is how people feel about this approach in general, and if they have alternate suggestions. The main goal is API simplicity, practicality, and consistency, as always. Thanks!
24-07-2014

@Scott: Regarding DialogController - conceptually it seems like a good idea, but in practice I am not familiar enough with FXML to argue for or against it. I hope someone more knowledgeable (including yourself) could help flesh out this idea further. @Jurgen: To be consistent with Stage, I have introduce initOwner(Window), and taken owner out of the constructor. This may change, depending on how big of an outrage this is to people. The reason why the owner was Object was because in the lightweight dialogs case it is possible for the owner to be any Object, but most commonly a node in the scenegraph. For the V5 refresh I just pushed, this has changed from Object to Window, but this may not stay like this either, as this prevents the introduction of lightweight dialogs in a future release. @Steven: Thanks for your use cases for specifying the position of the dialog. I will look into API for supporting this.
24-07-2014

Hi folks. I've just refreshed the V5 javadoc at [1]. The changes are relatively minor, but I think resolve some of the concerns people have: 1) I've added contentText and headerText properties to DialogPane (with forwarding API from Dialog). These are lower precedence than the header / content properties, but this plays more nicely with FXML, and also makes custom dialogs a lot simpler to write (e.g. TextInputDialog was a bit of a mess before this change). 2) I've added back a graphicFactory API to Action, although it is simpler than what was in V3 (but just as functional, I think). I've left the graphic property as being an Image. This means that (in my estimation) 90% of users will be happy without having to touch graphicFactory (and will also avoid the issue where their nodes disappear when they have the action on multiple controls). For those of you with more advanced use cases, the graphics factory works well, and takes precedence over the graphic property. 3) I've tweaked some of the constructors to reduce the overall number of constructors in some classes (particularly in Alert, Dialog and DialogPane). These will be tweaked again, I can assure you, so your feedback is very welcome. 4) I've removed some of the pre-built dialogs, namely ExceptionDialog, CommandLinksDialog, and FontSelectorDialog. These dialogs will almost certainly not be accepted as part of JavaFX, but they can continue to live on (and be refined) in ControlsFX. I'm still pushing to include TextInputDialog and ChoiceDialog, but they too might find themselves on the chopping block. I wrote some sample code today to test styling controls generated from actions, and it works well (primarily for the hover use case discussed previously). Similarly, I wrote code to test the graphic factory, and it works well too. [1] http://jonathangiles.net/javafx/dialogs/v5
24-07-2014

@Jonathan Giles: Back to your question about the positioning of dialogs, as to whether or not there are use cases for other than centered: I would say emphatically yes! As an old Swing developer, I almost always positioned my dialog NOT in the center. I recall clearly two use cases: a.) When I detected that I was running on the Mac, and wanted a centered modal dialog, I mimiced the behavior of horizontally positioning the dialog but the vertical position was just under the title bar of the JFrame and there was no border to the dialog. It made it look native. (I think the native look requirement is overrated -- not even Apple is consistent, but one gets creamed in reviews if it is not well supported. We don't want JavaFX to suffer the same negative reviews as Swing did back in the day because of that issue!) b.) But even more than that, working on control systems with big screens, or with many screens, it was imperative to have the dialog very close to where one clicked, minimizing the mouse movement required to traverse to it. There was no arguing with the users on this point: they were quite insistent. As a minimum, I think one needs a centering default, as well as an additional API for x-y placement, and it would be up to the developer to do the math to figure out where he or she thinks it belongs. Nice to have would be an offset API from the underlying node. I hope I have made some semblance of sense.
23-07-2014

+1 for Optional. It's a core thing in the JDK now and we shouldn't lag behind just because we're client developers.
23-07-2014

+1 for Optional, I agree with Fabrice and Eugene. It will also expose programmers to the concept in a natural way and remind us to try and use it.
23-07-2014

@Jonathan with regards to setting the owner of a Dialog (or one of its subclasses) I would prefer that it be provided through the constructor, like in your Alert API, as an initOwner method for me is not intuitive. Is there a particular reason why owner is of type Object in the Dialog and Alert constructors ?
23-07-2014

@Jonathan I think #4 is too much magic as well. The discussion about FXML led me to another idea. What about the concept of a DialogController? There would be a standard one that covered the common cases but you could supply a customized one (even simply as a reference in your FXML) by sub classing the default implementation. Perhaps that could be used to handle many of the issues with customizing the dialog, including things like replacing the Node factory for dialog graphics to handle non-Image graphics, dealing with return values from nonstandard Actions, validating input prior to dismissing the dialog, handling return values from non-modal dialogs, custom ButtonBars, wizard-style dialogs, etc. Would some sort of interface for a DialogController be helpful?
23-07-2014

Hi all, there have been a few requests for more details on actions, so I thought I'd do a quick and hopefully short post summarising the details as I see them, and one way we could integrate them into JavaFX in a rather lightweight way. Firstly, an action is just the command pattern - it contains an event handler that is fired when necessary, and contains a few useful properties that allow for it to configure zero or more controls. These properties include elements such as text, graphic, long text (i.e. tooltip), style, style class, etc. In a past life, I used actions in Swing a lot. I would have a package specifically dedicated to them, with names such as ExitAction, PrintAction, etc. Then I had my own code that would bring in an instance of the action and set it in my UI. This was great - consistent graphics (big and small, great for toolbar (big) and menu items (small)), text, accelerator, and centralised event handling code. When I had to fix a bug in one of my actions, I knew where to find it (and didn't have to dig through UI code finding the relevant code). Even in cases where I didn't use the action in more than one place, I got into the habit of always creating my JButtons (or J-whatevers) by first creating an AbstractAction instance, and then passing that to my UI component. This meant it was always easy to extract actions out later on, and meant all my code was consistent. In the case of JavaFX, I can see much the same. Of course, the API will be a little different, but at a high level the concept is the same. My back-of-a-napkin thinking right now on how to integrate Action into JavaFX is as follows: 1) Bring in the Action class, with tweaks and examples of how to support multiple images (big and small), handling changes in state (hover), etc. Bring in DialogAction for the dialog case. 2) Identify all the relevant UI controls that could benefit from this. My current list consists of the following: Button (and related classes Hyperlink, ToggleButton, RadioButton, and CheckBox), and MenuItem. 3) Create a new constructor in each of these cases that takes an Action as the argument. 4) Add special-case handling code in the setOnAction(EventHandler<ActionEvent>) method that each of these classes has, such that if the EventHandler<ActionEvent> is an Action (because Action implements EventHandler<ActionEvent>), we can set up bindings for all other properties (text, graphic, accelerator, etc). Step four is either genius or stupidity, I can't quite work out which. It means less new API is needed, but I wonder whether we're doing too much magic inside setOnAction (I tend to feel that we are). If setOnAction shouldn't be modified, then step four might change to adding a new setAction(Action) setter (along with the appropriate getter and property method). As always, what are your thoughts?
23-07-2014

+1 for Optional. Since the new Dialog API is for JavaFX 8 and forward, I don't see a reason not to use new Java 8 APIs. It also makes a lot of sense from the logic point of view: the dialog result returned IS optional. There is also universal agreement that usage of null is bad and should be minimized as much as possible.
23-07-2014

@Ryan: The argument against Optional is just that we haven't yet used Optional in JavaFX, so we must make a concerted decision to either use it or not. I have to add though that this kind of argumentation against (or for) Optional (and the same applies for Action vs ButtonType) is totally normal and natural in discussing APIs, and doesn't reflect a total rejection or acceptance of anything - API design is all about challenging the designer of the API to prove the need for a certain API, and so Optional falls into that boat - and one way I can prove (or disprove) the value of Optional is to have people in this jira to give their thoughts on the issue. So far I'm hearing total acceptance of Optional in jira, but I'm keen to hear as many opinions as possible.
23-07-2014

+1 for Optional. Are you able to share the argument against it? For the node / image swapping, I did mean on the button. The progress indicator was a bad example since, as you say, it makes more sense to switch the dialog's graphic to a progress indicator. My main concern is being able to make sure the button / action graphics scale correctly on high DPI displays. Since there doesn't seem to be a recommended way of scaling icons yet, I figured an arbitrary Node is going to be much more flexible than an Image. It's not something I'll be dealing with in the short term, but high DPI displays are becoming unavoidable.
23-07-2014

At present there is no API to specify where the dialog should go - it is either centered on screen or centered relative to its owner. I'd be interested in knowing whether there exists use cases for wanting the dialog to appear elsewhere.
23-07-2014

@Jonathan. What I am trying to get at is whether it is possible to have a dialog be modal on the owner, but not centered on the owner?
23-07-2014

@Graham: In ControlsFX (and in the dialogs implementation underpinning the API drops I keep doing), a dialog is window modal on the owner, if it is non-null, and application modal if the owner is null. JavaFX has a javafx.stage.Modality enum that we use internally, and in fact this is likely to be exposed in the final API (currently setModality, but in reality initModality is the better and more consistent name for it).
23-07-2014

@Derek: It is important that any JavaFX API (related to visuals, anyway) be accessible and configurable via FXML, and dialogs should be no exception. However, as I pointed out yesterday, my sample FXML code seems somewhat redundant and I am really keen to hear how FXML experts would use dialogs in FXML. You can configure a DialogPane instead of a Dialog, and then later reference that in a controller (or elsewhere in FXML), but I'm not sure personally the important use cases, so all I can really do is ensure that the code appears to work in FXML. In any case, supporting FXML has had no major impact on the API. The extent of the API changes I had to make to support the Action approach is to change the Action eventHandler property to be called onAction. It seems likely that FXML has special case support for the 'setOnXXX' naming convention, so setEventHandler wasn't working. That's it - not a great deal more complexity at all! Regarding actions precluding blocking dialogs: no, it doesn't - the V5 API (the most recent Action-based API) has show() and showAndWait() API, where the showAndWait() API results in a blocking call to the dialog. The show() API takes a Consumer argument, which is called when the dialog is closed, and this allows for the dialog to be non-blocking. Optionals are indeed used in the API, but this has nothing to do with blocking / non-blocking dialogs, it is simply a way to represent that the dialog might sometimes return null (e.g. when the user cancels a ChoiceDialog), and rather than introduce a source for NPEs, Optionals allow for a more lambda-based approach that avoids the possibility of a NPE.
23-07-2014

+ for Optional.
23-07-2014

In ControlsFX specifying an owner for a dialog centers the dialog over that owner. If the dialog is modal which node does ControlsFX block? The owner?
23-07-2014

@Ryan: I'll work on summarising the intended outcome of introducing Actions. You reminded me of my earlier point about internationalised text - I had forgotten - but that is a very good point against the button type approach in my opinion. Users have to be very careful about how to retrieve their buttons (especially so with those generated from the pre-defined DialogButtonType enumeration, as the user never specifies the button text in this case, and it may well be internationalised). Even I fell into that exact issue in my sample code, which suggests it's going to trap a lot of other people who ship their software internationally (remembering that JavaFX ships with translations to a small number of languages). Regarding your last point of swapping a node for an image (and vice versa): I think I need to clarify that the issue we're discussing relates to node / image in Action, whereas it sounds like your use case is swapping node / image in the Dialog. This use case remains totally feasible today. The use case that people have pointed out that isn't feasible is in the case where an Action has an Image as its graphic property, and the action is used to create a button, and they want to either alternate the image when the button state changes (hover, etc), or that they want to use a non-Image graphic, for example a glyph or any arbitrarily complex scenegraph.
22-07-2014

+1 for Optional - now that it has been introduced in JDK8 and there will be no backport of dialogs to JDK7, there is no good reason not to use it in any upcoming API (unless it's not meant to be included in lighter JDK profiles of course).
22-07-2014

@Jurgen: Your code sample seems correct, although I haven't compiled it to check. The setOwner question is interesting, and something I plan to explore in the next few days. The answer is that Stage takes an owner via an initOwner method. This is because the owner cannot be changed dynamically (which makes sense), and it is likely I will try to introduce the same API and concept into Dialogs. I might also do the same with modality. Your code could be made a little more succinct with the Optional, by doing something like the following (excuse the jira coding, I've not run this past my IDE for approval): langDialog.showAndWait().ifPresent(newLanguage -> { currentLanguage = newLanguage ; isNewLanguage = true; }; This is only possible because we use Optional, and I should note that I have received some resistance internally to using Optional in this API. It would be great if people could register their votes (+1, -1) towards Optional being used in Dialogs, otherwise the likelihood of it being included is minimal.
22-07-2014

@Jonathan - re: Dialogs & FXML... I am a little confused on why you would want/need a Dialog in FXML? To me, a Dialog is a standard way of presenting: 1) A choice to the user 2) Information to the user 3) Error to the user 4) Waiting/Progress indicator to the user In a standard way. I would prefer a simple/straightforward API that focus on that, rather than FXML support - I wonder how often one would code Dialogs in a way that would require the complexity of FXML and loading it. I do have a question on Actions - would that preclude the notion of a blocking call to the dialog? i.e. foo = dialog.show(); if (foo.equals("xxxx")) { //some processing? } meaning dialogs always end up in callbacks? Or would we be looking at optionals as noted by @Jurgen? Personally I think we have FXML support for complicated dialogs already - they are called Windows :) - I don't see how needing to support that in a dialog API makes sense, seems to require too much effort for something that could be easily handled when needed by building and styling your own based on the look and feel of the Dialog API if needed.... Maybe I am missing something?
22-07-2014

Right now, I'd say I prefer the Action approach, but I wouldn't mind a more comprehensive explanation of the pros, cons, and intended use of Actions. bq. iterate through getButtons(), cast each item from Node to Button, find the Button with the text equal to DialogButtonType.OK.getDisplayText(), store a reference to this button, break out of the iteration, and then remove the Button from the buttons list Is there a reason an Iterator can't be used to make that a bit simpler? Someone touched on something similar a while back, but how do you make that comparison against internationalized text? I'm a bit fuzzy on how the display text is set for a custom button type, so I might have overlooked something obvious. I don't think the choice between returning a CompletionStage vs passing a Consumer is a big deal. It's trivial to use static utility methods to get the opposite behavior. The Consumer approach is simpler to understand and less prone to abuse. I think the node vs image thing for a graphic deserves a bit of extra attention. I can think of a few cases where swapping the graphic for a progress indicator could be useful. Does the use of a node vs an image have any impact on the strategies that can be used for scaling on high DPI displays?
22-07-2014

@Jonathan Ok, thanks. I'm going through my project to see where I'm using Dialogs and thought I'd try and use the API on them. Here's a choice dialog as an example: ChoiceDialog<Language> langDialog; langDialog = new ChoiceDialog<>( currentLanguage, db.getLanguages() ); langDialog.setTitle("Clinical Language Choice"); langDialog.setHeaderText("Please select a Language"); langDialog.setContentText("Clinical Language Options:"); langDialog.setOwner( (Stage) getView().getScene().getWindow() ); // missing in API ? Optional<Language> languageChosen = langDialog.showAndWait(); if ( languageChosen.isPresent() ) { currentLanguage = languageChosen.get(); isNewLanguage = true; } I have two questions: 1. Do you have to set an owner ? 2. Have I used the showAndWait() result correctly ?
22-07-2014

@Jurgen: yes, by default, but in this case I annotated the Dialog and DialogPane classes with @DefaultProperty("actions") (or buttons), to remove the need for the extra layer of indentation.
22-07-2014

@Jonathan Shouldn't the <DialogAction text=.... lines be wrapped in an <actions> section ? And likewise with <Button fx:id=.... they should be wrapped in a <buttons> section / group I think ?
22-07-2014

Just to show what the FXML looks like if I create contentText and headerText properties in DialogPane (with forwarding API in Dialog), here is the action example again (and of course, the same applies to the button type example). Much more succinct for the common use case (I've even set the title text, which was always possible just not demonstrated): <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.action.*?> <?import javafx.scene.control.dialog.*?> <Dialog contentText="Hello World!" headerText="Header text!" title="Title text!" fx:controller="samples.fxml.DialogOne" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> <DialogAction text="Yay" buttonType="YES" onAction="#yayEventHandler" /> <DialogAction text="Noooo!" buttonType="NO" onAction="#nooooEventHandler" /> <DialogAction text="Help me" buttonType="HELP_2" onAction="#helpEventHandler" /> </Dialog>
22-07-2014

I've done a little more investigation into dialogs (with actions) and FXML. It took me a few hours to work out some kinks in the actions / dialogs API related to named arguments and default properties, but finally, here is some sample FXML that defines a dialog: <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.action.*?> <?import javafx.scene.control.dialog.*?> <Dialog fx:controller="samples.fxml.DialogOne" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> <!-- ideally we would support contentText in some fashion, but at present it doesn't work as it is not a property --> <content> <Label text="Hello world!" /> </content> <!-- same here, we would rather set headerText --> <header> <Label text="Header text" /> </header> <DialogAction text="Yay" buttonType="YES" onAction="#yayEventHandler" /> <DialogAction text="Noooo!" buttonType="NO" onAction="#nooooEventHandler" /> <DialogAction text="Help me" buttonType="HELP_2" onAction="#helpEventHandler" /> </Dialog> I would really like to know if there is a way to have the contentText and headerText setters accessible, so that rather than users having to set the content and header as above, they can just do '<Dialog contentText="..." headerText="...">'. Does anyone know if there is a way to support this? The alternative approach is to make contentText and headerText full-blown properties, which should still work fine (it'll just be a matter of documenting precedence, where *Text probably takes precedence over content/header nodes). If no one has a smart idea, I'll probably just take the full-blown property approach for now. In the controller code, I've simply done the following: package samples.fxml; import java.io.IOException; import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.control.action.Action; import javafx.scene.control.dialog.Dialog; import javafx.stage.Stage; public class DialogOne extends Application { public static void main(String[] args) { launch(args); } @Override public void start(Stage primaryStage) throws Exception { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("dialogOne.fxml")); Dialog<Action> dialog = fxmlLoader.load(); show(); } public void show() { Action result = dialog.showAndWait(); System.out.println("Result is " + result); } public void yayEventHandler() { System.out.println("YAY"); } public void nooooEventHandler() { System.out.println("Nooo!"); } public void helpEventHandler() { System.out.println("It's ok to ask for help!"); } } The result is a dialog with three buttons (two on the right, one aligned to the left), each with their own event handling code in the controller. The dialog works as you would otherwise expect. The thing is, I am almost entirely unfamiliar with FXML, and I never use it, so for one I've probably done dumb, non-standard stuff above, but for two, I need people to tell me how they would use dialogs in FXML. The example above uses the Dialog API, but there is also the high-level Alert API. I'd be really interested to hear, at the pseudocode level, how you would actually use the dialogs / alerts API to show and configure dialogs, as it would inform me as to what I need to make sure works. Thanks!
22-07-2014

Here's the same example for the button type approach. Note that again I must state my fxml-foo is very low, so I might not be doing things the best way. Also, this approach leaves me with some open questions to discuss, which I will point out at the end of this comment. The FXML: <?xml version="1.0" encoding="UTF-8"?> <?import java.lang.*?> <?import javafx.scene.control.Label?> <?import javafx.scene.control.Button?> <?import javafx.scene.control.dialog.*?> <Dialog fx:id="dialog" fx:controller="samples.fxml.DialogOne" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"> <!-- ideally we would support contentText in some fashion, but at present it doesn't work as it is not a property --> <content> <Label text="Hello world!" /> </content> <!-- same here, we would rather set headerText somehow --> <header> <Label text="Header text" /> </header> <Button fx:id="yayButton" text="Yay" onAction="#yayEventHandler" /> <Button fx:id="noooButton" text="Noooo!" onAction="#nooooEventHandler" /> <Button fx:id="helpButton" text="Help me" onAction="#helpEventHandler" /> </Dialog> The controller: package samples.fxml; import java.net.URL; import java.util.ResourceBundle; import javafx.application.Application; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.fxml.Initializable; import javafx.scene.control.Button; import javafx.scene.control.ButtonBar; import javafx.scene.control.ButtonBar.ButtonType; import javafx.scene.control.dialog.Dialog; import javafx.scene.control.dialog.DialogButtonType; import javafx.stage.Stage; public class DialogOne extends Application implements Initializable { @FXML private Dialog<DialogButtonType> dialog; @FXML private Button yayButton; @FXML private Button noooButton; @FXML private Button helpButton; public static void main(String[] args) { launch(args); } @Override public void initialize(URL location, ResourceBundle resources) { ButtonBar.setType(yayButton, ButtonType.YES); ButtonBar.setType(noooButton, ButtonType.NO); ButtonBar.setType(helpButton, ButtonType.HELP_2); } @Override public void start(Stage primaryStage) throws Exception { FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("dialogOne.fxml")); dialog = fxmlLoader.load(); show(); } public void show() { DialogButtonType result = dialog.showAndWait(); System.out.println("Result is " + result); } @FXML public void yayEventHandler() { System.out.println("YAY"); dialog.setResult(DialogButtonType.YES); } @FXML public void nooooEventHandler() { System.out.println("Nooo!"); dialog.setResult(DialogButtonType.NO); } @FXML public void helpEventHandler() { System.out.println("It's ok to ask for help!"); dialog.setResult(DialogButtonType.CUSTOM); } } Key points: 1) I don't know that there is any way to specify the button type on the buttons in FXML (as there is no buttonType property on Button, like there is for the actions API), so I've fallen back to just doing this in the controller. Unless we add buttonType as a property to button, I have a feeling that this is the best we can do (and I am definitely not advocating to adding buttonType to Button). 2) As I mentioned earlier, the buttonType API has a Dialog.getButtons() method that people place buttons into. This works well for custom buttons - just throw them straight in there. For the default buttons (represented in DialogButtonType), we have a public static method on Dialog to createButton(DialogButtonType). I'm not sure there is any way to support this from FXML. I should say that much the same argument applies for the action API - the FXML example in my previous comment only uses custom actions, and ideally there would be a way (I don't know if it is feasible or not) to reference actions on the dialog instance (ACTION_OK, ACTION_CANCEL, etc are all instance fields on Dialog) - but I'm dubious that is feasible. Pointers would be great if I'm wrong! 3) The other thing that the button type approach requires, as I've mentioned previously, is that people providing custom buttons take care to set the result on the dialog - otherwise nothing happens! This increases the burden on the developer a little, as with actions we can by default close the dialog and set the result to the relevant action. This means that by default there is no need for a custom onAction event handler to be set. With custom buttons the user must set an event handler, and they must call setResult for each button (assuming they want the button to close the dialog). As always, I'm interested in peoples thoughts to the code, and especially responses to my earlier request for details on how people might use and configure dialogs in FXML. Thanks!
22-07-2014

To respond to some of the other comments made recently: @Eric: That static property API is already on ButtonBar (called setType), although it might of course change in the coming weeks. Hopefully my previous comment might help inform the discussion around actions and FXML. I'm keen to hear your thoughts. I'll try to do a similar FXML sample using the ButtonType approach. @Scott: Interesting point around different images for different states. I'm almost inclined to say that this should be handled via style classes and CSS, but I will definitely need to investigate this use case more. Regarding actions for wizards, yes, indeed that would be the plan. Eugene and I have both worked on wizards in controlsFX, so we have a good feeling for how this could be done. @Graham: No, there isn't any JavaFX-specific documentation on the pros/cons of Actions. Probably the best source of pros/cons is this very long jira thread :-) If you want I can try to write a pros/cons summary based on this discussion, otherwise perhaps reading up on Swing actions will provide sufficient background theory on their concept and application?
21-07-2014

@Jonathan Is there some documentation somewhere that outlines the benefits/drawbacks of Actions? I think this would help inform the discussion a bit.
21-07-2014

As others have mentioned, a factory for supplying graphic Nodes via the Action makes sense. This has the added benefit that the factory can be passed some sort of context, so the same graphic doesn't have to be returned every time even though it is for the same action. There is a good reason to support this, since graphics used on a toolbar may be different that graphics used on a MenuItem which may be different from the graphic on a Button somewhere else. It isn't entirely inconsistent, as others have mentioned, given the CellFactories we have now for other things, the concept of factories producing Nodes is already there. How will Action support different images for hovered and non-hovered buttons? When attached to ToggleButton how will you supply a different image for the selected vs. unselected states via the Action? A single graphic property is to constrictive. I wish I had more time to dive into this and actually try using these APIs now, but I don't.. I'm just skimming the javadocs for now. You are worried about retro-fitting Action support into the Dialog API.. but that is exactly what you have to do to get Action support into Buttons and MenuItems already. In some respects, if you go with a Button-based API the Dialog API may get some form of Action support when such support is added to Button. It does make sense to think of the use-cases now so that Actions can be added in a way that fits well. I'm not against Actions at all. I want the Action API in JavaFX. I'm just not sure how often I would use them in the context of a Dialog. Maybe I just can't think of the use-case at the moment, please give an example of when I would get the benefits specific to using an Action. The only thing that comes to mind is tying the enabled/disabled state to some condition so that the appropriate buttons are enabled/disabled. But since I don't think using the one-to-many aspect of Actions applies much to Dialogs, I'm not sure why that would be preferred over simply getting access to the Buttons If you are going with Actions, in the case of wizard-style dialogs I assume you intend to add default Actions for all of the ButtonTypes ('Apply', 'Next', 'Back', etc.)
21-07-2014

+1 for Action
21-07-2014

+1 for the action approach (i.e. v5)
21-07-2014

@Eric: Thanks for the feedback. My main argument for Action is that we only get one shot at Dialog API, and once we do it is set in stone. Therefore, once the dialog API is set, we almost certainly won't be able to retrofit actions into it. I would hate to add Actions in a future release and kick myself for not having them in dialogs, which is why I continue to persist on discussing actions. To answer your questions briefly.... Action is an EventHandler<ActionEvent>, so it works in almost the same way as implementing an EventHandler<ActionEvent> does today - with the added benefit of containing related information. We could have API on classes such as Button to setAction(Action), or we might continue to use setOnAction(EventHandler<ActionEvent>), and special case for Action - I don't know yet. In any case, I imagine that Action will slot in quite well. They should fit into FXML in much the same way, although certainly there is always room for more investigation here. Regarding the ButtonType approach, how would you envision Scene Builder integrating it? In particular, how would people be able to specify the default ButtonTypes - say they want to drag on DialogButtonType.OK and DialogButtonType.CANCEL. Would you imagine adding these pre-built button types to the library area, and then having special case code that calls the converter from DialogButtonType to Button? Or is there another way that these kind of scenarios are handled in SB? How would Scene Builder know that the ButtonType enumeration (currently separate from DialogButtonType) can be set on these nodes - or would you allow any selected node in SB to have its ButtonType specified on it? The best option would be to only allow ButtonType to be specified on nodes that are within a ButtonBar - is this possible? It would be useful to understand your suggestion around the responder chain approach, even though I know it isn't overly relevant to the dialogs discussion. To my untrained eye (in all things Mac OS), the responder chain approach looks a little like how JavaFX has event filters and handlers, and if so, then it seems that Action fits into this approach already by having the ActionEvent go through the usual event capturing and bubbling stages. Thanks!
21-07-2014

+1 for ButtonType. Although I can understand potential of a concept like Actions, I'm not comfortable to have it introduced in a minor release as a part of an API like Dialog. To me, impact of Actions on FX is not clear enough: how do they position regarding more general action events, how do they fit in FXML model and its action event binding... I would prefer these areas to be clarified before voting for Actions. This added time could also be an opportunity to compare/merge Actions with some other API mechanism : I'm thinking to the notion of "responder chain" which is the foundation of Mac OS since ages. May be we could try to make a synthesis and get the best of the two worlds for FX...
21-07-2014

@Jonathan: yes, I understand the « one shot » issue. Note that it’s also true if we introduce Actions now and find some issues later. API spec is a difficult art... FXMLoader is able to map a text value like #mymethod to the injection of an EventHandler property. If we introduce Action, it might be interesting to see if we need to revisit or complete this notation to keep FXML simple and consistent… Clarifying such a point before setting Action in stone seems important to me. Concerning ButtonType and Scene Builder, one approach could be to treat it like BorderPane children (when user drags a component from Library to a BorderPane, SB displays placeholders named top, bottom, right, left, center). We might also expose ButtonType as one or more properties in the Inspector panel. More investigations will probably uncover other solutions... As I write those line, I realize that ButtonBar and ButtonType spec could also use so called « static properties ». In place of: boolean ButtonBar.addButton(ButtonBase, ButtonType) we could have static void ButtonBar.setButtonType(ButtonBase, ButtonType) It would be pretty consistent with: static void VBox.setVgrow(Node, Priority) static void GridPane.setColumnIndex(Node, Integer) ... Concerning the « responder chain », I mention this because of the Action proposal. I agree it’s not specifically related to Dialog. In Mac APIs, this concept is separate from the event handling model. In fact, it’s a more abstract concept above the Mac event model. It looks a bit the same for Actions and the FX event model.
21-07-2014

Nowadays, I rarely put icon on a dialog button (or any button besides toolbars). For me it's mostly text only or text-less monochrome font-based icon (ie: a single char that looks like an icon). But I do that only because it's the fashion of the day, because we're influenced by iOS, Android and Metro designs. This may change back to full color icon few years from now as these trends appear to be cyclical. My 2 cents: within the context of the API where all graphic properties here and there are Node, it makes more sense that the graphic for an action to be a Node instead of an Image. The same reasoning applies for Action as for the rest of the API : 90+% of the time we would simply use an Image, except some those extra rare cases were we may need something else instead (ie : a node with some kind of animation that will morph icon or text into something else). Applies to Buttons, Tabs, whatever... Now we face the issue that we can only have a Node once in the SceneGraph so it makes more sense to either provide a factory property or to override a method that generates the node. Personally, I am much more of the factory property as it seems more in place with the rest of the API: unlike Swing, the JavaFX API seems to favor more instancing pre-existing classes and using pre-existing properties than sub-classing and overriding methods. The places I actually happen to override things in JavaFX are limited : - Skin mostly and I have yet to achieve a working result there. - Custom layouts and charts too and the only things overridden are usually things like layoutChildren() and layoutPlotChildren() so action methods instead of methods that return things. - Outside of the UI elements there is Service and Task too but those have not directly linked to the SceneGraph. Every place else in the SceneGraph nodes and controls public API we use properties for factories to converters instead of overriding methods.
20-07-2014

Fabrice, thanks for your feedback. It would be interesting to hear your thoughts (as well as anyone elses thoughts) on what should be done in Action to support any arbitrarily complex scenegraph as the graphic for a node. Option 0: Do nothing - stick with the simple case of supporting just Image. I would think this probably suits 90%+ of users who just want to show an image in their button / menu item. Option 1: In the V3 API [1], we had a graphic property and a graphicFactory property. We also had the expected getGraphic() and graphicProperty() methods that operated with ImageView. For users that wanted arbitrary nodes, we had getGraphic(Object owner) and graphicProperty(Object owner) methods that deferred to the graphicFactory callback. This approach was nice in the sense that Buttons, etc could bind to the graphicProperty(btn), for example. The downside is that this approach is inconsistent with all other instances of the property API, so I doubt it would pass the first hurdle (that is, the first API review). In fact, it was one of the pieces of feedback I received internally when the V3 API was reviewed, which is why I changed it in V4. Option 2: Do something like what Scott or I just proposed - have a method along the lines of createGraphicForNode(Node) or somesuch, that could be overridden by subclasses. There could additionally be code to return a property to be bound to, but I start to get quite nervous about this. The other difference of this approach is that it is essentially moving the handling (i.e. caching) out to the Action creator, whereas in option 1 it was handled internally. Option 3: ??? [1] http://jonathangiles.net/javafx/dialogs/v3
20-07-2014

+1 for the action approach Probably provide a graphicFactory property (similar to cellFactory on virtualized controls) instead of simply storing an Image.
20-07-2014

Scott, thanks for the feedback. Here's my responses: Image as the basis for the Action graphic: This is something I've heard previously, and as I noted in an earlier comment is unfortunately due to scenegraph restrictions - we can't just have Action have a Node graphicProperty, as there isn't a 1:1 mapping between action and UI controls - if there was this would be fine API, but then Action would be pretty useless :-). I'm a little unclear on how your proposed API would work - could you clarify? The V3 version of the Action API had a lot of code for a graphic factory, etc, but that seemed overkill and inconsistent API-wise. Another option would be to have a method that could be overridden to getGraphicForNode(node), which by default returns null (and therefore indicates the graphic property of type Image takes precedence). Single "style" property: I think you're confusing "style" with "styleClass" - Action has both, and styleClass does indeed support a list of style classes which are added to the control. Dialogs without actions: It would be interesting to hear your thoughts on the V4 API - it has DialogBase and DialogPaneBase, which are generic and do not force the use of Actions, and then subclasses that do force the use of actions. Would this be beneficial to you, and if so, would you really use it even if it forced you to do more work compared to the pre-built Action-based dialogs? Regarding the overall API documentation: yes, nothing has been updated, this is purely an API discussion at this stage and I have a lot of work ahead of me to update the javadoc (I figure there is little point updating the javadoc when the API is in such a massive state of flux). Yes, ButtonBar will be updated to work as necessary (or alternatively it'll become a hidden implementation detail, I haven't thought through how best to expose this yet, and it depends if there is an appetite for exposing ButtonBar publicly). "APIs should be on DialogPane, instead of Dialog": Currently getHeader(), getGraphic(), etc are on both classes, with the Dialog API forwarding it on the DialogPane. This means there is no implementation in Dialog, just forwarding calls to DialogPane. I did this for the 95% of users who never need to know about DialogPane, because otherwise they would have to write all their code as such: dialog.getDialogPane().setHeader(...) - and this just seems like an extra unnecessary burden. Thoughts?
20-07-2014

There are a few things in the v5 API that I don't like: Using Image as the basis for the Action graphic: The only reason for it would be if it is not possible to render anything but an image to the OS X menu bar, but in general I dislike the forced limitation. A single API, e.g. setGraphicFromImage(Image) could be used to auto-wrap in an ImageView. It has a single "style" property for CSS but no means to use a list of CSS style classes that would be added to the control (MenuItem, Button, etc) Just like we can use Buttons and MenuItems with or without Actions in Swing, we should be able to use Dialogs with or without Actions. So I vote for the v6 approach. Let Actions remain a separate thing that we aren't forced to use, but could easily use if we wanted to. In the v6 API it has: javafx.collections.ObservableList<javafx.scene.Node> getButtons() Observable list of actions used for the dialog ButtonBar. I think it should return a list of Buttons. The discription needs updating too. APIs like getHeader(), getGraphic() should operate on DialogPane, instead of Dialog. Let DialogPane deal with those concepts and the layout thereof. Let Dialog worry about the lifecycle of the Stage it is in, handling of return values etc.
20-07-2014

To intercept Mikael, I should clarify that indeed, if actions are introduced as part of dialogs they will be introduced as part of the entire controls toolkit. So, if you're voting for actions, please consider that a vote for adding actions to the entire toolkit (where appropriate).
20-07-2014

If Actions are introduced they should be used in the whole of JavaFX, not just here. It's such a general concept I think. +1 for ButtonType
20-07-2014

+1 for the action approach
20-07-2014

Ok - discussion seems to have ground to a halt. I'll presume that in general people are happy with the direction shown in the v5 [1] and v6 [2] apis. In any case, could people please take the time to cast a simple vote? Your options are to +1 the action approach, +1 the button type approach, or +1 for "I don't like either and your API stinks". Thanks! [1] http://jonathangiles.net/javafx/dialogs/v5/ [2] http://jonathangiles.net/javafx/dialogs/v6/
20-07-2014

Super late to the discussion but I have been following along for a while. All I would like to say is that the Actions API seems solid and works well. I don't see any reason as to why it should be changed or removed. And I'm out!
16-07-2014

I figure I've done enough talking about the V6 API, so I wanted to get a version up for people to review. It is still very draft and exploratory, but it should interest people due to its lack of Action. The url is here: http://jonathangiles.net/javafx/dialogs/v6/ In short, v6 takes v5 and explores the DialogButtonType API approach. The DialogButtonType API approach essentially makes use of an enum of button types (OK, CANCEL, APPLY, etc) to specify which buttons to show. In short, instead of passing in a list of Action, you create Buttons from DialogButtonType (or you create your own custom buttons however you want), and you set these in a getButtons() method (which is analogous to the getActions() API in earlier API prototypes). All buttons need to have code in their event handler to set the result in the dialog, and by doing so the dialog will close. This is handled internally in the Action approach. In the case of Alert (the high-level dialogs), the type of result is Node - i.e. the Button that was clicked. In other cases, like TextInputDialog, it is Optional<String>. Porting the vast majority of the Actions-based dialogs over to ButtonType was trivial, although I did hit a few hurdles when it comes to custom buttons in a dialog. There are a number of concerns that will need to be resolved, including: 1) The Action approach had a really nice feature - people could create Actions that in their event handler consumed the ActionEvent, and this would act as a way to veto the closing of the dialog. The current API doesn't support that, as we require users to set the event handler directly on the button, so we've lost ownership of specialised handling (when we create buttons from Action, we create a private event handler that calls the action event handler, so we can do specialised handling in the outer handler....if that makes sense). 2) My belief is that this API makes some tasks more difficult (but I hope that there may be a better API that helps). Some examples: 2.1) Customising the buttons list is more difficult. In the Actions case, the use could simply getActions().remove(dlg.ACTION_CANCEL). In the DialogButtonType case, we need to do the following: iterate through getButtons(), cast each item from Node to Button, find the Button with the text equal to DialogButtonType.OK.getDisplayText(), store a reference to this button, break out of the iteration, and then remove the Button from the buttons list. 2.2) One of our test dialog types is the CommandLinksDialog. This creates a Windows-specific dialog with big, wide buttons stacked vertically. In the Actions case creating this custom dialog is easy, as we simply take the list of actions, and create our custom buttons from this. In the DialogButtonType approach, we're somewhat stuck - we only have getButtons(), which is a list of Node. This means that we have lost control over the buttons before we begin, and there is no guarantee that the buttons will be able to be styled to fit into the expected Command Links style. We could of course add additional API to the CommandLinksDialog to handle this, but we are always stuck with getButtons(), and users will expect this API to work. 2.3) It is more work to create custom buttons. The nice thing about the Action approach is that everything is encapsulated within the Action code - you create the Action instance, set the relevant properties and event handler, and pass that to getActions(). In the DialogButtonType approach, you need to create the Button, remember to specify the ButtonType, add an event handler (and remember to call dialog.setResult(..)), and then add this to the buttons list. Without doubt some helper API (or changes to the V6 API in general) might help in these situations. My main concern is having the best API we can, and I feel like getting rid of Action puts more onus on individuals to make sure they are doing the right thing to get the result that they want. As always, I look forward to your feedback - it has helped inform a lot of the API so far, and I hope you can all stick with me for a bit longer as we get onto the home stretch! Thanks.
16-07-2014

You might be right. If CompletableFuture is to be used the JavaDoc in the non-blocking method needs to be very good and contain example code! Consumer (which really is a listener) is a nice solution as well. I'm not a fan of Actions. Never used them in Swing. Mainly because when I tried them they couldn't convey all the options I wanted and was hard to extend.
16-07-2014

Mikael, thanks for the comment. I did look briefly into CompletableFuture and CompletionStage, and was blown away with the complexity of the API - so clearly I need to do more reading. The big hangup with this approach is ensuring that users can't shoot themselves in the foot by doing something like the following: Future<R> future = dialog.show(); if (future.get() == OK_BUTTON) { ... } The problem with this is that we have a nice, non-blocking dialog that immediately blocks when the user calls get(). Even worse, if we do nothing smart in the code (which I'm not sure of the feasibility at present), then the user has actually blocked on the gui thread - preventing the dialog from being responsive to the user input! It sounds like perhaps these new classes in Java 8 might help....but I wonder if the change to this API is worth it...? I'd be interested in hearing your, and others, thoughts on the API as presented in the V5 link - I just use the Consumer<R> argument approach, which nicely works around this problem.
16-07-2014

Jonathan, Regarding futures. You would not want to return a simple Future I think. They are as you mention a bit useless. Java 8 has the new CompletableFuture which is much more usable. You can read about it here: http://www.nurkiewicz.com/2013/05/java-8-definitive-guide-to.html I haven't used it though, I normally use ListanableFuture in Guava. But CompletableFuture seems to me to solve the same problem, which is that you can listen for a result and act upon it when it happens, on a thread of your choosing.
16-07-2014

As noted in my previous comment, I have now simplified the generic typing in Dialog and DialogPane in v5 to always require Action as the incoming type (i.e. the type of elements used to specify which buttons to show). This is reflected in the v5 javadoc here: http://jonathangiles.net/javafx/dialogs/v5/ Now, back to the mythical v6! :-)
16-07-2014

I should note that V5 has generic types in Dialog and DialogPane, although I'm inclined to remove them to simplify the API and to show what a fully Action-based API will look like. I'll probably look into that tomorrow, time permitting.
16-07-2014

Hi all, at present I'm working on two separate API implementations, and now have one at a point where you can take a look and give feedback. This version is what I'm calling V5, and it is a continuation of the action-based dialogs approach. The next version I'm working on is essentially the same API as V5, but without Actions. I'll post about that when it is ready for review. As always, the API can be found here: http://jonathangiles.net/javafx/dialogs/v5/ I will try to get code zips posted as soon as possible, but I am pretty flat out just getting the API revisions made. Here's a list of the major changes in V5: * Support for non-blocking dialogs - there is now show(Consumer<R>) and showAndWait() * I've collapsed DialogPaneBase and DialogPane into one class * I removed the expanded property out of Dialog (it belongs in the DialogPane, not in the Dialog) * DialogPane now extends from Region, not GridPane * ButtonBar has been made more generic, supporting any Node (as long as it has been annotated by ButtonBar.setType as usual). * What was previously called Dialog has been renamed to Alert, and has had its API simplified, in the following ways: * Alert is just about alerting the user, so confirmation, error, information and warning are the supported types. * Instead of having these four types as separate methods, I have introduced a DialogType enum which is a constructor argument in Alert. * This reduces the number of show methods to one * All other show methods on the existing Dialog class (showChoices, showCommandLinks, showException, showFontSelector, and showTextInput) have been removed, and extracted out to separate classes (e.g. ChoiceDialog, CommandLinksDialog, ExceptionDialog, FontSelectorDialog, and TextInputDialog, respectively). * Alert is a subclass of Dialog * I have moved the API into a slightly better package namespace (although where it eventually ends up is not decided (less packages are better)) The V5 API is therefore simpler and more complex at the same time. It essentially swaps a reduced method count for an increased class count. As always, I really look forward to your feedback. Please keep it coming! Time is running out to get your feedback in, so please don't hold back. Thanks!
16-07-2014

Ryan - sorry - I misinterpreted CompletionStage to mean a new class - I was unaware of the Java API of the same name.
16-07-2014

Folks, I'm glad we've shifted focus to non-blocking behavior, as that is something I want to work on right now. I can see at least two approaches, and I hope to hear your thoughts. Approach 1: Have the non-blocking show() methods return a Future<R>. Approach 2: Have the non-blocking show() methods take a Consumer<R> as an argument, which is called when the value is returned. With lambdas, this becomes dialog.show(result -> handleResult(result)); My problem with approach one is that Future isn't all that useful (although I might be wrong). All you can really do is call isDone() and wait in a loop until it is true, or call get() on it and then that starts blocking again. Approach two seems a bit nicer to me, in that it switches the responsibility back to the dialog to call you when the result has been set. I am unlikely to endorse an approach such as the one suggested by Ryan above where a CompletionStage class is created. In effect this code is equivalent to approach two, it just hides the Consumer inside CompletionStage (so it doesn't seem worth the extra class to me). I really would appreciate peoples thoughts.
15-07-2014

I played with this more and have a bit to add to my previous comment. The ability to show a dialog in a non-blocking manner (the false version of blocking in Tom's explanation) is what I was asking for. I don't think returning a Future<R> would be very useful. That API is pretty limited. The CompletionStage interface is more useful in my opinion. The API for DialogBase could look like this: public R showAndWait(); public CompletionStage<R> show(); That would let me do: dialog.show().thenAccept(result -> handleDialogResult(result)); // method reference could be used too Regardless, I think the DialogBase.show() method should be showAndWait() so it's consistent with Stage.
15-07-2014

I think there are 2 distinct things that get mixed up a bit: * modality: talks about the UI representation which does not allow a user to enter information into parent "windows" of the dialog * blocking: talks about the programm flow, true == spin-event-loop, false == do not spin event-loop I think a dialog system should support both concepts.
15-07-2014

I clicked post a little too quick on that last comment. If I misuse any terminology in this comment, please point it out. I see now the call to show() is probably using Stage#showAndWait, so it's a nested event loop regardless of modality. If I remember correctly, the current (stable) ControlsFX implementation is the same (correct me if that's wrong). I find this can make it difficult to create dialogs where the visibility is bound to the the state of another model. A very good example is the current worker progress dialog in ControlsFX. A simplified explanation of how it works is: - the State of the Worker is observed. - when the State changes to SCHEDULED, the show() method of the associated dialog is called - when the State changes to SUCCESSFUL, FAILED, CANCELED, the hide() method of the associated dialog is called The specific case I had trouble dealing with here was: - submit a Worker with State READY - State transitions to SCHEDULED - the transition is observed - Dialog.show() is called and enters the nested even loop - notification of future State changes is prevented, so a transition to a completion state never occurs and Dialog.hide() never gets called The way I dealt with the above was to make sure the call to Dialog.show() was wrapped in Platform.runLater. The result of the call to show() is discarded. For the API user, I think this could be a bit confusing. All of the other showXXX methods use a nested event loop and the dialog will be hidden before the next line of code executes, but, for showWorkerProgress() the next line of code can execute before the dialog is hidden. Also, and this may simply be a personal dislike, I don't like using Platform.runLater from the UI thread. I find it makes it more difficult to reason about the execution order of my code. I'd rather deal with a Future since I have a better understanding of the Futures API than I do of the JavaFX event loop, etc.. In my post a ways up I said that I'd like to have a non-modal dialog, but still be able to block user input. My explanation of that was not good and I misused some terminology. What I really should have been saying is that I think it would be useful to be able to create a modal dialog that doesn't use a nested event loop. Would it be possible to expose the difference between Stage.show() and Stage.showAndWait() in DialogBase? Maybe it could have a Future<R> showLater() method? I like the split between DialogBase and Dialog. I think it does a good job of giving us the "best of both worlds" where the API can support complex dialogs when needed, but remain simple for the most common use cases.
15-07-2014

@Scott - I should also add that the v6 API being worked on now presents an entirely different approach to dialogs (with no actions API, and more in line with Mikael's proposed API), so in that case you will definitely be able to have scalable graphics, rather than just Images.
15-07-2014

@Scott: I understand your use case, but I wonder if the increased complexity in the API is worth it? Eugene has exactly the same concerns. Did you take a look at the Action API in v3 and v4 - would you be happy with the v3 API from a functionality point of view? The problem is that it is non-standard API from a JavaFX consistency standpoint. @Ryan: I can try to package up a v4 zip later today. I'm actually in the process of building v5 and v6 APIs now as well, so I'll try to do it for all three later today when I release them. I apologise in advance for the pace at which new versions of the API are being created, but I'm on quite a tight timeline to get things done.
15-07-2014

Is there somewhere to download v4 or is it just the API docs for now? What gets returned by DialogBase#show when Modality is set to NONE?
15-07-2014

It should be possible to specify the graphic as a Node. You could still provide the convenience method to auto-wrap an Image with an ImageView. Using a Node will allow the graphic to be done with a vector representation, and possibly add simple animation, and more importantly allow for use cases that haven't been thought of yet.
14-07-2014

I should also add that V4 is a little rushed - I wanted to get it out in time for another internal discussion (which I will summarise when applicable). I would particularly appreciate it if anyone who reviews the API can propose ways in which it could be simplified.
14-07-2014

Hi folks. I've just put up a blog post about dialogs over at FX Experience: http://fxexperience.com/2014/07/javafx-dialogs-update-1/ In the post, I also put up the link for the V4 release of the dialogs API that Eugene and I have been working on: http://jonathangiles.net/javafx/dialogs/v4/ It would be great if you could read through the blog post and come back here to offer your corrections and feedback to what I have said, and how the API has evolved. I need to stress however that at this stage we are experimenting with API, so the changes between V3 and V4 are not indicative of a general movement one way or the other - it's just indicative of what we're exploring at present, and it is now up to you to take the time to review V3 and V4 and offer your opinion on which direction you like best (in short, V3 is simpler and less flexible, whereas V4 is still simple for the main use case, but more flexible for the advanced use case (but also more complex)).
14-07-2014

I'm back from vacation now, so I'll quickly respond to the comments left whilst I was away, but I'll start by noting that I am planning to do another blog post over at FX Experience in the next few days to summarise this discussion, and to introduce a v4 version of the API that Eugene and I are working on. @Graham: I don't have a notion of a Control and a Node being different, I have a notion of a Dialog and a Node being different. In other words, I don't believe that a Dialog is a Node - it is more in line with being a Stage than a Node, in my opinion. This is why I said that it seems weird to have all the API from Node available on your Dialog class. It means that people will complain when your dialog is not rotated 90 degrees, or other weird issues that arise from having all the API from Node on what is a top-level window. Your use case seems to be handled very simply (which suggests I must be understanding it). You would create a new Dialog instance with the Actions you want (OK, Cancel), then you would create your custom content to sit above the buttons, and call setContent(Node). All you would see in the dialog is your custom content and then the buttons beneath it, which sounds like what you're asking for. @Eric: Thanks - I can appreciate this will be a problem for SB, so I'll work on a way to resolve this. @Steven / @Scott: I agree, being able to control which min / max / close buttons are shown is important. It is something that needs to be first made available by Stage, and I filed these requests back in July 2013 in RT-31903 and RT-32348. The only way dialogs can do this in advance of Stage having the functionality is by using the cross-platform style, which is not overly what Steven in particular is asking for. What I do in the dialogs implementation is set the StageStyle to be 'utility', which on some platforms at least makes the dialogs better. You can see screenshots in the ControlsFX JavaDocs here: http://controlsfx.bitbucket.org/org/controlsfx/dialog/Dialogs.html (Scroll down to the 'Styled Dialogs' section)
11-07-2014

The title bar buttons are something that should be addressed by the Stage. Yes, the default for the dialog should be as you say, but the implementation that allows control of these buttons belongs in Stage. I agree that this is important.
11-07-2014

One of the most important things is that the API provide the means whereby the Dialog will appear as Native to the user with high fidelity. Practically that means that there must be means within the API to fully get rid of the minimize, maximize and close buttons as provided by the underlying OS, and which were prevalent in the Swing version of the title bar of JOptionPane. No, a better idea: these title bar buttons should not be there by default and there should be an API to make them visible for those rare occasions where they would be desired. As justification for this point of view, show me one such dialog in native OS X or Windows operating system! The existence of such dialogs is the first and blatant give-away that the software is not native.
11-07-2014

Looking at latest v3 prototype, I noticed: Dialog.setContent(Node) Dialog.setContent(String) From an API standpoint, this is perfectly correct. However for SB it's a bit problematic because type of Dialog.content property becomes ambiguous. May be we could have: Dialog.setContent(Node) Dialog.setContentWithString(string)
09-07-2014

@Jonathan > Because the model is essentially for the purpose of a single property, doesn't it make sense to simply have the result property be on Dialog itself Possibly yes. The only reason I didn't do this was because different dialogs could have different models, rather than just being simple results. @Jonathan >In terms of separating concerns, it seems to me what you're really doing is making a Dialog appear as if it is a Node as well, so in my eyes you're mashing together the concerns you're trying to Umm, I am not sure what you mean here. But I guess to me a dialog is a node shown in a particular way. I am not sure what else one would think I dialog is :-) You have some notion of a control and a node being different ... @Jonathan >In terms of reusing one dialog inside another, my personal feeling is that this is a very rare use case. The only example I've really heard of is the 'multiple cancellable progress bars stacked in a VBox' requirement Ok, so let's attack this from a different angle. Suppose I want a dialog with an Ok/Cancel button bar, but none of the standard masthead, message etc, stuff. So I want the Ok/Cancel part (including the internationalization and the button ordering), but not the rest -- for the rest I want some custom thing. To make that happen your dialog API for the standard case will have to expose the relevant capabilities so that they can be re-used. Otherwise I have to re-implement it all myself. If you expose the standard things like this, then you get both the standard dialogs and composability too. I gather you don't like that idea since it makes the API large ... even though the methods are there, just not public ... @Jonathan >In terms of reusing one dialog inside another, my personal feeling is that this is a very rare use case. The only example I've really heard of is the 'multiple cancellable progress bars stacked in a VBox' requirement (I attached a screenshot of this from IntelliJ), and this case suffers to make a strong point because the progress / cancel buttons are custom and not based on a pre-built dialog type. Do you have an example use case where you would use a multiple instances of a pre-built dialog in a dialog? This was my original example of what i wanted to do -- a progress bar with cancel button (that can be done in ControlsFX with the standard setup) -- and then several of them laid out horizontally. IntelliJ did some custom thing for this, but I wanted the N standard dialogs laid out left to right. And yes I knew/know that the ReusingDialog has a bug -- I wasn't trying to write perfect code, just illustrate the approach. And finally, yay for DialogPane :-)
02-07-2014

By the way, I'm aware that I'm coming across as someone that is tearing everyones feedback and implementations to shreds. I am not meaning to be rude at all, and I really, really appreciate your hard work (especially if you're spending the time to create implementations). As I've said all along, I'm happy to get as good as I'm giving, which is why I've posted the implementation code for the version Eugene and I have been building in this jira issue, and also have posted the API documentation for the latest prototype here: http://jonathangiles.net/javafx/dialogs/v3/ The only caveat I'll add is that the implementation and API docs are pre-API review, so it is missing any changes based on that discussion. I have listed the outcome of the API review a few comments further up this Jira issue, and will be exploring them once I return from vacation. Despite this, I really do hope that people poke holes and point out issues in this API as well!
30-06-2014

Ugh, this discussion is becoming very multi-pronged. Let me try to answer without continuing to branch into separate points... In your implementation, the model has a result proprty, which can be observed. This is the crux of the model, as you state. Because the model is essentially for the purpose of a single property, doesn't it make sense to simply have the result property be on Dialog itself, rather than complicate matters with a model (the complication arises because listeners need not only concern themselves with listening to model.result, but also to model, and if model changes, to detach their listener from oldModel.result, and to attach it to newModel.result). By having the result on Dialog, we do not have this concern (and it isn't a concern for me as an implementor, it is a concern for end users of the API, most of which will never pick up on this subtle detail and possibly shoot themselves in the foot when they change their model and no longer gets results as expected). I agree, in JavaFX UI controls we attempt to use ObservableLists for the model, wherever possible. This is also why I currently use getActions() as the means of specifying the action, for example. In terms of separating concerns, it seems to me what you're really doing is making a Dialog appear as if it is a Node as well, so in my eyes you're mashing together the concerns you're trying to separate, in the name of composability. Taking this approach you're risking having a very large API surface area, and receiving a lot of bug reports when things don't work as expected. This is also why classes like MenuItem or Tab don't extend from Control - it doesn't really make sense that they do, but back when I was building these classes people also wanted these to be Controls (and many still would like that) :-). In my mind, Dialog is the same - it is a Dialog, not a Node that can also be a Dialog. My intended approach is quite similar to yours, but avoids this issue. My plan is to have Dialog extend from Object, but to be able to contain a DialogPane that extends from some reasonable parent (be it Parent, Region, or something else, I haven't worked it through in my mind yet). This has the benefit of not scaring away end users (their simple case is on Dialog, which only exposes API from Object, and whatever API we specifically want), but also allowing for your use cases of creating a DialogPane and going to town. In terms of reusing one dialog inside another, my personal feeling is that this is a very rare use case. The only example I've really heard of is the 'multiple cancellable progress bars stacked in a VBox' requirement (I attached a screenshot of this from IntelliJ), and this case suffers to make a strong point because the progress / cancel buttons are custom and not based on a pre-built dialog type. Do you have an example use case where you would use a multiple instances of a pre-built dialog in a dialog? I think we should therefore separate out the need to create totally custom dialogs from the ability to reuse pre-built dialogs, as the former is important, but I find the latter debatable. I find the 'reusing dialog' argument for the value of the model apparoch to be highly contrived - it might be better to create a more realistic use case and example. The approach you take is to create a custom ReusingDialog subclass of DialogPane as your custom UI and internal model (as it listens to the model.result property of each sub-dialog, and if the count of the number of cancel clicks is equal to the constructor argument, it updates the outer model). I would have presumed you would have had the ReusingModel class handling all the sub-model stuff. The ReusingModel doesn't really serve any purpose other than to be set by ReusingDialog, and observed by the ReusingDialog and user. This approach also easily lets bugs creep in - I assume the intent is that the user needs to click each cancel button in the four standard dialogs, but this isn't enforced - the dialog also closes if the user clicks ok and then cancel four times. If the intent is to have each of the four cancel buttons clicked, how would you determine which button is clicked? If someone put a gun to my head and forced me to use the actions approach to reuse four standard dialog panes in a single dialog, my approach would be to create four standard dialog panes as you do, but then I would get the actions lists for each pane, and iterate through. For each cancel action found, I would setEventHandler(..) to an event handler that modified the count (or bitset if all buttons have to be clicked). If the (bitset) count was less than four, the event handler would conclude by consuming the event. This informs the current dialogs implementation to _not_ hide the dialog. Alternatively, if the (bitset) count was four, I would not have the eventHandler consume the event, so that the dialog would close. This also means that my handling is happening inside each button, where I can know which one has been clicked and to know if it has been clicked before (to avoid the bug I mentioned before).
30-06-2014

@Jonathan >Your suggestion is that having a dialog model is consistent with other UI controls, but from my point of view in JavaFX we've tried really hard _not_ to have models. Most UI controls have an ObservableList as their model I thought about this after I posted that comment, and I think it's just a matter of terminology. I agree that JavaFX appears to have no classes for models. But I think JavaFX has a very strong notion of model, namely observables (lists, properties, etc). JavaFX simply splits a Swing style model into several observable pieces, so that client code can observe part of the model, without observing all of it. My implementation essentially does this too, since they only thing of any real note in my model is an observable property. @Jonathan >1) It seems reasonable to me that DialogPane extends from Parent, but it is unexpected that the dialog implementations that end users call (OkCancelDialog, etc) extend from DialogPane. This means that all API on Parent is available to users of the OkCancelDialog, and they would expect for all of it to work (e.g. rotate, translate, etc). Is this your thinking, or an oversight? To me the dialog is a node. How the dialog is displayed/popped-up (lightweight, heavyweight, whatever) is a separate concern. So yes I meant to have all the nodeyness available to dialogs. @Jonathan >2) What dialog implementations would you propose being included in the API? >4) A big concern with your implementation is the number of classes required to provide the functionality. With respect to the standard dialogs that should be there, I honestly have no real preference. My implementation was not designed to address such issues, but to try to look at composability via models. Also as to the number of classes, I am not sure that is true. I made OkCancelDialog as a class, but I think with a little tweaking of how the buttons are specified, it could be the single standard dialog class. Don't read too much into the details of how I arranged the classes -- I wrote it quickly and without coffee :-) @Jonathan >5) It seems odd to me that DialogPane has both set/getContent methods, but also a buildContent() method that returns a Node. What is the intended approach, and should there be properties for model and content (yes, there should). >6) When you say your approach factors into composable pieces, can you clarify what you mean? Are you meaning that DialogPane is a Node so that it may be placed into the scenegraph without being in a popup window, or are you saying that DialogPane can have any content set within it (or >built within it using buildContent)? Ok, so this is a result of me doing a crappy job of explaining things. I am trying to get DialogPane as a Node, yes, since I want to put it into the scene graph without it being in a popup (see my previous comment about a dialog being a node and how it is displayed on screen is a separate concern). Also I want DialogPane to be able to contain arbitrary content so you can build complicated custom dialogs. My implementation had a model, the hide listener in the show method (and not in the buildContent() method), and the separate buildContent() method, precisely so I could re-use one dialog inside another -- so I could compose dialogs with other dialogs and other nodes to build more complex dialogs. I exploited this in my ReusingDialog example. @Jonathan >3) The difference between the Action / DialogAction approach of setting the result on the Dialog directly, and the non-action / model approach of setting the result on the model, are virtually identical, except for the extra layer of indirection between the dialog and the model in your implementation. Your approach is to set a result on the model, but then the dialog itself observes the model and immediately hides the dialog and returns the result back to the caller. Is there any intent to change that, because to me if you're going to instantly close the dialog when the model changes, you're not gaining any new functionality, are you? So maybe I am misunderstanding this, but to me the model and the dialog observing it serve a critical role -- it is the key to being able to compose smaller dialogs into bigger ones. Take the ReusingDialog -- if I had used standard actions then when the user hit cancel one one of the Single Dialogs sitting withing the ReusingDialog, it would have hidden the whole ReusingDialog. Which is not what I wanted. So there were two choices for ReusingDialog: a) use the model and observers approach as in my implementation -- this approach allows me to re-use the OkCancel dialog *as-is*. b) create my own cancel action (which has to look just like the standard cancel action, except it shouldn't hide the dialog box), then create an OkCancel dialog with this new cancel action, and not the standard one, and then put the OkCancel dialog into my ReusingDialog. So I don't get to re-use the OkCancel dialog as-is -- seems like more complexity than the model based approach. Hope I covered everything.
30-06-2014

Graham, Thanks for taking the time to create an implementation to help discuss your ideas. Before I comment on your implementation, I think it is important that we clarify your point a). Your suggestion is that having a dialog model is consistent with other UI controls, but from my point of view in JavaFX we've tried really hard _not_ to have models. Most UI controls have an ObservableList as their model, and only have 'proper' models in cases where there is a subset of functionality that can be shared across multiple controls (e.g. selection and focus models). Having a model backing dialogs does not make sense if the only argument is for API consistency. Some high-level comments on your implementation: 1) It seems reasonable to me that DialogPane extends from Parent, but it is unexpected that the dialog implementations that end users call (OkCancelDialog, etc) extend from DialogPane. This means that all API on Parent is available to users of the OkCancelDialog, and they would expect for all of it to work (e.g. rotate, translate, etc). Is this your thinking, or an oversight? 2) What dialog implementations would you propose being included in the API? You've got OkCancelDialog, etc - but it would be good to enumerate what your total set would be (if any). I doubt ReusingDialog or OkCancelExtraDialog are part of the public API. Without knowing what 'high-level' dialogs you would plan to include, it is hard to comment on how easy the API is to use for the simple use cases. 3) The difference between the Action / DialogAction approach of setting the result on the Dialog directly, and the non-action / model approach of setting the result on the model, are virtually identical, except for the extra layer of indirection between the dialog and the model in your implementation. Your approach is to set a result on the model, but then the dialog itself observes the model and immediately hides the dialog and returns the result back to the caller. Is there any intent to change that, because to me if you're going to instantly close the dialog when the model changes, you're not gaining any new functionality, are you? In general, to me, the extra layer of the model doesn't pay for its weight, so whilst I'll grant that it is ideologically cleaner, it doesn't (to me) seem to offer any pragmatic value. What benefit do you foresee from having the separate model class? 4) A big concern with your implementation is the number of classes required to provide the functionality. As I said in 2), it would be good to enumerate what dialog types you would propose, but based on what is in your zip file (and I can't be sure you are suggesting all of it should be part of a public API), I count eight to nine classes (four model and four to five UI-related). I'm sure this could be reduced quite dramatically with a bit of refinement. 5) It seems odd to me that DialogPane has both set/getContent methods, but also a buildContent() method that returns a Node. What is the intended approach, and should there be properties for model and content (yes, there should). 6) When you say your approach factors into composable pieces, can you clarify what you mean? Are you meaning that DialogPane is a Node so that it may be placed into the scenegraph without being in a popup window, or are you saying that DialogPane can have any content set within it (or built within it using buildContent)? I think the big benefit of your approach is the DialogPane class, which allows for far greater customisation. This is something I also posted in one of my earlier comments as being something that will be researched and implemented in a future implementation of my prototype.
29-06-2014

Thanks Jonathan. My dialog implementation looks butt ugly -- I haven't spent any time on layout, pretty stuff, etc. Besides, I suck at that stuff, so whatever I do won't look nice. What the implementation does do is to attempt to build a dialog implementation that: a) has an explicit dialog model (like other controls do) b) factors into composable pieces c) is easy to use for simple cases. d) supports custom dialogs As a result of a) I haven't used Actions (at least as implemented in ControlsFX). Actions mix model (being the results of dialogs), and control (calling dialog.hide() methods). In this implementation Dialog results are part of the model, and are separate from anything the controls do. My main program shows three dialogs -- a standard Ok/Cancel, an Ok/Cancel extended with an extra button, and a dialog that embeds 4 Ok/Cancel dialogs inside it (click each cancel button once to close the dialog). The whole thing could in my opinion be made even more composable, but I wanted to get the approach out there. Also I don't really like the way dialogs are shown -- I wanted to support lightweight dialogs but don't know how to, and I wanted to support the dialog and the node whose events are being blocked to be modal, from one another, but again I didn't know how to do that. Also I just noticed a small "error". The first line of showDialog() in class ReusingDialog should just say Stage stage = new Stage(); I don't actually need/use the DialogStage class.
28-06-2014

Attaching Graham Matthews' dialog implementation, as requested.
28-06-2014

@Jeff: having a buttonClicked() method isn't what other parts of JavaFX do (?) They have event handlers and consume the event. Take a look at Tab for example. This kind of thing is precisely why I brought up models for dialogs.
28-06-2014

@Jonathan: I think you could solve #1 with a protected boolean buttonClicked() method (that returns true if the button click should be accepted). You could solve #2 with a getOptionButton(name). #3 is already solved with the showOptionDialog() method returning the Options index. I submit though, Actions aren't the end of the world. :-)
28-06-2014

Attaching Scott's dialog implementation as requested.
28-06-2014

I have another question for folks. I was looking over the dialog-impl attachment and something occurred to me. Most controls have models (selection models for example). I couldn't find any models for Dialogs. In fact it seems that Actions perform the role of models. For example when you set the result of a Dialog you set it to an Action. But Actions seem to be more than model as they call Dialog methods. I was expecting to see a dialog model that the actions would set values in, and then listeners in the Dialog control would re-act to changes in the state of the model. This would allow for a lot of customization. But I don't see this. Can the model be teased out for a dialog and separated from the actions?
28-06-2014

@Jeff: Why is that? What is it you don't like about Actions? How would you propose supporting the three main use cases that Actions (non-exclusively) enable (or would you propose not supporting all of these): 1) Support for dialogs that do not dismiss when the button is clicked 2) Support for toggling the disabled state of the button directly via the action 3) Support for specifying which button has been clicked in the UI.
27-06-2014

@Jonathan: You may be right - I might just be getting hung up on the Action idea. I'd prefer to go without it. :-)
27-06-2014

For security reasons attachments are disabled unless you're an Oracle employee. If you really want to post an ODF file I can attach it if you email me, but I think generally it would be better to post it as a comment so that people are more likely to read it.
27-06-2014

Thanks -- the find/replace dialog is a nice example! I have another dumb question -- I started typing up some ideas about what things I think need to be kept orthogonal are, what an API might look like, etc. It's an ODF document. How do I attach it here -- I must be missing something really obvious.
27-06-2014

There has been a lot of discussion whilst I was asleep, and I'll now try to respond briefly (as it is a sunny Saturday morning here). @Jeff: When I look at your API suggested earlier on, and compare it to the latest API I posted for my prototype, I don't fully understand what you're not keen on? Could you please clarify in terms of the API I'm proposing? To me the difference I can quickly see are you using String to represent the options - other than that it seems to match up to my prototype extremely closely. @Graham: One example of a non-blocking dialog is something like the 'find/replace' dialog you see in most text editors - even though you've got the dialog open and you can interact with it, you are not blocked from typing text into the text editor itself. @Everyone: I just did an internal review of my prototype and now have a bunch of feedback that will help inform another revision of the prototype that Eugene and I are building. Some of the topics to explore (but not necessarily implement) are listed in my notes from the meeting, shown below. Do not read too much into these, as they are just exploratory and may or may not lead anywhere. However, I think many of you will appreciate some of these ideas. When I return from vacation, these are some areas I may explore: We want to let users access the internals of the Dialog. * We could have the root pane of the Dialog be a DialogPane, and expose this via API on Dialog. * Users could also instantiate this themselves if they don't want to show in a modal/blocking window. * DialogPane could expose ButtonBar as one of its fields, but people can avoid it if they want and change the dialog pane however they want What should we do with show* methods? * Leave as-is? * We can have a DialogType enumeration property and a setDialogType() method or parameter in the constructor * We could have subclasses of Dialog for ActionDialog, ChoiceDialog, TextDialog? * If DialogPane is introduced, we might not be able to use show* methods, as we need to set the defaults into DialogPane before getDialogPane() is called - and this is difficult if the default values aren't set until show*() is called. Should we use Optional - it is not something that JavaFX uses elsewhere. Action should use Image, not Node, for the graphic property - this allows us to get rid of the graphicFactory approach Need to propose API for creating Button, MenuItem, etc from Action Need to work out what to do with the static SetType and SetSizeIndependent methods of ButtonBar - do they have a better home when ButtonBar is moved into JavaFX? Can explore whether ButtonBar should be a layout rather than a control, also, can it deal with Node, rather than ButtonBase? Action on Dialog should be static, not instance field - need to go back to the locking approach. This is to help improve findability of the default actions. Need API to specify modality - question about how to do in lightweight? Need API to getOwner() on Dialog Need to explore a better name for masthead? Maybe header? Lightweight needs to be punted until glasspane is supported, but don't want to introduce API that precludes lightweight support in the future. Might want to leave lightweight implementation intact for now to keep us honest. Might want to add Dialog.cancel() (and return Dialog.ACTION_CANCEL / null), and remove hide(). Need to explore API for non-blocking dialogs (Should create a 'text find/replace dialog' like in Eclipse/Microsoft Word to prove the concept)
27-06-2014

I have a question about non-blocking/blocking vs modality. Non-blocking is not something I really grok. As I understand it non-blocking means that you do dialog.show() to show the dialog, and the dialog is shown, and then show() returns immediately, so that the code after the call to show() will run before the dialog has been closed. Is this correct? I am curious what use cases people use this for.
27-06-2014

@Scott, I agree with that - I could see adding a getOptionButtons() method (maybe protected). Also maybe a protected buildDialogUI() method.
27-06-2014

@Jeff The issue I had with JOptionPane was the inaccessibility of the buttons. You have to do ugly hacks if you want to disable the OK button until a valid value is entered.
27-06-2014

I'd be curious to hear a use case that wouldn't work with the API I provided. As mentioned above, with the "Content" attribute, you could even turn SceneBuilder into one big dialog panel with a few lines of code: // Run SceneBuilder document pane in dialogbox and save on user confirmation DialogBox dbox = new DialogBox("SceneBuilder"); dbox.setContent(mySceneBuilderDocPane); if(dbox.showConfirmDialog(focusedNode)) mySceneBuilderDocPane.save(); It really is just an objectification of Swing JOptionPane. Of all the things I've seen replaced in Swing, I've never heard of a JOptionPane re-write or replacement (despite the flaw in its static method approach).
27-06-2014

@Scott: As long as the right things are exposed through a simple API, it can be built on to produce a more sophisticated kind of dialog. I think that should be the goal, rather than making the base API too sophisticated at the outset. I should clarify here. I used "sophisticated API" when perhaps I should have used "open API". I am off the same mindset as you Scott that as long as you expose the right things, you are good to go for the more sophisticated use cases, as well as the simple ones. Apologies if I confused people with that. The content is a good example -- always a Node as you say. A simple API on top of that can then take a string argument and stick it in a label and then pass the label as the content. That was actually the change I asked Jonathan for in TableView for the message to show when no data is available to the TableView :-) (the first version had just a string, now there is a node). And when I say "pushed", Jonathan agreed in 2 seconds, so it was more like nudged.
27-06-2014

As long as the right things are exposed through a simple API, it can be built on to produce a more sophisticated kind of dialog. I think that should be the goal, rather than making the base API too sophisticated at the outset. It can be as simple as making sure certain methods are protected instead of private. I sent a quick hack to Jonathan that had a hook for setting the return value and dismissing the dialog for example. The "content" is always specified as a Node (just use a Label if you want plain text). You could get the complete dialog Pane that would be the content of a dialog window before showing the dialog. From it you can get access to the standard buttons via Node's existing "lookup" method. Rather than be restricted to certain types of message (error, warning, information, etc.) you can specify a custom graphic as well. (Just another Node) The Dialog would take care of the basic layout and provide the helper methods for blocking until a choice was made, etc. If you wanted to do everything custom, just say no graphic, no buttons, and do everything in the content Node.
27-06-2014

Exactly Graham, Anything worth doing is worth doing right. And given earlier experiences with Java API:s the first version will be tweaked at best. The initial API will set the level.
27-06-2014

@Jeff: I wanted to post one last time to advocate for simplicity (though I seem to be in the minority). I don't understand the need to architect a sophisticated mechanism to handle advanced use cases at the expense of us DialogBox commoners - these situations are relatively rare and may be better addressed by simply having the class create and manage it's own stage and stage lifecycle (though my API offers a fine solution for this too). Are they rare? Or do people simply not do them because most existing dialog toolkits make it hard/impossible to do? I am guessing that they are not as rare as you might think. In business applications, yes rare, in scientific and data intensive applications, not so much would be my guess. Also it's not a choice between simple and sophisticated -- you can have both if you design things carefully. A good example is NIO. It's complicated, especially if you don't need asynchronous I/O. But all the regular IO can be implemented as another API layered over NIO to get the simple synchronous case. @Derek: I agree with @Jeff - attempting to get all the sophisticated elements in, especially in the initial release, could limit the usability of the API. If we can hit 80% of the common use cases, then I think it would be a success. The problem is that if you don't do something sophisticated to start with, you may not be able to expand the API later to handle more sophisticated use cases. You then force people to make their own framework for complicated dialogs which defeats the purpose, and which then gives you two look and feels for dialogs.
27-06-2014

Thanks @Eric & @Derek - I should have also mentioned that I use this API in ReportMill and SnapCode for dozens of cases and messages, confirmations, options and inputs - as well as some advanced cases with a custom FontChooser, ColorChooser and a Commit/Update panel and more. It is simple and it has never let me down.
27-06-2014

I do agree that this API should be simple in it's design. Should allow for things like: Informational Warning Error Confirmation and then things like in controls fx - showWorkerProgress where it attaches to a long running background and closes when complete. I agree with @Jeff - attempting to get all the sophisticated elements in, especially in the initial release, could limit the usability of the API. If we can hit 80% of the common use cases, then I think it would be a success. If the popup/window has more full featured elements, is it truly an Alert? Or is it more of a custom window that would be easier to manage by creating application specific classes to manage?
27-06-2014

@Jeff I share this simplicity approach. Your API would be fine for a tool like Scene Builder.
27-06-2014

It should be simple to USE. That doesn't mean it needs to be limited. Good API is easy to use but doesn't fall short for every kind of customisation.
27-06-2014

I wanted to post one last time to advocate for simplicity (though I seem to be in the minority). I don't understand the need to architect a sophisticated mechanism to handle advanced use cases at the expense of us DialogBox commoners - these situations are relatively rare and may be better addressed by simply having the class create and manage it's own stage and stage lifecycle (though my API offers a fine solution for this too). I thought the API I posted had the benefit of being simple, self-contained, extensible and very similar to Swing (which also helps with porting efforts). Swing's only real fault was trading a conventional instance based approach for a sea of static methods.
27-06-2014

To everyone - I know it is unusual for one to announce their vacation plans in a Jira issue, but given how active this issue is (and how many watchers there are), I wanted to post that I am taking a vacation from Wednesday, 2nd July through to the end of Thursday, 10th July. Of course I hope that you all continue discussing and revising the ideas being put forth, but it is likely that my input will be minimal, if not non-existent during this time. When I return dialogs will be my number one priority, so I hope we can all reach a comfortable middle-ground and I can get cranking on the code. Finally, thanks for all your comments and discussion up to this point - it is all taken on board and helps to shape the direction things go. This has to have been one of the more active and in-depth Jira issues I've seen in my five years at Sun / Oracle, so keep up the good work :-)
27-06-2014

@Eric Thanks for your feedback and descriptions of your use cases in the Scene Builder. I have attached a zip file of the latest working code from the ControlsFX fork that Eugene and I are working in. Package naming, etc is still all wrong, but in general the API is in a fairly good place (in my opinion, anyway). I apologise in advance for it not being packaged in an overly friendly way - hopefully in the next few weeks we can get it (in some form) into the 8u40 repo for easier testing and feedback. Nonetheless, I really do look forward to your feedback! If you have any troubles in using or understanding the API, please feel free to email me privately. If you have feedback that the group may benefit from, please leave comments in this jira issue.
27-06-2014

@jonathan Zip of the prototype code would be of interest : we could try replacing Scene Builder's own dialog classes by the ones proposed in V3 spec. For info, Scene Builder has its own variant of Dialogs (another one!). It is tailored to its specific needs. For example, the "Do you want to save the changes…" dialog is obtained using our AlertDialog class like this: final AlertDialog d = new AlertDialog(getStage()); d.setMessage(I18N.getString("alert.save.question.message", getStage().getTitle())); d.setDetails(I18N.getString("alert.save.question.details")); d.setOKButtonTitle(I18N.getString("label.save")); d.setActionButtonTitle(I18N.getString("label.do.not.save")); d.setActionButtonVisible(true); We also have ErrorDialog (extending AlertDialog) which reports an error and (optionally) the corresponding exception stack. final ErrorDialog d = new ErrorDialog(getStage()); d.setMessage(I18N.getString("alert.save.failure.message", fileName)); d.setDetails(I18N.getString("alert.save.failure.details")); d.setDebugInfoWithThrowable(x); d.showAndWait(); Parent class of AlertDialog is AbstractModalDialog : this class can be subclassed to provide a fully customized content (but still having our three OK/Cancel/Action buttons). Looking in Scene Builder code, it noticed the following: 1) we have 37 occurrences which creates an AlertDialog/ErrorDialog 2) we have 2 customized dialogs (i.e. extending AbstractModalDialog), one being used one time, the other one used three times. I guess it shows once more that predefined/alert dialogs are the key players here and that API design should favor their usability first. Even if it means a bigger API for the custom dialog…
26-06-2014

@jonathan > For example, how would a user do a traditional Yes/No dialog? DialogContent can return any type. And if it doesn't have something to return, like a String, then it simply return Optional<ButtonType>. Super simple. :) Btw, I am now using this myself in my app, so thanks for making me design a new one in JavaFX! :)
25-06-2014

(Jonathan asked in relation to Dialogs returning any kind of value, how a traditional yes/no dialog could be done): In my simple API there's a top level DialogPane class that only provides the basic functionality (returning values, handling modality, on-screen positioning, providing a Node). Users are free to subclass this to add additional functionality, which can be very specific dialogs that are used only for one purpose (anonymous subclass) or reusable ones that can have some configuration: new DialogPane<R>(); // empty dialog, must be customized, R = return type new InformationDialogPane(String message); // Shows single line of text + OK button (but doesn't look like a System dialog), R = Void new SystemDialogPane(String title, String message, Button... buttons); // Shows a system dialog, R = Button public enum Buttons { OK, CANCEL, YES, NO, etc... } Now, each of the above dialogs can optionally return a value which can be obtained using a getResult method or through the convience of static methods on a Dialogs class: Button button = Dialogs.showAndWait(new SystemDialogPane("Warning", "Delete important files?", Button.YES, Button.NO)); // shown modal Future<Button> futureButton = Dialogs.show(new SystemDialogPane("Warning", "Delete important files?", Button.YES, Button.NO)); // shown non-modal, obtain result using callback, Future, overriding onClose or adding a callback (for example). Any number of convience DialogPanes can be created. SystemDialogPane would obviously be part of JavaFX itself (or some hierarchy of classes that deliver this functionality in parts, requiring less and less configuration for the most specific classes). new TimeOutDialogPane(String unimportantMessage, int displayTimeMillis); // Shows a message with OK button, with a progressbar that counts down after which it closes automatically. etc..
25-06-2014

Whilst reviewing everyones feedback, I've been continuing to refine the prototype with Eugene, and I wanted to post an updated JavaDoc for people to review, here: http://www.jonathangiles.net/javafx/dialogs/v3 The changes are relatively minor, it's more refining of an action-based (and non-fluent) API. No one should take this as the final API: it is far, far away from being anywhere near final - but it is my job to progress what I perceive to be the best approach, and as with last time, I invite you to tear to shreds this API, pointing out where it fails your use case. Perhaps the biggest change is the addition of API to Action related to the graphic property. This was necessary because I realised there is no way for an Action to have a Node graphic property that can be reused across multiple controls (because of JavaFX's insistence that a Node only exist in one place in the scenegraph, and the lack of any API to clone or duplicate a Node). As a side note, this was avoided in ControlsFX by having a Duplicatable interface, and also special-casing the ImageView case (by taking out the Image and creating a new ImageView with the shared Image. If there is any interest, I can also post a zip of the prototype code, for people to play with and modify to their hearts content.
25-06-2014

@Jonathan: So my use case is as follows. It started with the following -- our application has a bunch of tabs, each one of which is a sort of workflow designing tool. When the user hits “run” in a tab, the workflow for that tab starts in the background. At this point our application pops up a dialog that has a progress bar on top, and a cancel button below it (call this the “SingleDialog”). The dialog blocks access to the underlying tab (but not other workflow tabs). When the user hits the cancel button the workflow is cancelled, and the dialog is closed. I think we did this version in ControlsFX actually. Then one of our workflow tabs had an unusual feature that, when the user hits run, several background workflows are started. That meant we had to change our popup dialog that appears when they hit run. So we thought ok, we have a dialog which is an HBox which contains N SingleDialogs layed out left to right, where N is the number of background workflows created. The cancel button for the N-th SingleDialog cancels the N-th background workflow, but does NOT close the overall dialog — that only happens if all N are cancelled. The HBox becomes the dialog, blocking access to the underlying tab. Doing this was a bundle of work because we couldn’t re-use SingleDialog, since it wasn’t a scene graph node, it was some other sort of thing. Now we actually have a third use case, where hitting run in a tab starts up something like 50 background workflows. We no longer want to put the 50 SingleDialogs in an HBox over our tab. We want a glass pane over the tab, blocking access to it, but we want to put the SingleDialogs into some kind of ListView on a slide out pane on the side (we may even have a TreeView as there is some organization on the SingleDialogs). I could of course code all these “new” dialogs myself from scratch, but it seems like a lot of work. I have to code up the internationalization of “Cancel”, rather than simply re-use the one in the Dialog API, I have to make my own glass pane, rather than use the one in the Dialog API, I have to make my own button order (if I had more than one button), etc. If I could re-use the existing Dialog functionality it would be much simpler. And to me all I am doing is presenting a bunch of progress dialogs in a slightly unusual way — in essence I have a different view (in the MVC sense) of a dialog model. If the functionality of the glass pane, the creation of the buttons, the sort order on the buttons, the close behavior, the getting of the Node representing the content of the dialog, etc, were all orthogonal to one another. I could build my “strange” dialogs, as well as the standard ones.
25-06-2014

I haven't tried the prototype yet, but Fabrice made a point that applies to me. I tend to use modal dialogs to block user input and am less concerned with blocking execution. I'm not even positive what the guarantees are (if any) in terms of models being modified when a modal dialog is showing. For example, if a Task<?> completes while a modal dialog is in view, what happens to the model updates that get marshaled back onto the UI thread? Do they get deferred until the dialog is closed? Will the same behavior apply to lightweight dialogs? API wise, I like return types that force the correct handling of the result. For example: Optional<T> show(); Future<Optional<T>> showNonModal(); ...vs void show(Consumer<Optional<T>> resultConsumer); void showNonModal(Consumer<Optional<T>> resultConsumer); I find the first way to be less error prone since all of the behavior is communicated via the API. However, I also think Fabrice makes a good point about creating lower level dialogs that control the showing and hiding of the dialog. I've done this with my own (very messy - unfinished) login dialog using ControlsFX. Once my dialog is shown it gathers credentials and authenticates using a Service. The dialog isn't hidden until 1) the service completes successfully, 2) the service completes with an unrelated error, 3) the user cancels the login. With a non-modal dialog, I'd be able to do something like: hide(); future.setResult(...); However, I'd also need to be able to block input independent of the dialog's modality for that to work. Since I'm essentially using modality as an easy way of blocking user input, what I end up doing is less than ideal; I back the dialog with a model and interrogate the model after the call to show() returns. I discard the result from show(). The consumer based approach in my example above would also work since I could do something like this in the dialog: hide(); resultConsumer.accept(...); I don't think that's as good an API though. Specifically, it assumes the user understands the difference between modal and non-modal, including the potential difference in the execution order of the code following their showXXX(...) calls. The first way forces them to handle the non-modal case correctly. Would there be any benefit in distinguishing between modality and input blocking?
24-06-2014

@Will Herrmann: That said, I'm fine with having all of these independent composite pieces that you describe as the base if that is what everyone desires, but I think there also needs to be some way of bringing up prefab dialogs (as could be done with Swing's JOptionPane) that hides all that complexity for those who 98% of the time just want a simple Yes/No/Cancel dialog. I think there is room for both, but it's important to myself and other programmers that the simple version be there for those who use it. I agree with this. I am not saying only have the "composable dialog" setup -- that would be a bit of a nightmare, and as Jonathan suggests a nightmare that no-one would use (which rather defeats the point)! I am saying you have the composable setup as the basis, and then you have methods/classes whatever to make the simple/standard/common cases, that are implemented under the hood by calling the composable setup. And at a guess these methods will be all the standard dialogs that people find useful for your 98%. @Will Herrmann: Also, one thing that hasn't been brought up is that prefab dialogs ought to respect the conventions of the operating system. For instance, an OK/Cancel dialog box on Windows has OK on the left and Cancel on the right, but on OS X they are switched. Having prefab dialogs that respect these sorts of things means that programmers can have dialogs that look right on the proper platform, without having to worry about these sorts of things. People will probably hate my suggestion for this :-) To me a button ordering like this is just a sort order on a collection of buttons. Since some dialogs don't have buttons they shouldn't have to worry about this. But for those that do we provide a standard sort method that sorts according to the platform preferences, and then people can use this as they wish (but they could use other sort orders if they want -- it's just a lambda essentially). The sort method is not in the dialog creation chain -- users sort their buttons before calling the Dialog creation code. For common cases like OK/Cancel dialogs the convenience method that are provided as above, will call the standard sort routine for the platform, and then call into the composable Dialog layer with the buttons already sorted. Hope that makes sense ..
24-06-2014

@Will Herrmann: Regarding OS-specific button placement, I have mentioned it indirectly a few times by referring to ButtonType (in this Jira issue, but also in the FX Experience post), but I understand that it can get lost in such a long discussion. You might want to look at the ControlsFX ButtonBar / ButtonType API here: http://docs.controlsfx.org In short, the approach is to annotate each button via some API (e.g. ButtonBar.setButtonType(okButton, ButtonType.OK)). This indicates that the Button is an OK button. When the ButtonBar comes to lay out the buttons it contains, it can do so using OS-specific placement. This is something that is already handled in ControlsFX dialogs, and certainly something I would like to see included in JavaFX (whether or not we expose the ButtonBar as a separate control is another question. My preference is yes, but there is always a push for less API, so it may not survive the chopping block). ControlsFX also pre-annotates the prebuilt Actions, so Dialog.ACTION_OK is ButtonType.OK, Dialog.ACTION_CANCEL is ButtonType.CANCEL, etc.
24-06-2014

@John: The point that you and Mikael raise about return types is interesting. It would be interesting to see a few more code examples of your suggestion approach, if possible. For example, how would a user do a traditional Yes/No dialog? @Graham: You've presented an alternative approach, but I'm worried that such an approach will result in a lot of API that is used relatively infrequently, and that such an approach has negligible gain (although I'm happy to be convinced otherwise). Your example in an earlier comment was the following: "To see what I mean by this consider a controller of three long running operations. The controller could consist of an HBox with three cancel dialogs in it, one dialog per process. But I can't do that with most dialog kits, because I can't get the dialogs as regular nodes to put into the scene graph. Why? Because most toolkits think of dialogs as popups, and combine the construction of the dialog as a node, and it's showing on the screen in some way. I would like to see the construction of a dialog as a node, and how you want to show it/use it, to be entirely separated to increase flexibility." My question is: what do you really want to show in your 'long-running process VBox'? It seems there are three possible answers (so please clarify for me): 1) Are you going to stack the root node from three pre-built progress dialogs into a VBox? 2) Are you going to take a subset of the pre-built progress dialog (e.g. the progress bar and cancel button) based on your suggested API? You might even create what you want and then lay them out as you expect? 3) Are you going to create a custom panel for each process based on a ProgressBar and Button? It seems to me that: Option 1 is totally wrong as you'd end up with three stacked dialog boxes confusing the user. Option 2 seems weird if you use the pre-built progress dialog (as the progress bar and buttons would be separated vertically, and you'd expect the cancel button to be to the right of the progress bar, as shown in my attached screenshot from IntelliJ). If you go to the effort of composing a dialog based on sub-components exposed through an API, that seems reasonable, but it sounds like it is more work than option 3 (and is there anything to be gained)? Once you get to the point of doing option 3, you're entirely custom anyway and so the dialog API seems irrelevant at this point? It's quite possible I'm missing something important, so please do let me know. It would be interesting to see some sample code of how you imagine this to work. Thanks!
24-06-2014

@graham matthews: You wrote that "Dialogs have all sorts of uses outside the standard Yes/No/Cancel modal situations", but at least for me, that's 98% of what I use dialogs for. So for me, ease of use is far more important than flexibility. That said, I'm fine with having all of these independent composite pieces that you describe as the base if that is what everyone desires, but I think there also needs to be some way of bringing up prefab dialogs (as could be done with Swing's JOptionPane) that hides all that complexity for those who 98% of the time just want a simple Yes/No/Cancel dialog. I think there is room for both, but it's important to myself and other programmers that the simple version be there for those who use it. Also, one thing that hasn't been brought up is that prefab dialogs ought to respect the conventions of the operating system. For instance, an OK/Cancel dialog box on Windows has OK on the left and Cancel on the right, but on OS X they are switched. Having prefab dialogs that respect these sorts of things means that programmers can have dialogs that look right on the proper platform, without having to worry about these sorts of things.
24-06-2014

@graham matthews: That's exactly my point of view!
24-06-2014

> I see a Dialog as a way to draw the user's attention and to make it easy to block input. Yes/No/Cancel type dialogs are imho just what > *business* applications use a lot, but those are not the only applications. Yes exactly. For me the critical thing is NOT to identify the common use cases and build an API that makes it easy for such use cases. That approach makes it hard for "non-standard" use cases. That was the biggest problem with Swing -- the hoops one had to jump through to make Swing do non-standard things ... For me the critical thing is to factor dialog requirements into independent composable pieces. For example the result of a Dialog should be independent of the buttons, since some dialogs don't have buttons. Whether a dialog is shown in a window or lightweight is independent of whether it's modal or not. etc Build a set of orthogonal capabilities, build a set of ways of composing them, and *then* build the standard cases as a set of choices of these capabilities composed in certain ways. I know that sounds terribly "abstract", but I guess I am just saying that flexibility is more important than ease of use. Dialogs have all sorts of uses outside the standard Yes/No/Cancel modal situations,
24-06-2014

> @John Hendrix: Your API suggestion uses integer return types, based on the position of the button. Do you hard code the expected position of your confirmation button? If so, have you tested your dialog works when run in a RTL environment? I'm interested in your findings in this case (which is one of the concerns I note in my earlier blog post). Jonathan, the API I'm using is very free form (it doesn't need Buttons). The Integer return value in this case isn't even a Button position but more the "result" of the Dialog, which can be anything (in the example it is a resume position for the Movie that was selected, in seconds). A CookieDialog for example might return a subclass of Cookie depending on what the user chooses (from a ListView for example, no Buttons involved). I see a Dialog as a way to draw the user's attention and to make it easy to block input. Yes/No/Cancel type dialogs are imho just what *business* applications use a lot, but those are not the only applications. So, I donot hardcode positions in the "base" DialogPane, as there is nothing to hardcode (although subclasses can definitely do that). Subclasses would need to provide support for RTL.
24-06-2014

@Scott - I forgot to answer your question about the purpose of Actions in dialogs, given that they don't seem overly relevant. I have a few quick responses to that (I'm running out the door as we speak), so please pardon my succinctness: 1) You are correct, Action is much better suited to be used elsewhere in the API, where a single Action is used to create multiple controls. 2) In my experience, the frequency with which an Action creates more than one control is actually really, really low. Again, in my experience, it is actually more the case that it is just convenient to extract out Actions from your gui code so that they can possibly be reused, even if they aren't. 3) The biggest question (in my mind) for dialogs is how do you specify the buttons to show in a concise way that allows for the highest degree of configuration (without going overboard). Action seems like a good candidate, even in the case where it is only being used to create a single Button in a dialog. 4) Getting Action into JavaFX for dialog also allows for Action to permeate the rest of the UI toolkit, where, as you note, it can be more useful. 5) Doing this allows for a common API across JavaFX for describing actions. Also, to answer your comment about validation: this is my belief also, and it is how we do it in ControlsFX (especially in terms of the wizard prototype).
24-06-2014

@Scott - thanks for clarifying. I had assumed this is what you meant, but it always good to be certain. It would be interesting to see a mockup of how you see this approach working. My concern is that it could lead to relatively verbose dialog creation / customisation, as the approach (I assume) would be something along the following lines: String[] buttonText = new String[] { "Print", "Don't Print", "Format" }; // These of course need to be internationalised String[] buttonId = new String[] { "print", "cancel", "format" }; // These should NEVER be internationalised! Dialog dialog = new Dialog("Title text", "message text", buttonText, buttonId); String result = dialog.show(); if ("print".equals(result)) { // print! } else { // .... } In the worst case (i.e. when the user wants to modify the action of the buttons such that pressing them doesn't result in the dialog closing), they would have to write something like this, I presume (please ignore my crappy example, my point is to say that sometimes people want the dialog button to cause actions other than hiding a dialog): Button printButton = dialog.getButton("print"); printButton .setDisabled(false); printButton .setOnAction(e -> showPrintDialog()); Button formatButton = dialog.getButton("format"); formatButton.setDisabled(true); formatButton.setOnAction(e -> showFormatDialog()); Let me know if I misunderstood your suggested approach. An Action-based approach for the worst-case scenario above would be something like this: Action printAction = new DialogAction("Print", ButtonType.OTHER, event -> showPrintDialog()); Action dontPrintAction = new DialogAction("Don't Print", ButtonType.CANCEL_CLOSE); Action formatAction = new DialogAction("Format", ButtonType.OTHER, event -> showFormatDialog()); Dialog dialog = new Dialog("Title text", "message text", printAction, dontPrintAction, formatAction); Action result = dialog.show(); // if we don't have custom event handlers (like in the simple example above), we could now compare actions if (printAction == result) { // print! } else { // .... } Finally, please excuse the Jira coding - I hope this makes sense :-)
24-06-2014

@Jonathan 1) I think we should use the API that is available and people will learn Optional if we use it. :) 2) ButtonType is much like ButtonType in ControlsFX and I use the MigLayout button ordering. Buttons of the same type is no problem, you just have to get the Dialog and compare the button instances (e.g. no strings!). This should however rarely be needed but it's important that the use case can be solved. One can also solve this in other ways basically using classes and not enums. Of course you can also just button.setId(..) and add the content can use .lookup(..) to get it. 3) Setters work great for this version of the API. Just change the fluid methods to setXxxx. If it's possible maybe the setters can return this, or would that not work with FXML? 4) If you have a custom button you will also have a custom DialogContent. It would be strange otherwise. They can interact in many ways. Either connect them before creating the dialog or just have the DialogContent look them up from the Dialog class (there's a method for that which looks them up by CSS ID) which can be done when the Dialog passes itself to the DialogContent class at showtime.
23-06-2014

I did not intend to use button text for the ID. That wouldn't work well for localized text. The ID must be separate. I'm not sure I like an ID in an Action though. IDs must be unique within the scene. One good thing about using the ID is that it is already part of JavaFX API. CSS works with it already. There is already API to get a Node based on ID. If we have standard buttons (yes, no, ok, cancel) then they will have standard IDs, regardless of the text shown in the button. As I mentioned, the problem is when the dialog/alert is lightweight. It becomes harder to use a standard ID and be sure it is unique in the scene... Multiple lightweight alerts happening simultaneously would mess that up... for heavyweights it works very well though. I'm not sure I see the benefit of using Actions for dialog buttons... I see Actions as beneficial for operations that could be accessed multiple ways (menu, button, keystroke), but the buttons to dismiss a dialog would never be used that way in any of the cases I can imagine. E.g. The Open menu item would be for the action that shows the dialog, not the action that happens when you click the open button on that dialog. I think validation *must* be done before pressing OK whenever possible. It makes of very clumsy UI otherwise. If it needs to be done after the user presses OK, then it would make sense to have an action listener that is installed on the OK button where it can consume the ActionEvent which would prevent the default closing of the dialog. If the event is not consumed, then the dialog would close. This seems consistent with how JavaFX works for other events.
23-06-2014

Now that this jira issue has grown so long, I've just added to the OpenJFX wiki a task list of everything that needs to be done with dialogs: https://wiki.openjdk.java.net/display/OpenJFX/Dialogs This list will grow as more points are made. I think I'm remembering most aspects, but if I've forgotten anything let me know and I'll update it.
23-06-2014

Fabrice, in terms of validation and wizard - this is something that Eugene and I have also been looking into recently in ControlsFX. There is a 'wizard' branch in the repo that has a simple API, and there is an action item on me to review a pull request from Eugene for an alternative API. This wizard branch supports validation, branching, and modifying the state of the actions at the bottom of each page. The way validation is done in the wizard API is of course via the ControlsFX validation API, but in general the approach is to validate as input is received, and to toggle the state of the relevant actions disabled properties when applicable. To give a few more details about how I implemented the wizard: * My API was simple (I haven't reviewed Eugene's yet): There is an ObservableList<WizardPage>, where WizardPage consists of the obvious: a content node, a list of actions, masthead text, graphic, etc. * Unless custom actions were used, the previous / next / finish buttons change state as expected. * There is an ObservableMap<String, Object> of settings. This map is automatically populated from the value of all UI controls on each page. Therefore, at the end of the wizard, the user can just pull the values straight from the map without having to do anything. This works for the common UI controls, and there is an API to add value extractors for other controls (from the top of my head, something like addValueExtractor(Class<T>, Callback<T,R>) In other words, I have looked into this area, but it isn't clear to me yet if wizards should be considered part of dialogs, and if so, if it should be considered for 8u40. I am more than ready to implement wizards if desired, I just need 1) to hear from the community that they want this and 2) to be given the go-ahead by my management.
23-06-2014

Jonathan, yes it's good for a highlevel API (AKA predefined convenience methods) where you are actually expecting a response from the dialog and where you expect the action/the button to really close the dialog. This is in use for confirmation dialogs, error dialogs, information dialogs, print dialogs, save dialogs, open dialogs, etc etc. Returning Optional<Action>/Optional<Button> is great especially when the user closes closeable dialogs using the crosshair in the title bar (or the other way I pointed out) because this is not really an action and we do not want to have something predefined here. On the other hand, dialogs that auto-close themselves when clicking an action/a button are not great for a lowlevel API where you can manage what your action do with more finegrain. As others have pointed out there is the issue of form validation, we have 2 cases: - we validate the form as we type -> we need a hook or a callback on the action/the button to disable it/gray it out/change its label or style to indicate there is an error. - we validate the form as we click on the OK button. -> in this case clicking on the ok action/button does not close the dialog yet. We need to perform form validation and if ok close the dialog. If not we need to do the same disabling state change and keep the dialog opened. Then we have also the wizard route : the only action/button that should be returned is the one that ends up closing the dialog (ok, yes, no, close, cancel, exit, finish). Some other actions (next, previous, forward, backward, more, less) actually keep the dialog open so its content is changed to the new state/step of the wizard (which may include changing the list of its actions/buttons). So having a onAction()/onButton() callback and a close() method on the dialog itself could come in handy when programing using a lowlevel API.
23-06-2014

Based on the feedback that has been received in this Jira issue Eugene Ryzhikov and I have been refining our dialogs prototype (based on top of the ControlsFX implementation). I've quickly exported the JavaDoc to http://jonathangiles.net/javafx/dialogs/v2/ although I must note that I've deleted a lot of the documentation because it is ControlsFX-specific and will need to be rewritten. Also, some API lingers from ControlsFX that will be removed, but I wanted to get something out quickly for review, to let people tear it to shreds. I'll summarise the changes: 1) There is no longer a fluent API. Previously there was a Dialogs class that was fluent, but this has been removed. The other important aspect of the Dialogs class was that it was able to 'auto-configure' the default dialogs (that is, it knew the default buttons, graphic, title text, etc for confirm, information, etc dialogs). To continue to support default dialogs, we have added similar API in to the Dialog class. It now has methods showChoices, showConfirmation, showError, showException, showInformation, showTextInput and showWarning. 2) The Dialog class is now both high- and low-level Previously the Dialog class only had the show() method, and this relied on the user (or the Dialogs fluent API) setting all properties appropriately. Dialog still has show(), but as noted above it has a bunch of higher-level API. This high-level API installs default values where they have not been set by the user. This makes customisation of dialogs easy - you can either build up a dialog and call show(), or you can modify the high-level dialog by changing the properties it uses. 3) Action has not yet been removed I summarised in the initial blog post the two most contentious issues - fluent API and dialogs. Fluent API is gone, but so far I'm holding tight to Action, because it remains the best way (in my very humble opinion) to support customising the dialog buttons. Which brings me to.... 4) We heard the feedback about button customisation! The concern with using Action is that it doesn't allow for full customisation of the Dialog buttons. Our current solution to this is to add three new properties to the Action class: id, style, and styleClass. In all three cases we bind the button id/style/styleClass properties to the Action equivalents, and from there you can either lookup the node, or even better, style it directly from CSS. I should note that Eugene and I are a little unsure about id being on Action (it seems odd to have one Action id possibly map to multiple nodes), but we can look into that further if Action is accepted. 5) We have not yet added convenience constructors to Dialog We are interested in hearing what convenience constructors you want to see added to Dialog. One possible series of constructor would be the following: owner owner, message owner, message, title owner, message, title, masthead owner, message, title, masthead, Action... Anything more than this and we start to get into constructor overload hell, but I am happy to add tweak this suggestion. Let me know. ====================== Code examples The code is as you'd expect: non-fluent, setter based, and with Actions: // Simple confirmation dialog: Dialog dlg = new Dialog(stage); dlg.setContent("I was a bit worried that you might not want them, so I wanted to double check."); Action response = dlg.showConfirmation(); // Simple choice dialog: Dialog dlg = new Dialog(stage); dlg.setMasthead("Name Guess"); Optional<String> response = dlg.showChoices("Pick a name?", "Jonathan", Arrays.asList("Jonathan", "Julia", "Henry")); // Custom dialog as per the FX Experience blog post
23-06-2014

Fabrice - it's been a while since I've used dialogs in The Real World, but in my experience I always wanted to block execution until the dialog was shown - it made using the dialog much easier as you didn't need to perform magic tricks to get the result back from the dialog before the decision what made on the result (which was almost always the following line of code after showing the dialog). But, I've taken on board your feedback regarding non-modal dialogs being important to you, so I will be sure to include that in my design notes.
22-06-2014

Well the way I see this, which may be wrong, most of the time you want to actually block the user, you really want to prevent them from using the UI, which is what modal is made for. I quite rarely see a case whenever you actually want to stop running the code flow, especially if this means somewhat blocking the JFX App Thread. The only case where I can see this happening would be when using convenience methods such as: APredifinedEnumResult result = Dialogs.showConfirmationDialog(<parent>, "Do you really want to overwrite this file?"); // Will return either APredifinedEnumResult.YES or APredifinedEnumResult.NO That would be a blocking call. But this convenience method would be constructed using the more generic non-blocking API so no biggy.
22-06-2014

@Fabrice It seems that the API you're proposing, based on callbacks for all events, suggests that you don't want execution to block on the show() method? This does make it harder for most users, who simply want to stop code execution until the dialog returns. In this case, the user has to code in special handling for the common case. I like your 'click outside of the dialog' suggestion. This would be a nice addition to the lightweight dialogs in ControlsFX, and if we get lightweight dialogs in JavaFX, there as well. I should also add in terms of styling dialogs - in ControlsFX the lightweight and heavyweight dialogs are styled exactly the same using CSS - so you get (almost) exactly the same visuals in either case. In terms of native dialogs - I don't believe this is in scope at all for JavaFX 8u40 - the goal is JavaFX-specific dialogs. This means the dialog content is entirely rendered using JavaFX controls, and the extend of the native integration (like in ControlsFX), will be using native titlebars (or a JavaFX cross-platform titlebar if desired).
22-06-2014

@Mikael Grev Thanks for taking the time to work on a prototype. Based on your example code in the Jira, I have a few questions / comments: 1) It's nice to see the Optional API in use. It's something that has been in ControlsFX and something I'll be presenting soon in my second API revision. I hope people are ready for Optional in dialogs! :-) 2) I note you use ButtonType, which if it is anything like the ButtonType enum in ControlsFX (which itself is derived from your MigLayout code), I slightly worry about the situation where a dialog may have two buttons of the same type (which is possibly very rare, but still possible - e.g. in a wizard case where buttons might be of the general type OTHER). I see you have an example (the last one in your comment) where the same ButtonType is used, and I see that in this case it forces a change in the way the API is used - you go from using the returned Optional<ButtonType> to either comparing the pressed button with the provided buttons, or getting the result out of the dialog (which I presume would be the string from the button?). 3) Of course, whilst I'm a fan of the fluent API approach, as I've pointed out it doesn't seem popular to everyone. I also note that fluent API doesn't play nicely with FXML, and to me that is more important than fluent API. As I noted in an earlier comment, we could always have both a fluent API and a setter API (in separate classes), but I imagine that will be frowned upon too for being too much API. 4) When you pass in Button instances via addButton, how do you define what happens when the button is clicked? That is, in most instances the dialog should close, but in some instances it should remain open and respond differently. In the case of the ControlsFX action API, this is handled quite by DialogAction - the default implementation will close the dialog if the DialogAction is closing or cancel action. If a DialogAction is not closing or cancel, the dialog will remain open (of course, the handleEvent method is called in either case).
22-06-2014

Several people are talking about the different values returned by the dialog but I hardly see why the dialog should return any value at all. Ie: in the currently, limited-scope, implementations I've done I've relied heavily on callbacks : final ACustomControlClass dialogContent = ... final Dialog dialog = Dialog.showDialog(<parent AnchorPane>, title, dialogCotnent, Actions.Ok, Action.CANCEL, ...); // In my case here a predefined list of enums that will generate buttons when the dialog's skin is loaded. dialog.setOnOK(actionEvent) -> { final Stuff result = dialogContent.validate(); dialog.close(); doSomethingWithResult(result); }); dialog.setOnCancel(actionEvent) -> { dialog.close(); }); dialog.setOnClose(actionEvent) -> { // Some cleanup operation. }); But that's for me in my very limited use case scenario (task progress monitoring and exception/error handling). Something similar would go with a more advanced and flexible Action API: final ACustomControlClass dialogContent = ... Action action1 = new Action("Ok", "Ok tooltip", okIcon); action1.setOnAction(parent -> { // We need a ref to the parent dialog of the action. final Stuff result = dialogContent.validate(); (Dialog)parent.close(); // Careful if we allow action to be used with buttons and menu items. doSomethingWithResult(result); }); [...] // Here I use convenience method but you could use fluent instead. final Dialog dialog = Dialog.showDialog(<parent window or pane or scene or whatever>, modalOrNot, heavyOrLigth , title, mastHead, dialogContent, action1, action2); Also in my own API, when using lightweight dialogs I have a provision to be able to close the dialog whenever the user clicks on the outside of it (ie: within the blocking pane that covers the scene). That allows to have button-less dialogs (without even a close button in the title bar) that can still be closed by clicking outside of its content (most Adobe products use similar dialogs for their "about Photoshop", "about Adobe Reader", ... functions). Also popping up and out a lightweight dialog could be animated (in my case I use an optional fading effect that can be disabled) but I understand this may make the whole thing a bit too complex and cumbersome to implement and different from the heavyweight dialog (unless those two are actually treated apart from each other in different classes) especially if you prefer to keep heavyweight native like. My preference would be that heavyweight dialogs should be skinnable from CSS just like lightweight and should not necessary match the native windows.
22-06-2014

If someone wants to run my code to see how for instance the enabling/disabling works you need MigPane. Go here: https://oss.sonatype.org/content/repositories/snapshots/com/miglayout/ and download the core and javafx jars and add then to the project.
22-06-2014

Attaching Mikael's dialog implementation, as requested.
22-06-2014

I had to try my suggestion so I made an implementation. I'll mail it to Jonathan for attaching. Note that the impl. is butt ugly because it has absolutely no styling. This is the code that tests it: // Simplest possible Ok/Cancel Optional<ButtonType> pressed1 = Dialog.createMessage("Return to the moon?").show(stage); pressed1.ifPresent(s -> System.out.println("You selected: " + s)); // Normal Yes/no question Optional<ButtonType> pressed2 = Dialog.createMessage("Are you a Festis?") .buttons(ButtonType.YES, ButtonType.NO) .masthead("Important Question Below") .show(); pressed2.ifPresent(s -> System.out.println("You selected: " + s)); // Normal single line input Optional<String> festisName = Dialog.createSingleLineInput("Your Festis name please:").show(); festisName.ifPresent(s -> System.out.println("You selected: " + s)); // Simple choice selection Optional<String> type = Dialog.createSingleChoice("Which kind of festis are you?", Arrays.asList("Blackberry", "Strawberry", "Raspberry")) .show(); type.ifPresent(s -> System.out.println("You selected: " + s)); // Custom text on buttons for standard button types Optional<ButtonType> pressed3 = Dialog.createMessage("Delete All Files?") .masthead("This is not a joke", getGfxNode()) .addButton(new Button("No, don't delete"), ButtonType.NO) .addButton(new Button("Yes, delete files"), ButtonType.YES) .show(stage); pressed3.ifPresent(s -> System.out.println("You selected: " + s)); // Apply support Optional<String> name = Dialog.createSingleLineInput("What is your name", s -> !s.trim().isEmpty()) .masthead("This is a simple query", getGfxNode()) .applyTo(s -> System.out.println("Your name is: " + s)) .buttons(ButtonType.OK, ButtonType.CANCEL, ButtonType.APPLY) .show(); name.ifPresent(s -> System.out.println("You selected: " + s)); // Custom buttons with no sane normal button type Dialog<ButtonType> dialog = Dialog.createMessage("What will you do today?") .addButton(new Button("Buy a Tesla Model S"), ButtonType.CUSTOM_CLOSE_APPLY) .addButton(new Button("Buy a Tesla Model X"), ButtonType.CUSTOM_CLOSE_APPLY); dialog.show(stage); System.out.println("You pressed button: " + dialog.getPressedButton()); System.out.println("You pressed button type: " + dialog.getPressedButtonType()); System.out.println("Result: " + dialog.getResult());
22-06-2014

@Scott Palmer: Your node id suggestion is an interesting concept that I hadn't thought of. It raises two questions for me: 1) How frequently will people need to access the buttons? There are a number of use cases for accessing buttons: styling, changing the action event handler, enabling / disabling buttons. As the frequency with which people need to be retrieving the buttons increases, so does the verbosity of this approach. 2) I presume in the node id world we would simply pass in an array (or varargs list) of Strings that would be set on the buttons in the dialog. I note you say that the return type will be the node id. Is your proposal to add an additional parameter to the relevant methods to set the node id for each button, or do you suggest using the button text as the node id? I think in general, this suggestion can almost be seen as the opposite to the Action suggestion (although I'm by no means implying it is any better or worse!). What I mean is, the Action approach either uses the default built-in actions (Dialog.ACTION_OK, etc) or constructs new Actions up-front, and passes those in to the Dialog, and these Actions are then returned when the dialog is dismissed. The suggestion by Scott is to pass in a list of Strings (text for each button), and to have this String returned as a result of the show method being dismissed. If the user wants to access the Button, they will need (before calling show() and execution blocking) call dialog.getButton(String id) where id is presumably the "OK" or "Cancel" text. From there the developer can interact with the button as desired. However, in writing out the last paragraph one other big issue sticks out to me - in the case of the developer using 'pre-built' buttons (e.g. OK, Cancel, etc), they can't just write something like: String result = dialog.show(); if ("OK".equals(result)) { // user pressed OK, so lets do the work they requested } This won't work, because JavaFX strings are internationalised, so comparing to "OK" is going to fail in some locales. I'll end by saying that I have indeed constructed a bit of a straw man here, as I have assumed that (to keep API simple), the default node id for buttons will be their text string. If instead there is additional API needed for specifying the node ids, then I think we run into additional complexity that most users wouldn't understand what it exists for. In any case, I'm happy to keep discussing this approach, but I do see some hurdles that need to be jumped.
22-06-2014

@John Hendrix: Your API suggestion uses integer return types, based on the position of the button. Do you hard code the expected position of your confirmation button? If so, have you tested your dialog works when run in a RTL environment? I'm interested in your findings in this case (which is one of the concerns I note in my earlier blog post).
22-06-2014

Recopied from my comment from FXExperience.com: Having done (and redone) some lightweight dialog API(s) for a couple of app over the past 2 years, I would definitely prefer a full Action API over using simple strings. First, it’s much more manageable this way when handling I18N text. Using strigs would have people doing switch() on them after and this is a no-no when the content of labels of buttons changes as the language changes. Also, in the lifespan of a dialog, especially when dealing with wizards, the same button may actually change role (ie: “Cancel” becoming “Close” at the end of the wizard) and this can be made feasible if the action has text, graphic, onAction as mutable properties. This is not possible at all with simple strings. As for fluent vs. static convenience method, I really do not care. I went to static convenience methods in my own code, I can adapt to fluent if needed by the time the official API is released. Going fluent seems just like going back to builders which feels and sounds weird because you just eradicated them (because of Generics issues with JDK 8 + memory size on embedded – so there were no issue at all with using a builder-type API)… Damn I miss builders already. ADDED - the problem I foresee with an Action API though is that, well as in Swing, it's very tempting to expand it from Dialog to be also usable with Buttons and Menus which may of course make it too complex to implement and test by 8_u40. But I miss the Action framework from Swing too. It was a nice way to unify menus, buttons and toolbar buttons and control their enabling state from a centralized entity as well as defining the action map for keyboard shortcut.
22-06-2014

Actually, if you have a public static <R> Dialog<R> create(DialogContent<R> content) {...} in Dialog you can have setters in Dialog for the fluid stuff, without fluid API, and still get the type of the dialog result from the content. Still prefer fluid for such a tight and purposeful API though. There's a difference between the decision to not have all kind of stuff have builders and not allowing builders at all.
22-06-2014

If as you say the a fluid API is not possible much of the stuff I proposed can't be realised, mostly because it gets a bit cumbersome without the possibility to carry the generics information through the build chain. show() is just to show what you have set up in the build chain. information, confirm and error dialogs are decided by, for instance, different mastheads. There might be an ErrorMasthead for instance, or a more general masthead that you can give an enum with the "type". My last example shows this. One can also support completely custom "sections" to make it even more flexible. All builder method (except the content ones) simply return Dialog<R>. Content methods look something like this to set the generic type in the chain: public <E> Dialog<E> content(DialogContent<E> content) Note that the declaration is using another type E and there's a need for an explicit cast in that Dialog method to save the content to type R. One can also make this a static "create" method that create the builder and as such sets the generic return type. This might actually be a better way since we can only have ONE content anyway. The DialogContent.getResult(...) should (and I did not do this in the examples above) take the button pressed. That way it knows what to return. Optional is just a suggestion. Either the type returned from the content is always an Optional<R> or it can be any type R, where R can be Optional<Integer> for example. Just a matter of if you want to enforce Optional or not. Buttons can be 'tagged' with either a ButtonType enum or - which is more flexible - through a CSS style class. If style class is used then the content pane can look up the buttons with Node.lookup(selector). The JavaDoc needs to be crystal clear how the standard buttons a tagged though. I don't use non-modal dialogs at all actually (except for help dialogs). But that might just be a matter of style. Other mentioned non-modal dialogs though and I think Future is a good way to solve this. Not sure it's that easy in plain Java without Guava to make a ListenableFuture though, but that should be added anyway... ListenableFuture is the best thing since sliced bread. :) The content pane get a chance to get the buttons from the Dialog when the actual Dialog Node are created since Dialog should call DialogContent.setDialog(dialogNode) when the actual Dialog Node is created. This can be done in many ways though. Button lookup can be made with CSS lookup (as suggested above) or by feeding it a subclass of node that has some .getButtons() method. That limits the options for heavy vs lightweight dialogs though.. The main thing to take away from my suggestion is: 1) No Node related methods to compete with when setting up the dialog, hence the API will be easily discoverable and code completion friendly. 2) You get a result, not the pressed button which means a whole post translation stage is not needed when showing dialogs. 3) The Dialog is a holder for content and there can be many different contents, even custom ones. The content together with possibly a masthead, is the actual dialog type. 4) You can show simple dialogs with one-liners, yet you can make them as advanced as you want, including wizards. 5) Since there's not a myriad of constructors, the API can easily be extended with new features, like mastfeet, left panes and whatnot.
22-06-2014

Also, before I run out the door, I know a lot of people have mentioned that they like and use the lightweight dialogs in ControlsFX, and that they want similar for JavaFX. For those unfamiliar with what I mean by lightweight dialogs, refer to the lightweight dialog pictures in the ControlsFX javadocs here: http://controlsfx.bitbucket.org/index.html?org/controlsfx/dialog/Dialogs.html The thing is, the way lightweight dialogs are done in ControlsFX is a terribly ugly hack. It's good enough for ControlsFX, but not good enough for JavaFX. The way I do it is I force the dialog (as well as its background obscuring pane) into the children list of the owners parent, and then I force the owner to be a child node of the lightweight dialog. If you're familiar with JavaFX scenegraph API, you'll note that getChildren() isn't always public, so in some cases the lightweight dialogs code either fails, or if enabled, uses reflection to pry open getChildren() - although this is no longer the case with the most recent ControlsFX - it just fails to install the dialog in those cases. As you can imagine, this breaks the UI in many circumstances. A much better way of doing this is to have a glasspane that can observe the bounds of the owner node, and draw the lightweight dialog (and its background obscuring pane) over the owner, but not into the owners scenegraph. Unfortunately, there are hurdles to writing a glasspane API, particularly around scrolling inside a Scrollpane, clipping, and effects. There is a Jira issue for this (that I may or may not have hijacked) at RT-37509. If we want lightweight dialogs in JavaFX 8u40, I don't believe we can do it without a glasspane API. If no such API is available, I believe that lightweight dialogs will need to be held back until a glasspane is available. If this is the case, I will of course try to ensure the API is able to support this in the future. The way ControlsFX does this is to have a lightweight() fluent API method, or a setLightweight(boolean) method, and the rest is handled automagically. I hope that eventually we can arrive at that point. If lightweight dialogs are important to you, you should speak up so that we can prioritise their implementation appropriately.
21-06-2014

As always, thanks everyone for your comments. I'm now trying to work through individual comments to understand them in more detail (when time permits). For now I just have a bunch of question for Mikael Grev: It seems the tide (in this Jira issue) is strongly moving against fluent APIs. In any case, I'm keen to ask a few questions about your proposal. Firstly, I note that you have only include a show() method in your example, and you have no API to specify different types of dialog (e.g. confirm, information, error, etc). This means that you're relying on developers to build up these types from the static fields you mention (i.e. the correct graphic and buttons). Is this intentional or do you imagine additional API? Secondly, you've generified Dialog such that show() can return Optional<R>. I see you have DialogContent<R>, and I can see that you'd call that to get the result that is returned from show(), but it isn't entirely clear to me how you plan to use this interface in your examples? What do developers have to do to be able to return a result based on the content / buttons that they provide? Thirdly, I'm interested to understand in what circumstances you find a non-modal dialog to be useful? In ControlsFX there is a NotificationBar control that slides in from the top or bottom of the screen. In my naivity, I would have expected that to be a preferred way of having non-modal notifications, rather than a dialog that takes focus but not modality? Fourthly, you've got a buttons() fluent API that takes DialogButton static fields (or custom DialogButtons via the create() method). Internally you'll be creating the relevant buttons, but it isn't clear to me how you feed these into the content pane so that they may then be retrieved and modified (e.g. disabled), and how you know which button is which?
21-06-2014

There is a rather simple solution for using Buttons with respect to how do you get access to a particular button to tweak it and what do you return to tell the caller which button was pressed to dismiss the dialog. You use the node ID of the button. The only problem would be for lightweight dialogs, as they would need an ID that is unique within the scene. Assuming that can be solved in a reasonable way, I like the simplicity of just getting the ID of the button used to dismiss the dialog and the existing lookup(String id) to get the button should you need to customize it in some way. Heavyweight dialogs would have standard IDs for standard buttons (yes, no, ok, cancel), lightweight dialogs might have to use these as a prefix with a user-supplied unique suffix or something, unless there is a better way. If you pass in your own buttons, then you can be responsible for setting the IDs.
21-06-2014

Hi Jonathan, I would like to add some comments from a more architectural point of view. The new "dialog" should integrate into the understand, feel and code of the standard FX API. This leads to some conclusions: 1. A "dialog" contains multiple controls. So its more a kind of Pane (lets say "DialogPane") in javafx.scene.layout 2. The controls in a dialog should be accessible by standard FX API (buttons, areas, images, borders, ...) 3. The "dialog" should have a clearly specified area of functionality. Avoid overloading it. Its just an information to the user which provides limited feedback (buttons). Everything more sophisticated is available in the FX API anyway. (@Mikael Grev: validation and automatic button disabling is quite nice, but goes against this requirement. I suggest access like I mentioned in #2). 4. The "dialog" (pane) must be integrated into Scene Builder (and its FXML notation) 5. The "dialog" must have full CSS support (e.g. with classes like '.dialog-button-panel', '.dialog-button', '.dialog-image', ...) 6. The "dialog" is prefilled with some standard controls (message, title, icon, button-panel, decorations) 7. There should be "lightweight" (overlaying a Pane, TabPane or Tab) and heavyweight (own stage, movable) dialogs. (I solved this in my 'HalDialog' with two constructors. HalDialog( Stage ) creates heavyweight dialogs while HalDialog( Pane ) / TabPane / Tab creates lightweight ones). 7.1 It should be possible to switch a heavy-weight dialog between modal and non-modal. 7.2 Being modal is not possible for light-weight dialogs anyway. A light-weight dialog can block the underlying pane (I did this in HalDialog by blurring the underlying pane and replacing it with a stack pane which has the underlying pane as child(0) and the dialog as child(1)). 8. Coming to the actions in a dialog. An action in a dialog is done by activating one of the buttons. 8.1 As a follow-up from #3 there should be a very restricted (enumerated) number of buttons like: Abort, Cancel, Ignore, No, OK, Retry, Yes (which should be internationalizable). This also solves the question about the "closing button" 8.2 Buttons should be put into some button panel at the bottom area 8.3 It must be possible (especially for light-weight dialogs) to assign an own event handler (from my personal point of view, it's sufficient to assign one handler to all buttons in a dialog) 9. Additional features: 9.1 setting the effect of the underlying Stage, Pane, Tab or TabPane (e.g. setBlur()) 9.2 having the light-weight dialog with or without a title bar 9.3 Easy integration of some "progress dialog" and a worker If you are interested, I can mail you my HalDialog class. Its well documented and just 600 lines. I'm looking forward to the result :-) Hajo
21-06-2014

Since it came up, here's how custom buttons work for me in a subclass of DialogPane: Button resumeButton = new Button("Resume from " + Formatter.SECONDS_AS_POSITION.format(mediaData.resumePosition.get())) {{ setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { resumePosition = mediaData.resumePosition.get(); close(); } }); setMaxWidth(10000); }}; And in the overriden getResult method: @Override protected Integer getResult() { return resumePosition; } Since the subclass has full control over the DialogPane content, Buttons can do whatever they want, and we're not limited to Buttons either. Here's how a time-out works for the Dialog (the Dialog closes automatically if the resume position information is not found): // Override of onShow, that uses a Timeline to wait for information (40 cycles of 0.1 seconds, 4 seconds total) before closing the dialog // automatically if no resume information was found. Otherwise, the dialog is shown as normal giving the user the option to resume // or start from the beginning. @Override protected void onShow() { timeline.setCycleCount(40); timeline.setOnFinished(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { if(!resumePositionFound) { close(); } } }); timeline.play(); }
21-06-2014

The problem with Actions is similar to too simple layout panes: If you start using them and after a while you find out that they don't do everything you need to do you need to completely roll back and restart with another approach. Ryan, The content pane will be given the dialog (or a proxy) during construction. The pane can then look up any button (by type) and control its properties.
21-06-2014

Just wanted to add some information about how dialogs get used in an application that doesn't have focus most of the time (because it is controlled by something other than the keyboard or mouse). First, lightweight dialogs are a requirement because heavyweight dialogs will flash the taskbar. I created an RFE to make it possible to disable the flashing when a new Stage is shown. I also think there may be a further distinction in dialog types. In my application I often use non-modal dialogs, but these dialogs do block input to other components (by means of replacing the root node in the Scene). From a programmer perspective it is non-modal. From a user perspective it is modal. For example, a dialog pops up when the user asks to start playing a movie. This dialog offers three options: play from start, play from where you left off and cancel. There is no need for it to be blocking the code flow, as each of these options will just trigger the appropriate action. Further, I think that at the lowest level, the Dialog API should just provide a Node that can be customized by the user completely, just to make use of the modal/non-modal logic. In my application the API looks like this: void show(Scene scene, DialogPane<?> dialogPane); void show(Event event, DialogPane<?> dialogPane); <R> R showAndWait(Scene scene, DialogPane<R> dialogPane); <R> R showAndWait(Event event, DialogPane<R> dialogPane); DialogPane is just an empty StackPane with some logic to be modal/non-modal and block input if needed. Children can be added to show content. Subclasses can be created for specialized uses. I could imagine JavaFX having a SystemDialog subclass for basic infrastructure for all the standard dialogs, with standard layout of title, message area and buttons. Example uses are: Dialogs.show(scene, new InformationDialog("No video player was configured.\nUnable to play the selected item.")); resumePosition = Dialogs.showAndWait(scene, new ResumeDialog(media)); Dialogs.show(scene, new OptionDialog("Configuration", options)); Or direct use of DialogPane: DialogPane<?> dialogPane = new DialogPane<Void>() { @Override public void close() { super.close(); System.out.println("Dialog closed!"); } }; dialogPane.getChildren().add(content); In an event handler: public void handle(KeyPressEvent event) { Dialogs.show(event, customDialog); // doesn't block event.consume(); } Finally, I'm in favor of an API that doesn't try to provide full customizability through means of lots of setter/getters. I can already think of a dozen things that won't be in such an API (because they go a bit beyond what people think of as a Dialog). For example, what if I don't want my dialogs to look like a typical system dialog? I'm very much against the "OK" "CANCEL" button thing for example, as they convey no meaning to the user; it should always be something like Save+Cancel, Quit+Cancel, Delete+Cancel... never "OK". So, I think JavaFX should provide standard dialogs for common cases, with limited configurability (limited enough that it could be done mostly with the constructor). Then provide further flexibility by allowing subclasses. Users can create their own class then that handles *their* most common use case.
21-06-2014

Thanks everyone for your feedback. I can't say I've digested all the feedback yet (silly me for posting a big post on Friday night), but it is Saturday night now and I wanted to spend a few minutes to respond, to spur on the discussion. Firstly, I've heard everyone loud and clear how important Scene Builder support is. It goes without saying that Dialogs without Scene Builder support is a total non-starter, so I will be spending some effort in the next days understanding what this implies. From the top of my head, the biggest implication is that a fluent API does not work with Scene Builder / FXML, so a fluent API can not be the sole high-level API (or, it could be replaced entirely with a more standard setter style API). From what I'm reading, people either enjoy using the ControlsFX fluent API, or don't feel that it is necessary (and that it is non-standard). My gut feeling is that a fluent API is not something people are clamouring for here, so my next prototype will probably do without one. If this really upsets you, please do comment! Secondly, there has been some concern about the suggestion of using Actions. The first concern I have heard a few times is that Actions are non-standard and not part of JavaFX, so it makes no sense to have them in JavaFX dialogs. My response to this is that if Actions are added to JavaFX, it would of course be critical to have API that would make them applicable to Button, MenuItem, etc. This would be done in a backwards compatible way - new API would be added, but no existing API would be removed. Whether this is constructor / methods on the relevant controls, or some other means is well off in the distance, but please don't discount Actions as being non-standard (feel free to discount it for other reasons though!). The other concern I note is from Richard, and I may be misunderstanding, but my interpretation is he is saying that an Action can never fully specify a UI control (as that would suggest you'd need all the API of the resulting control to be available on Action!). My response here is that this is true, but it is quite easy to come up with a set of properties that are by far and large the most important, including text, 'long text' (i.e. tooltip), disabled, graphic, and accelerator / mnemonic. This covers, I would say, the 90% use case. The problem with having a getButtons() ObservableList where the user can specify buttons directly on the dialog is that we fall back to needing to return something from the dialog when it is dismissed. In the case of Action, you can return the Action quite nicely. In the case of removing Action and dealing directly with buttons you either have to return an int representing the button position (which is what Swing does, and as I note in the blog post does have some implications), or you return the Button node itself. I don't know what others think, but the thought of being given a Button and doing a comparison on it to determine whether the 'okButton' was clicked seems weird. It also doesn't play nice with the higher-level API where no button is actually specified by the developer, and default buttons are used instead - the API would either need to expose a public static final OK_BUTTON to compare the return result against (which will never work - we don't want this button to be mutated, or ever inserted in the scenegraph, and people will try both), or again, ints would work (in the sense that the API would make sense, not in the sense that I would be happy with this API). I'm not saying that Action is right and having getButtons() (or similar) API is wrong - I'm just trying to point out some pitfalls and hope that people have smart suggestions on how to avoid them. Thirdly, I also note a lot of feedback that people feel it is critical to be able to provide custom functionality for buttons (as opposed to just having them close the dialog), and to be able to toggle the state of the button based on their own whim. I agree that this is important, and would love for it to be possible in our API. My question is, if the Action API is rejected (either due to not being liked, or as part of a more technical review of API before we integrate into JavaFX), how can we offer this functionality? It is the Action API in ControlsFX that enables both of these features in a relatively clean way: the user creates Actions, gives them to the Dialog, and it creates Buttons from them. If the Action disabled state changes, or the Action text property changes, or the Action gets an alternate event handler, the Button is immediately updated on screen. If we don't use Action, we need some other way to hook into this. I will of course explore possible options (one might be to have various callbacks that can be set on a Dialog - although this doesn't seem terribly pretty off the top of my head), but if others have suggestions, I'm open to hear them. Thanks again for all your feedback. I plan to spend my Sunday working on another prototype of API without the fluent API. I hope that you can all help me by responding with your thoughts on what I post above. As I noted in my original blog post, time is of the essence, so please don't hold back!
21-06-2014

+1 to the list of happy ControlsFX users. I agree with / want: 1. Limited method / constructor overloading. 2. A setter API is good enough for me, especially if it makes Scene Builder support more likely. 3. Good "lightweight" support. 4. I'd like to have control over content, button enabling / disabling, dialog closing. 5. Optional return types. How would they work with dialogs that aren't used for input? Ex: an OK (message) dialog. I think Mikael's example would do everything important to me. How does Mikael's #6 work for accessing custom buttons (ex: previous / next in a wizard)? Having non-modal dialogs return a future is a nice idea.
21-06-2014

Just read your blog post, thanks for taking the time to write down your proposed API, I think this is a great idea since you'll get lots of feedback to help you define the best choice. From what I've read from your blog post here is my opinion: 1 - I don't think a fluent API will be a good choice: there's nothing like this for other controls, so it would look foreign (like a 3rd party library was forcefully integrated into javafx) and also this looks a lot like the builder pattern which is in the process of being removed. 2 - I also don't think an Action class will be desired: for the same reasons pointed out in 1, there is no where else on javafx where actions is used so this will be strange to most users. 3 - We need to have a class (like the Dialogs class you mention in the blog post) with property setters and getters for each field so that it would be possible to create a dialog in FXML. My 2 cents, Thanks for your efforts,
21-06-2014

I forgot to mention to 2 in my previous comment: 1- I think it's very important to also be able to create non modal dialogs. From a user perspective modal dialogs can be very disruptive as they don't allow any changes to the rest of the user interface. Some use cases are better of with non modal dialogs. 2- Will there be a chance to choose whether the created dialog is skinned using the native O.S. look? Native looking dialogs give the idea of an app that is better integrated with the native O.S. like native looking file choosers do.
21-06-2014

I think the big problem with dialogs in Swing was the permutations problem. There were four basic types of dialogs (Message, Confirm, Option, Input) with six different parameters (Title, Message, Icon, Content, MessageType, Options) - so JOptionPane ended up with a sea of static methods that were confusing to navigate. I don't think you could go wrong with a simple DialogBox class like this (I love simple): // Constructor public DialogBox(String aTitle); // Options public String getTitle(); public void setTitle(String aTitle); public String getMessage(); public void setMessage(String aMessage); public MessageType getMessageType(); public void setMessageType(MessageType aMessageType); public Node getContent(); public void setContent(Node aNode); public Node getGraphic(); public void setGraphic(Node aNode); public String[] getOptions(); public void setOptions(String ... theOptions); // Convenience methods to set Message + MessageType public void setErrorMessage(String aMessage); public void setWarningMessage(String aMessage); public void setQuestionMessage(String aMessage); // Show methods public void showMessageDialog(Node aNode); public boolean showConfirmDialog(Node aNode); public int showOptionDialog(Node aNode, String aDefault); public String showInputDialog(Node aNode, String aDefault); // Programatic dismissal public void confirm(); public void cancel(); Then most common invocations would look something like this: // Get user confirmation DialogBox dbox = new DialogBox("Sanity Check"); dbox.setWarningMessage("Are you sure you want to do this? It could kill you."); if(!dbox.showConfirmationDialog(focusedNode)) return; Using instance methods instead of static methods gives opportunity to subclass and override various methods. And notice the Content attribute - for the standard case when no Content is provided, it is built programmatically based on the parameters (essentially just the message and either an Option combo, an input textfield or nothing). I've been using this in my JavaFX app for a while and it is working great and makes porting from Swing easy. I even built it on a convenient FormBuilder class that makes building a simple stack of form controls easy, and can also be used for advanced DialogBoxes.
20-06-2014

Thanks everyone for all the comments - I'll spend the weekend processing what everyone has said and will attempt to summarise and respond to all the suggestions as soon as possible. I might also try to implement or at least explore some of your suggestions in forks of ControlsFX, so please be a little patient with me! :-)
20-06-2014

Another angle to keep in mind while designing this API is that it be SceneBuilder (and thus FXML) friendly. We need to be able use SceneBuilder to design the UI for a custom dialog. The simple message boxes might still benefit from some scene builder love. Some terms I've seen that you might want to use to distinguish the use cases (and might make an appearance in the final API) is Alert (or "MessageBox") for the simple guy, Dialog for a windowed dialog (and this Dialog should be Apple "sheet" friendly), and "LightBox" for the "lightweight" dialog. Perhaps Dialog can be used both for windowed and light box varieties. I first came across the name "light box" in some JavaScript libraries (http://en.wikipedia.org/wiki/Lightbox_%28JavaScript%29). I agree with Steve, having fewer convenience methods and the normal setter pattern seems like the way to go (I keep pestering Brian G. to give us some way to construct classes in Java in a fluent or builder manner for free, maybe something will come of it down the road). In any case, the setter approach seems inevitable in order to support FXML and SceneBuilder well. Mikael's points are good. I like the Action concept in principle although it carries with it some baggage. With an Action you have to pick what properties of the final button you want to expose, whereas if you were allowed to customize (or supply) the button itself, then you have all kinds of liberty. I don't like String -> int mapping like JOptionPane. Sorry for the ramble but I'm definitely interested to see what kind of final API you get out of all this :-)
20-06-2014

I am a big user of ControlsFX and really like it. I like the actions API, and I like the fluent API. I could love without either of course, but that is the nature of code. Indeed I wouldn't mind seeing ControlsFX become the JavaFX dialog framework :-) The two weaknesses of most dialog toolkits that I have encountered are as follows (and I would like to see JavaFX avoid these problems). First, lightweight dialogs (so dialogs that not in their own window to use Jonathon's terminology) are nice, but they are treated too differently to heavy weight dialogs (again using Jonathon's terminology, dialogs in their own window). For example with a heavyweight dialog you get an onWindowShown event when the dialog is shown, but you don't for a lightweight dialog (since its not in a window). So if both kinds are to be supported they need to be supported via a unified API -- onDialogShown, etc. Second, there is an over-emphasis on dialogs as some sort of popup thing different to a regular node. To see what I mean by this consider a controller of three long running operations. The controller could consist of an HBox with three cancel dialogs in it, one dialog per process. But I can't do that with most dialog kits, because I can't get the dialogs as regular nodes to put into the scene graph. Why? Because most toolkits think of dialogs as popups, and combine the construction of the dialog as a node, and it's showing on the screen in some way. I would like to see the construction of a dialog as a node, and how you want to show it/use it, to be entirely separated to increase flexibility. graham
20-06-2014

Have done a lot of these dialogs over the years I'd like to share some common findings. 1) I usually want to get a string (single row), text (multi row), date, date range, time, time range, zero, one or more of many choices (as objects that can have a custom .toString()), yes/no. These versions of a dialog should be super simple. 2) I now always disable the OK button for all invalid choices, if any, so the user cannot OK something that is invalid. This means that I don't have to check the validity of the returned result and don't have to show a "you've made some invalid choice, please try again". Increases UX. 3) I now tend to include the help text in the dialog as grayed out text -> no help button and no need to handle more dialogs and if the should be modal or not and whether they should hide with the parent dialog etc. 4) Dialog might be resized (animated) if the choices/content in the dialog changes. Think expand for more advanced options. See how Apple does this for Preferences. 5) I return the result of the dialog (which is interpreted and returned by the content section) as Optional<R> where it is empty if OK or YES was not pressed. I don't like to return the button pressed (unless it's a yes/no dialog). 6) The content panel should be the "meat" of the dialog. It should optionally (if it extends say DialogPane) be fed the dialog (DialogPane.setDialog(..)) structure so it can affect enable/disable of the OK/YES button depending of its content. 7) There should be a few standard DialogPanes to care for the most common dialog types. E.g. StringDialogPane, ChoicesDialogPane and TextDialogPane. 8) I have a .showNonModal() that returns a ListenableFuture<Optional<R>> which works well for non-modal dialogs with minimal API cruft. Fluid works very good for such a specialised use. The Dialog has the options it has and these should not be cluttered with all the choices of the parent type of Stage or similar. Fluid keeps the API discoverable and clean. API such as this would work for me where Dialog is really a builder. Optional<String> = new Dialog() .title("...") .masthead("...") .content(new GetStringDialogPane("")) .buttons(Dialog.OK, Dialog.CANCEL) .show(owner); Optional<Person> = new Dialog() .title("...") .masthead(new MyCustomNodeMasthead()) .content(new PersonDialogPane(myPersonToEdit)) .buttons(DialogButton.OK, DialogButton.CANCEL, DialogButton.create(new SetToDefaultPerson(), DialogButton.OK)) .show(owner); Optional<Boolean> = new Dialog() .title("...") .masthead("This is a warning", Dialog.WARNING) // Second argument is an interface to get an icon node and background. .content("You have been warned for the last time!") .buttonsOkCancel() // Since the API for Dialog is so sheltered for the rest of the platform we might possibly do this to simplify .placement(Dialog.PLATFORM) .show(); // A version without a parent owner should always exist and work. Sometimes you don't have a parent reachable. // Just a simple start interface DialogContent<R> { setDialog(Dialog dlg) // to get the buttons to be able to enable/disable OK, Next, Previous Optional<R> getResult() } As you can see Dialog has a number of static fields of the corresponding types for masthead, buttons and placement. That makes them easy to find for code completion. Note that this API is also made to accommodate a Wizard which basically just switches the content and enable/disable buttons and possibly the masthead. Just my 2 cents. Cheers, Mikael
20-06-2014

Already posted on the fxexperience site, but since this seems more active on the discussion front: Personally I’m a fan of the fluent API currently in ControlsFX – to me it seems like the most flexible approach there. I think it’s very important to be able to specify custom buttons and actions as easily as possible, since having to abandon the API whenever something slightly custom is required and fall back to Dialog is frustrating at best, and can lead to nasty hacks / bugs / shortcuts at worse (we all know it *shouldn’t* happen, but it invariably does.) Perhaps I’m showing my ignorance here, but would a straightforward builder pattern be out of the question? They’ve already existed in JavaFX (ok, most are deprecated now but this means it’s not a new concept), they keep much of the readability offered by the fluent API, and on the face of it it’s really very similar. Having said this, I really wouldn’t be *that* opposed to just a constructor and setters either. Sure, it’s not the flashiest thing on the planet, but it’s still very readable and it’s as standard as it gets (so *everyone* knows how to use it at first glance.) However, I must question why you say there’s certain to be convenience constructors? If it were up to me I’d simply have one constructor, perhaps with the title and the message, forcing people to set all the other properties via the appropriate setter methods. I struggle to see how long, often overloaded “convenience” constructors are really that helpful – they’re as bad as heavily overloaded static methods. And having said that, the only approach I’d actively campaign against is the heavily overloaded methods one – it’s just an absolute pig to have to look up the documentation for what order what parameters come in each time you not only use it, but want to read it as well! In terms of the action API, I must admit I was initially in favour, but then started to think of the wider implications – since there’s many other places actions could be used in this sort of context, would the FX API really be rewritten in every place they could occur? I suspect that would be infeasible, at least until a major release, and I wonder whether it would therefore act as a wider point of confusion. Of course this could be mitigated somewhat by naming it such that it was clear its intended use is restricted to dialogs (DialogAction?) but then again, that seems a bit hacky considering there’s nothing functionality wise that’s affording this – it seems a bit arbitrary.
20-06-2014

One very important aspect that was missing in Swing was a simple way to get access to the confirmation buttons that would dismiss the dialog. I.e. OK or Cancel, or Yes, No, Cancel, etc. We want to be able to get those buttons and easily modify their state. The most common tweak is to disable the OK button until a form is properly filled in. Another reason to get access to the buttons might be to make the text dynamic, perhaps with a binding. For example, the dialog might have a list of items with multi-select enabled and the confirmation button could read: "Update 7 items", where the number of selected items is reflected in the button text making it much clearer to the user what will happen when the button is pressed.
20-06-2014

Thank you for outlining the choices as you see them. And having been using Dialogs from ControlsFX in my POC to move towards Java FX for a desktop application, I think your current fluent API is great and easy to use and read. Quite simple to adopt. I do agree that adding actions may be a bit much for inclusion in JavaFX, the overall general approach of Controls FX is something I would like to see ported to native JavaFX.
20-06-2014

To summarise the current state of things, and to seek further discussion on dialog API, I've posted a rather long post on the topic here: http://fxexperience.com/2014/06/bringing-dialogs-to-javafx/ Feedback is encouraged!
20-06-2014

What you call a ‘high-level dialogs’ is usually described as a "message box" or "alert". And ‘low-level dialogs’ are called simply "dialogs".
20-06-2014

About constructors vs. set/get vs. fluent. Convenience constructors / methods explode as the number of options increase so they should be provided for the most common case and no others. The mistake is to provide a billion of them and thing that they will solve the every problem instead of their intent, which is to address the most common cases. If you expect to configure custom button behaviour and tweak icons, then you should not be using convenience constructors / methods. Looking at get / set vs. fluent, if convenience constructors / methods are avoided, then I don't see much benefit or difference. It seems to be the builder pattern that some people find useful and that can cut down on the amount of lines we need to type, however, builders in FX are deprecated and the fluent API seems to add the pattern back again.
20-06-2014

For those using JavaFX 8.0, another dialogs option is my newly released ControlsFX project, which includes a number of pre-built, modal dialogs, as well as API to build custom dialogs. See http://fxexperience.com/controlsfx/ for more details.
08-05-2013

You are talking about JavaFX 8. Is JavaFX going to step from version 2 to version 8 just to match Java 8 release?
15-02-2013

As per RT-27833 I have now removed the dialogs API from JavaFX 8.0. I have attached the patch and the final code in RT-27833, so that it may be easily imported in the future, and used by external parties in the meantime.
22-01-2013

The version renumbering was well signposted. See here for example: http://fxexperience.com/2012/08/javafx-2-2-is-here-and-javafx-8-0-is-on-its-way/
11-01-2013

Jonathan, I'm sorry to hear that, this seems like such an obviously useful feature, and it's one that basically every other GUI ToolKit has. Hopefully they come to their senses! Until then, we'll give your Dialog from the sandbox a try. Thanks.
11-01-2013

Cory, correct, there will be no pre-built dialogs in JavaFX 8.0. There are pre-built dialogs in the UI controls sandbox and these have been backported to 2.2, but unfortunately I am unable to persuade the powers that be that we should have pre-built dialogs in 8.0.
11-01-2013

@Jonathan: Does that mean that you guys have decided that there will be no Dialogs (i.e. Alerts) in JavaFX 8.0?
11-01-2013

Due to time constraints and different priorities I will be unfortunately removing the Dialogs class from the JavaFX 8.0 repos in the coming weeks. It will continue to be available in the OpenJFX UI Controls sandbox repo, as linked to in a previous comment.
08-01-2013

I should note that I blogged about Dialogs support here as part of the JavaFX 8.0 controls sandbox: http://fxexperience.com/2012/10/announcing-the-javafx-ui-controls-sandbox/ Also noteworthy is that someone has already back-ported Dialogs to work on JavaFX 2.2: http://edu.makery.ch/blog/2012/10/30/javafx-2-dialogs/
01-11-2012

The Dialogs class (as it is currently called) did not make it into JavaFX 2.2, due to lack of time. I have just now pushed my proof of concept Dialogs class into the JavaFX Lombard (aka 3.0) repo, so it may possibly be included in that release. Whilst a long way off, at least with public builds to start soon, you can develop your applications using the JavaFX 3.0 builds and make use of the API (and provide feedback on how to improve it).
31-07-2012

Note that this this can be implemented on top of the public showAndWait() API now that RT-19783 is implemented.
16-05-2012

Reassigning to controls team and upping priority based on the vote count.
16-05-2012

Mailing List Thread: - http://mail.openjdk.java.net/pipermail/openjfx-dev/2012-April/001072.html
06-04-2012

Thank you for you reply, Jonathan Giles I appreciate your work This feature will be included at JavaFX 2.2 I am glad to hear that. I am looking forward to see it. Thanks
02-01-2012

For what it is worth, I have a working Dialogs implementation that is very similar to JOptionPane, although I'm not planning on making it part of JavaFX 2.1, it may be possible to include it for JavaFX 2.2.
02-01-2012

The ability to halt and wait for input is a necessary feature. I think that JavaFX should have a convenient class just like Swing JOptionPane.
02-01-2012

Comments from developer for RT-14951: And for RIA (applet mode at least) , we do need an "internal" popup/alert control such Flex or JS does. Stages "window oriented" are useful for desktop apps, but in a Browser environment (multi tabs...) a flat Dialog control would make more sense. This control should not be draggable out of the parent's bounds, like JInternalFrame did. Moreover, when prompting this control, the background of the parent stage could be blurred for example...
11-07-2011

Consider for Presidio
18-04-2011