1

The first time I open a Shell and create a new FXCanvas setting the Scene it works fine. The second time the code executes (after closing the Shell and opening a new one) it throws the "Not on FX application thread" exception.

As I debug, when the first new FXCanvas returns I am on the FX thread as indicated by javafx.application.Platform.isFxApplicationThread(). The second time the code runs, the new FXCanvas returns and I am not on the FX thread.

If I wrap the whole process in a Platform.runLater() it runs fine the first execution, but the second execution never executes the code in the runLater().

Let me know if that is unclear.

Thanks.

Java Code:

package temp;

import java.net.URL;

import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;

import javafx.embed.swt.FXCanvas;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;

public class SwtWrapper {

    public SwtWrapper() {
        super();
    }

    public void go() {
        Display display = Display.getDefault();
        try {
            Shell shell = new Shell(display);
            FXCanvas canvas = new FXCanvas(shell, SWT.NONE);

            URL url = Class.class.getResource("/temp/Fxml.fxml");
            FXMLLoader fxmlLoader = new FXMLLoader(url);
            Parent rootNode = fxmlLoader.load();

            canvas.setScene(new Scene(rootNode));
            canvas.pack();

            shell.pack();
            shell.open();
            while (!shell.isDisposed()) {
                if ( !display.readAndDispatch() )
                    display.sleep();
            }

        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            display.dispose();
        }
    }

    public static void main(String[] args) {
        new SwtWrapper().go();
        new SwtWrapper().go();
        System.exit(0);
    }

}

FXML:

<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.text.*?>
<?import javafx.scene.control.*?>

<VBox>
    <children>
        <Text text="The FX Content." />
        <ProgressIndicator />
    </children>
</VBox>

Maven Dependencies:

<dependency>
    <groupId>org.eclipse</groupId>
    <artifactId>swt</artifactId>
    <version>4.4-cocoa</version>
    <classifier>macosx-x86_64</classifier>
</dependency>
<dependency>
    <groupId>com.oracle</groupId>
    <artifactId>jfxswt</artifactId>
    <version>8.0.0-FINAL</version>
    <systemPath>${java.home}/lib/jfxswt.jar</systemPath>
    <scope>system</scope>
</dependency>
Bryan Pugh
  • 113
  • 1
  • 7

2 Answers2

1

I'd like to link you to this question, which is essentially the same as this question, where I have posted an answer similar to the one below.

Change JavaFX Application Start Form

Essentially, to create a "FX Application thread" you create a class that

  1. extends "Application." i.e., public class SwtWrapper extends Application {

  2. overrides the start method (this is where all of your code goes, and it's essentially the "FX Application Thread." i.e @Override public void start(Stage stage) throws Exception

  3. has launch(args) set within the main method, usually that's all that's set, not sure if people set anything else in there.

So your code

  public static void main(String[] args) {
    new SwtWrapper().go();
    new SwtWrapper().go();
    System.exit(0);
}

should be within the start method

  @Override
public void start(Stage stage) throws Exception 
{
new SwtWrapper().go();
    new SwtWrapper().go();
    System.exit(0); // should probably be within the "stop" method
}

and your main should look like

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

Hope this helps.

Community
  • 1
  • 1
XaolingBao
  • 1,034
  • 1
  • 18
  • 34
  • That is great information and filled in some gaps for me, but it didn't get at the root of my problem. My real goal is to launch an SWT window from a base SWT application, and that SWT window has an FXCanvas in it. That window can be closed, and the parent application will open the SWT window again. In this scenario there is no javafx.application.Application involved and the FX toolkit is initialized with the instantiation of the FXCanvas. I will consider making the entire window into an FX application, but I am not sure whether that will work for me. – Bryan Pugh Apr 13 '16 at 20:40
  • Gotcha, I guess I missed that detail. I'm assumign you've looked at this http://docs.oracle.com/javafx/2/swt_interoperability/jfxpub-swt_interoperability.htm It seems they use FX objects within SWT, so I would read up on this (if you haven't already). This might be a bug as well, so you could also try reporting it at the javafx Jira, but I would wait until all other options are attempted :) – XaolingBao Apr 13 '16 at 20:58
0

It turns out that my specific problem was fixed by removing display.dispose(); for further reference see http://help.eclipse.org/juno/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fswt%2Fwidgets%2FDisplay.html

Bryan Pugh
  • 113
  • 1
  • 7
  • On a related note, the reason that the Platform.runLater may not be executing is answered here: http://stackoverflow.com/questions/29302837/javafx-platform-runlater-never-running – Bryan Pugh Apr 13 '16 at 23:34