JDK-8090865 : Please make Toolkit.enterNestedEventLoop and exitNestedEventLoop public API
  • Type: Enhancement
  • Component: javafx
  • Sub-Component: application-lifecycle
  • Affected Version: 8
  • Priority: P3
  • Status: Resolved
  • Resolution: Fixed
  • Submitted: 2013-11-13
  • Updated: 2017-05-18
  • Resolved: 2015-11-19
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 9
9Fixed
Related Reports
Relates :  
Relates :  
Description
This API can be used to for example allow the creation of Dialogs that donot require the use of a Stage (which itself has the showAndWait() method that makes use of this API).  Stages are not always desirable for this.  Alternatively, a special Pane could be created that offers a showAndWait() style method, but that may limit potential other uses of nested event loops.

The API looks intuitive enough as it is currently, and could be moved as-is to Platform in the future.

Below part of the mailinglist discussion:

---------------

Hi John,

Please file an RFE to introduce this public API.

-- 
best regards,
Anthony

On 11/13/2013 08:35 PM, John Hendrikx wrote:
> On 13/11/2013 16:35, Stephen F Northover wrote:
>> What is the difference?
>>
>> Dialog d = new Dialog() {
>>    public void onClose() {
>>       Platform.exitNestedEventLoop();
>>    }
>> }
>> Platform.enterNestedEventLoop();
> I find the current API to work well, it is just in the wrong package
> tree
>
> Considering I didn't know about nested event loops before, I find the
> solution quite elegant -- leave the old event loop on the call stack,
> and start a fresh one that can be exited to continue again where the
> main event loop was halted -- it's almost like a 2nd thread gets
> started, but there isn't
>
> --John
>
>>
>> Steve
>>
>> On 2013-11-13 5:28 AM, Tom Schindl wrote:
>>> What bothers me with the API as it is today is that I have call
>>> enter/exit, I would find it more easy to work with an API like:
>>>
>>> -------8<-------
>>> WaitCondition c = new WaitCondition();
>>> Dialog d = new Dialog() {
>>>     public void onClose() {
>>>        c.release();
>>>     }
>>> }
>>> Platform.spinNestedEventLoop(c);
>>> ------->8-------
>>>
>>> Tom
>>>
>>> On 13.11.13 11:18, Artem Ananiev wrote:
>>>> I also think it's a good request for public API. In AWT/Swing, people
>>>> had been using ugly workarounds with modal dialogs just to enter a
>>>> nested event loop, until public java.awt API was finally provided:
>>>>
>>>> http://docs.oracle.com/javase/7/docs/api/java/awt/SecondaryLoop.html
>>>>
>>>> http://docs.oracle.com/javase/7/docs/api/java/awt/EventQueue.html#createSecondaryLoop()
>>>>
>>>>
>>>>
>>>> The same is here in JavaFX: unless Toolkit.enter/exitNestedEventLoop()
>>>> is exposed at javafx.* level, people will have to workaround it by
>>>> using
>>>> Stage, or calling into com.sun.javafx.*, which is not good.
>>>>
>>>> Thanks,
>>>>
>>>> Artem
>>>>
>>>> On 11/13/2013 10:15 AM, John Hendrikx wrote:
>>>>> Hi List,
>>>>>
>>>>> Any chance that Toolkit.getToolkit().enterNestedEventLoop() will in
>>>>> the
>>>>> future become public API?
>>>>>
>>>>> I'm currently using this to create Dialogs based on a Pane to avoid
>>>>> creating Stages (which have the nice show and showAndWait
>>>>> functionality).  I duplicated this functionality in a Pane,
>>>>> allowing me
>>>>> to create Dialogs on top of existing Scenes without creating a Stage,
>>>>> and it makes use of the enterNestedEventLoop and exitNestedEventLoop
>>>>> functions in com.sun.javafx.tk.Toolkit.
>>>>>
>>>>> The reason I'm avoiding the Stages is because they donot play well
>>>>> with
>>>>> an application that never has the mouse or keyboard focus (my
>>>>> application is fully remote controlled) -- creating a Stage, even
>>>>> one to
>>>>> just show a Dialog, will cause Windows to try and attract the user's
>>>>> attention by flashing its taskbar button (for which I filed a
>>>>> bug/feature request) and this is undesired.
>>>>>
>>>>> Regards,
>>>>> John
>>>>>
>>>>> (Here's a part of the DialogPane to show and close it:)
>>>>>
>>>>>     public R showDialog(Scene scene, boolean synchronous) {
>>>>>       this.synchronous = synchronous;
>>>>>       this.scene = scene;
>>>>>       this.oldFocusOwner = scene.getFocusOwner();
>>>>>
>>>>>       Parent root = scene.getRoot();
>>>>>
>>>>>       stackPane.getChildren().add(root);
>>>>>       stackPane.getChildren().add(this);
>>>>>
>>>>>       scene.setRoot(stackPane);
>>>>>
>>>>>       requestFocus();
>>>>>
>>>>>       if(synchronous) {
>>>>>         return (R)Toolkit.getToolkit().enterNestedEventLoop(this);
>>>>>       }
>>>>>
>>>>>       return null;
>>>>>     }
>>>>>
>>>>>     public void close() {
>>>>>       Parent originalRoot = (Parent)stackPane.getChildren().remove(0);
>>>>>
>>>>>       scene.setRoot(originalRoot);
>>>>>       scene = null;
>>>>>
>>>>>       if(oldFocusOwner != null) {
>>>>>         oldFocusOwner.requestFocus();
>>>>>       }
>>>>>
>>>>>       if(synchronous) {
>>>>>         Toolkit.getToolkit().exitNestedEventLoop(this, getResult());
>>>>>       }
>>>>>     }
>>>>>
>>>>>
>>
>


Comments
Filed JDK-8143356 as the follow-up issue for additional tests.
19-11-2015

Changeset: http://hg.openjdk.java.net/openjfx/9-dev/rt/rev/e7910cbaf703
19-11-2015

+1 on the API change Docs look good. Implementation looks good. A few comments on the tests (not blocking) : 1) As we discussed off line, additional tests could be written as a follow-up to more fully test flow control. Can you file a new JIRA for this? 2) A small modification to the existing tests would go a long way toward that (and might even make more complicated follow-on tests unnecessary given how well-tested the underlying mechanism is with showAndWait). My thought is to add loopOneStarted and loopOneFinished flags (also for loop two), that you set just before and just after the call to enterNestedEventLoop, respectively. The code that verifies that the loop is running would assert that loopOneStarted is true and loopOneFinished is false. (The code that verifies the return value could additionally check that loopOneFinished is true, but that is already covered by checking the return value.) Approved for integration.
18-11-2015

