17

I've been smashing my head with JavaFx...

This works for when there's no instances of an application running:

public class Runner {

    public static void main(String[] args) {
        anotherApp app = new anotherApp();
        new Thread(app).start();
    }
 }

public class anotherApp extends Application implements Runnable {

    @Override
    public void start(Stage stage) {
    }

    @Override
    public void run(){
        launch();
    }
}

But if I do new Thread(app).start() within another application I get an exception stating that I can't do two launches.

Also my method is called by an observer on the other application like this:

@Override
public void update(Observable o, Object arg) {
    // new anotherApp().start(new Stage());
            /* Not on FX application thread; exception */

    // new Thread(new anotherApp()).start();
            /* java.lang.IllegalStateException: Application launch must not be called more than once */
}

It's within a JavaFX class such as this:

public class Runner extends Applications implements Observer {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage){
    //...code...//
    }
    //...methods..//
    //...methods..//

    @Override
    public void update(Observable o, Object arg) {
    //the code posted above//
    }
}

I tried using ObjectProperties with listeners but it didn't work. I need to get this new stage running from within the update method from java.util.observer in some way.

Any suggestions are welcomed. Thanks.

Sergey Grinev
  • 34,078
  • 10
  • 128
  • 141
link_boy
  • 1,025
  • 4
  • 12
  • 23
  • 2
    Is your intention only to open a nother window? If yes, you can create a new `Stage` within the UI Thread: `final Stage stage = new Stage(); stage.setScene(yourScene); stage.show();` – Vertex Mar 27 '13 at 23:08
  • Yes, my intention is to open another window (application in another class), but I have to do it inside the update method from java.util.observer not the UI thread. – link_boy Mar 28 '13 at 07:15
  • 1
    You can run a bunch of code in the UI thread by calling the `runLater` method: `Platform.runLater(new Runnable() { @Override public void run() {//runs in the UI thread}});` So you can call it inside the `update` method. – Vertex Mar 28 '13 at 08:16

3 Answers3

31

Application is not just a window -- it's a Process. Thus only one Application#launch() is allowed per VM.

If you want to have a new window -- create a Stage.

If you really want to reuse anotherApp class, just wrap it in Platform.runLater()

@Override
public void update(Observable o, Object arg) {
    Platform.runLater(new Runnable() {
       public void run() {             
           new anotherApp().start(new Stage());
       }
    });
}
Sergey Grinev
  • 34,078
  • 10
  • 128
  • 141
  • 1
    Ok. It worked! for now but.., The documentation says "runs at an unspecified time in the future". What does that mean? That it may run 10 mins afterwards or something like that in some cases? What does the unspecified time depends on? Thanks. – link_boy Mar 28 '13 at 19:05
  • 1
    You can expect it to happen instantly. Unless you make 100500 of such calls simultaneously they are executed in split second :) – Sergey Grinev Mar 28 '13 at 20:40
  • 2
    You're a lifesaver @SergeyGrinev with the new anotherApp().start(new Stage()); I too had been beating myself up over a similar problem and your suggestion helped. Thanks! – Fergus May 02 '17 at 03:30
  • You forgot to catch the Exception thrown by start(stage). – DJViking May 10 '18 at 09:44
  • This will only work if your application is not dependent on the pre-loader. – Displee Nov 17 '19 at 23:24
2

I did a constructor of another JFX class in Main class AnotherClass ac = new AnotherClass(); and then called the method ac.start(new Stage);. it worked me fine. U can put it either in main() or in another method. It does probably the same thing the launch(args) method does

0

Wanted to provide a second answer because of one caveat of using
Application.start(Stage stage).

The start method is called after the init method has returned

If your JavaFX application has Override Application.init() then that code is never executed. Neither is any code you have in the second application main method.

Another way to start a second JavaFX application is by using the ProcessBuilder API to start a new process.

    final String javaHome = System.getProperty("java.home");
    final String javaBin = javaHome + File.separator + "bin" + File.separator + "java";
    final String classpath = System.getProperty("java.class.path");
    final Class<TestApplication2> klass = TestApplication2.class;
    final String className = klass.getCanonicalName();
    final ProcessBuilder builder = new ProcessBuilder(javaBin, "-cp", classpath, className);

    final Button button = new Button("Launch");
    button.setOnAction(event -> {

        try {
            Process process = builder.start();
        } catch (IOException e) {
            e.printStackTrace();
        }

    });
DJViking
  • 832
  • 1
  • 12
  • 29