Hi!
Alan O’Leary shows in his blog a WebView integration in Swing. It is a not good documented feature, how to integrate JavaFX 2.0 controls into a swing application. But an integration is a main goal for the JavaFX 2.0 release.
As an enthusiastic NetBeans Platform/RCP developer and JavaFX partner, I work since two days to ...
Hi!
Alan O’Leary shows in his blog a WebView integration in Swing. It is a not good documented feature, how to integrate JavaFX 2.0 controls into a swing application. But an integration is a main goal for the JavaFX 2.0 release.
As an enthusiastic NetBeans Platform/RCP developer and JavaFX partner, I work since two days to marriage JavaFX 2.0 and a NetBeans Platform Application. And yes, it works
I’ve created a maven based platform application with a special starter Main.class. I need to launch the JavaFX toolkit system before any other module bootstrapping. The solution here is based on the early access release through the JavaFX partner program. This “best practice” may change significantly between now and the final version. However, I’ll show only a concept, not compilable code.
The solution behind the bootstrapping a NetBeans Platform is based on a FAQ by Tom Wheeler. My Main.class is a JavaFX Application class – I need this Application instance to get rid of from invoke exceptions. The created Stage object by the Launcher can be ignored.
public class Main extends Application{
private static final String NB_MAIN_CLASS = "org.netbeans.core.startup.Main";
public static void main(String[] args) throws Exception {
// do whatever you need here (e.g. show a custom login form)
System.out.println("Launch Java FX");
long ms = System.currentTimeMillis();
Launcher.launch(Main.class, args); // This is the main start up for JavaFX 2.0
System.out.println("Launched Java FX in " + (System.currentTimeMillis() - ms) + "ms");
// once you're done with that, hand control back to NetBeans
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
Class mainClass = Class.forName(NB_MAIN_CLASS, true, classloader);
Object mainObject = mainClass.newInstance();
Method mainMethod = mainClass.getDeclaredMethod("main", new Class[]{String[].class});
mainMethod.invoke(mainObject, (Object) args);
}
@Override
public void start(Stage stage) {
// Nothing to do, forget the stage....
}
}
The Main class is in a standard Java archive. This JAR file and all the JavaFX files must be in the platform/core folder.
At runtime all the core-Libs are available to the whole NetBeans Platform modules (and plugins). For the compiler I need a special dependency to the runtime:
<dependency>
<groupId>sun.javafx</groupId>
<artifactId>tools</artifactId>
<version>2.0.0</version>
<scope>system</scope>
<systemPath>${basedir}/../../corelauncher/mainlauncher/src/main/lib/jfxrt.jar</systemPath>
</dependency>
The system path depends on your project structure.
Now I can access all the JavaFX classes in a NetBeans module.
Please note, any scene construction needs to be build up in the JavaFX event queue thread. This is not the EventDispatcher-Thread from Swing!
My favorite call to jump in the JavaFX event thread is: Toolkit.getDefault().defer (Runnable) javafx.application.Platform.runLater (Runnable). But the Toolkit class is in a com.* package. IMHO in the future we get an official way to do this.
The creation of a WebView component is pretty similar to the sample from Alan. But I don’t need a stage object:
Platform.runLater(new Runnable() {
@Override
public void run() {
group = new Group();
Scene scene = new Scene(group);
browser = new WebView(new WebEngine());
browser.getEngine().addChangeListener(PropertyReference.WILDCARD, new ChangeListener() {
@Override
public void handle(Bean paramBean, PropertyReference paramPropertyReference) {
if ("title".equals(paramPropertyReference.getName())) {
EventQueue.invokeLater(new Runnable() {
// Jump to Swing EventDispatcher...
@Override
public void run() {
BrowserTopComponent.this.setDisplayName(browser.getEngine().getTitle());
}
});
}
if ("url".equals(paramPropertyReference.getName())) {
EventQueue.invokeLater(new Runnable() {
// Jump to Swing EventDispatcher...
@Override
public void run() {
String url = browser.getEngine().getUrl();
tfUrl.setText(url);
addHistory(url);
}
});
}
}
});
group.getChildren().add(browser);
group.setScaleX(0.8d);
group.setScaleY(0.8d);
Reflection r = new Reflection();
r.setTopOffset(8);
group.setEffect(r);
scene.setFill(javafx.scene.paint.Color.BLACK);
browser.setWidth(panel.getWidth());
browser.setHeight(panel.getHeight());
panel.setScene(scene);
}
});
panel.addComponentListener(new ComponentAdapter() {
@Override
public void componentResized(ComponentEvent e) {
Platform.runLater (new Runnable() {
// Jump from Swing-EventDispatcher to the JavaFX Thread:
@Override
public void run() {
browser.setWidth(panel.getWidth());
browser.setHeight(panel.getHeight());
}
});
}
});
I’ve added some useful listeners. Please aware the switches between different threads (Swing and JavaFX).
The result is a beautiful NetBeans Platform application with an embedded JavaFX 2.0 WebView:

PS.: I like the Twitter message from Dean Riverson: “Ok, I call a moratorium on rotating and reflecting WebView…” (origin). -
I have to write 100 times:
I’ll never rotate and reflect WebView again, I’ll never rotate and reflect WebView again,I’ll never rotate and reflect WebView again,I’ll never rotate and reflect WebView again,I’ll never rotate and reflect WebView again,I’ll never rotate and reflect WebView again,I’ll never rotate and reflect WebView again,I’ll never rotate and reflect WebView again,I’ll never rotate and reflect WebView again,I’ll never rotate and reflect WebView again, …
VN:F [1.9.10_1130]
Rating: 5.0/5 (4 votes cast)