As we discussed offline, the following needs to be added back in to enterNestedEventLoop + * @throws IllegalStateException if this method is called on a thread + * other than the FX Application thread + *
17-11-2015

Updated patch with a small number of unit tests and updated javadoc.
14-11-2015

One more note about the implementation. Our pattern thus far has been for Platform to call PlatformImpl and then PlatformImpl to call the Toolkit. I'm not sure we necessarily need to perpetuate this for API methods that just call into the Toolkit, and don't interact with anything that PlatformImpl cares about, but it is something to think about and make a deliberate decision on.
12-11-2015

The API looks good, although the methods on Platform need to be static. Can you add the following to the enterNestedEventLoop method? * @throws IllegalStateException if this method is called during * animation or layout processing. Also, here is a suggested update to the isNestedLoopRunning method: /** * Checks whether a nested event loop is running, returning true to indicate * that one is, and false if there are no nested event loops currently * running. * This method must be called on the JavaFX Application thread. * * @return true if there is a nested event loop running, and false otherwise. * * @throws IllegalStateException if this method is called on a thread * other than the JavaFX Application Thread. * * @since 9 */ public static boolean isNestedLoopRunning() {
12-11-2015

The existing system unit tests for showAndWait will test the underlying mechanism, but it would be good to have tests of the new API, too. Maybe these tests can be copied to a NestedEventLoop test?
11-11-2015

+1
02-02-2015

I find this API very usefull. It helps us keep javafx controller code simple when it comes to interacting with a server. With the public API for running things in background (e.g. Task), one has to implement suceeded() methods for each server side call which ends up boiling up the code. It is a very common scenario in a JavaFX client / server application to have something like this in an action method: 1 disable a part of the screen before calling the server 2 create an anonymous javafx.concurrent.Task 3 implement Task.call() to call the server 4 implement Task.suceeded() and do whatever you have to do with the value 5 enable the ui. 6 update the ui according to the server response If in the same javafx action method you have to call a server twice, then double the bubble. By using enterNestedEventLoop and exitNestedEventLoop we have been able to write a small set of classes which allows us to wrap all our remote service ports/stubs with a JDK dynamic proxy and reduce 1-5 in the above steps to just the line of code that calls the server. The JavaFX code in the action method virtually waits for the server to finish before the next line in the javafx action method gets executed without boilerplate code This is the JDK dynamic proxy using enterNestedEventLoop / exitNestedEventLoop http://git.anahata.uno/anahata-jfx/src/fd6ea42ef98c05213c1bb4791360743cf6b92d8a/src/main/java/com/anahata/jfx/concurrent/BackgroundInvocationHandler.java?at=master And simplifies our controller code to this: /** * FXML Controller class * * @author pablo */ @Slf4j public class NestedEventLoopTestController { @Background @Inject DummyBackgroundService service; @BackgroundDisable @FXML Button refreshButton; @FXML Label label; @FXML public void refresh() { String status = service.getStatus(); //automatically runs in a javafx.concurrent.Task and the code execution waits here without blocking the JavaFX thread until the service call has completed, additionally the refresh button gets disabled while the server call is in progress label.setText(status); //update the UI } }
31-01-2015

Just for interest, I used this in the ControlsFX project for the lightweight dialogs (i.e. dialogs that do not have their own stage). It worked very well: https://bitbucket.org/controlsfx/controlsfx/src/14ce84a1ff72afeb45175d9de10249872dd1618a/src/main/java/org/controlsfx/dialog/LightweightDialog.java?at=default
13-11-2013