14 Replies Latest reply on May 25, 2012 9:09 PM by jsmith

    How to call Stage’s show/hide methods from AWT-thread

    Steamus
      Hello Everybody,

      I would like to use java SystemTray functionality with JavaFX application. So, I implemented TrayIcon with MouseListener. My FX-Application started but primary stage is not visible. Then I want to show/hide my FX-Stage by clicking mouse on TrayIcon.

      Because I can call stage.show()/hide() from FX thread only I use Platform.runLater( fxTread ). Something like this:
      Platform.runLater( new Runnable()
      {
          public void run()
          {
              if( stage.isShowing() )
              {
                  stage.hide();
              }
              else
              {
                  stage.show();
              }
          }
       } );
      It works, but one time only. Just show and hide. Looks like the Platform.runLater( thread ) doesn’t finish FX- thread and it is unavailable any more to manipulate the visibility of stage.

      Is there a way how to do it?

      Thank you.
        • 1. Re: How to call Stage’s show/hide methods from AWT-thread
          895506
          I'm not good to talk about threads but what if you call new Runnable only if the the stage is closed?
          • 2. Re: How to call Stage’s show/hide methods from AWT-thread
            Steamus
            Yes, I was trying to do it that way.

            I was creating a new thread for Platform.runLater(), started the stage.show() and stored the new thread in the variable. Then, I used that created thread to call stage.hide(). It works and it works absolutely the same (one time only).

            To make sure I was trying to use some other switcher. For example - stage.setIconified(). This case it works fine. I can switch iconify/normal as many time as I want. On the other hand I checked - is it possible to run the show()/hide() in the base FX-GUI thread several times. Yes, it is possible.

            Apparently, looks like the show()/hide() doesn’t work properly in the thread running by Platform.runLater().
            • 3. Re: How to call Stage’s show/hide methods from AWT-thread
              Artem Ananiev-Oracle
              I guess this behavior is related to JavaFX lifecycle. By default, JavaFX toolkit is auto-terminated, when the last window is closed, exactly like it is in AWT. Once shut-down, JavaFX runtime for some unknown reason is not reinitialized again... Could you try the following:

              1. Keep another JavaFX window open, while calling show()/hide()

              2. Call Application.launch() after the window has been hidden, before show() it again

              3. Terminate AWT part of your application (TrayIcon), so it doesn't prevent Java from exiting. I'd expect that after the call to hide() JavaFX shuts down its non-daemon threads, so the whole application should exit
              • 4. Re: How to call Stage’s show/hide methods from AWT-thread
                867289
                I am experiencing the same problem. Some research had shown that the problem is that calling Stage.hide() call is equivalent to calling Stage.close() in JavaFx.
                So javaFx tries to close application, after hide method was called(and there is no other stages visible) - I can we it because there is a new thread called "DestroyJavaVM":)

                Maybe you should be using swing for window management and have javafx embedded inside jframe.
                • 5. Re: How to call Stage’s show/hide methods from AWT-thread
                  Steamus
                  For ArtemAnaniev:

                  1. Keep another JavaFX window open, while calling show()/hide()
                  --------------------------------------------------
                  This case it works. If there is other opened stage, the primary stage can be hiding and showing many times. But it doesn’t make sense for me because my purpose was to avoid iconifyed app in the taskbar (only in the tray). Unfortunately, if we have other opened stages – we have it.

                  2. Call Application.launch() after the window has been hidden, before show() it again
                  --------------------------------------------------
                  It is impossible. According to runtime exception the ‘launch()’ can be running only from subclass of javafx.application.Application. Difficult to say what means this message. Sure, I run it from subclass of javafx.application.Application. Otherwise it would be compilation time error. :)

                  3. Terminate AWT part of your application (TrayIcon), so it doesn't prevent Java from exiting. I'd expect that after the call to hide() JavaFX shuts down its non-daemon threads, so the whole application should exit
                  ---------------------------------------------------
                  I was trying to remove Tray Icon if the primary stage is showing. And add icon back when stage hiding. Without success, as before – one time only.

                  For ndrw:

                  Maybe you should be using swing for window management and have javafx embedded inside jframe.
                  ---------------------------------------------------
                  Definitely it is possible. But, the idea was to avoid ‘Swing’ completely. Just AWT: a couple of included AWT classes
                  located in one/two my user’s clasess.

                  It would be good to listen to FX-engineers opinions. May be there is a plan to add this possibility (Tray)?
                  • 6. Re: How to call Stage’s show/hide methods from AWT-thread
                    Artem Ananiev-Oracle
                    Yes, SystemTray support is currently targeted to 3.0: http://javafx-jira.kenai.com/browse/RT-17503.

                    There is a workaround for your problem, however I must put a warning here: this is not a public API, so it can be changed or removed anytime in the future. Try implementing com.sun.javafx.application.PlatformImpl$FinishListener and register it with PlatformImpl.addListener().
                    • 7. Re: How to call Stage’s show/hide methods from AWT-thread
                      Steamus
                      ArtemAnaniev:
                      It is not a problem. I can implement exitCalled() and idle() and get both on app exit. But, sorry, I didn’t catch what I should do with it?
                      • 8. Re: How to call Stage’s show/hide methods from AWT-thread
                        Artem Ananiev-Oracle
                        Sorry, I wasn't clear about it... Just register a listener, it should be enough to prevent FX runtime from exit.

                        Artem
                        • 9. Re: How to call Stage’s show/hide methods from AWT-thread
                          Steamus
                          I was trying to register it in the Application’s start method. And it was registered. I see message on Platform.exit(). But show/hide behavior is the same. :(
                          • 10. Re: How to call Stage’s show/hide methods from AWT-thread
                            Artem Ananiev-Oracle
                            It sounds like a bug then. Could you file a new issue in JavaFX JIRA and attach the test case, please? URL is http://javafx-jira.kenai.com
                            • 11. Re: How to call Stage’s show/hide methods from AWT-thread
                              908093
                              Temporary workaround to prevent the FX application from closing is to open a dummy stage before hiding/closing the primary stage and hide/close the dummy stage after the the primary stage is shown...

                              Stage dummyPopup = new Stage();
                              dummyPopup.initModality(Modality.NONE);
                              // set as utility so no iconification occurs
                              dummyPopup.initStyle(StageStyle.UTILITY);
                              // set opacity so the window cannot be seen
                              dummyPopup.setOpacity(0d);
                              // not necessary, but this will move the dummy stage off the screen
                              final Screen screen = Screen.getPrimary();
                              final Rectangle2D bounds = screen.getVisualBounds();
                              dummyPopup.setX(bounds.getMaxX());
                              dummyPopup.setY(bounds.getMaxY());
                              // create/add a transparent scene
                              final Group root = new Group();
                              dummyPopup.setScene(new Scene(root, 1d, 1d, Color.TRANSPARENT));
                              // show the dummy stage
                              dummyPopup.show();
                              1 person found this helpful
                              • 12. Re: How to call Stage’s show/hide methods from AWT-thread
                                932079
                                If you are using JavaFX 2.0. You also have to call the following method after you show the stage, as the stage size would have changed( I don't know why, maybe a bug)

                                stageToShow.show();

                                // size back to scene size
                                stageToShow.sizeToScene();

                                // if you centered it before hiding
                                //stageToShow.centerOnScreen();
                                • 13. Re: How to call Stage’s show/hide methods from AWT-thread
                                  iamjvn
                                  Thanks, the dummy stage approach works for me. Tested on Windows 7 and Ubuntu 11.04 with Gnome 2.32.0

                                  Edited by: user1668940 on 25-May-2012 13:48
                                  • 14. Re: How to call Stage’s show/hide methods from AWT-thread
                                    jsmith
                                    If you use 2.2, you should no longer need the dummy stage work around.

                                    See http://javafx-jira.kenai.com/browse/RT-15011 "Provide ability to alter the implicit "exit on last window closed" behavior"

                                    "add the following pair of methods to the Platform class.
                                    {code}
                                    public static void setImplicitExit(boolean implicitExit)
                                    public static boolean isImplicitExit()
                                    {code}
                                    If this attribute is true, the JavaFX runtime will implicitly shutdown when the last window is closed. If this attribute is false, the application will continue to run normally even after the last window is closed, until the application calls Platform.exit(). The default value is true, which preserves the existing behavior. "