JavaFX Tutorial - JavaFX WebEngine








JavaFX provides capabilities to interoperate with HTML5 content.

The underlying web page-rendering engine in JavaFX is the popular open-source API called WebKit. This API is used in Apple's Safari browsers, Amazon's Kindle devices, and was used in Google's Chrome browser.

The embedded browser enables you to perform the following tasks in your JavaFX applications:

  • Render HTML from local or remote URLs
  • Obtain Web history
  • Execute JavaScript commands
  • Calls JavaFX from JavaScript
  • Manage web pop-up windows




WebEngine

JavaFX provides a non-GUI component capable of loading HTML5 content, called the WebEngine API (javafx.scene.web.WebEngine).

This API is basically an object instance of the WebEngine class to be used to load a file containing HTML5 content.

The HTML5 file to be loaded can be located on a local file system, a web server, or inside a JAR file.

When you load a file using a web engine object, a background thread is used to load web content so that it does not block the JavaFX application thread.

Load from URL

We can load web content from a URL by using WebEngine's load( ) method.

The WebEngine uses background threads, adheres to an event-based programming model.

A web engine can load web content asynchronously from a remote web server and notify handler code when the content is finished loading.

The following code loads HTML content from a remote web server in a background worker thread.

To monitor or determine whether the worker thread has finished a javafx.beans.value.ChangeListener is added to the state property.

import javafx.application.Application;
import javafx.concurrent.Worker.State;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
/*  ww w .jav  a 2  s.  co  m*/
public class Main extends Application {
  public static void main(String[] args) {
    Application.launch(args);
    
  }

  @Override
  public void start(Stage primaryStage) {
    WebEngine webEngine = new WebEngine();
    webEngine.getLoadWorker().stateProperty()
        .addListener((obs, oldValue, newValue) -> {
          if (newValue == State.SUCCEEDED) {
            System.out.println("finished loading");
          }
        }); // addListener()

    // begin loading...
    webEngine.load("http://www.java2s.com");

    
    Group root = new Group();
    Scene scene = new Scene(root, 300, 250);

    primaryStage.setScene(scene);
    primaryStage.show();
  }
}

The following are all of the possible worker thread states:

  • READY
  • SCHEDULED
  • RUNNING
  • SUCCEEDED
  • CANCELLED
  • FAILED




Load HTML String

We can load HTML string to WebEngine with WebEngine's loadContent( ) Method.

Web engine's loadContent(String htmlText) method can load HTML content represented as a string dynamically without having to fetch content from a remote server.

The following code snippet loads pregenerated HTML content:

webEngine.loadContent("<html><body><b>JavaFX</b></body></html>");

HTML DOM Content

The web engine has the ability to load the current page's document object model (DOM) as XML content following the W3C standards-based APIs for Java.

After a web engine instance successfully loads HTML content, an XML DOM can be easily obtained by invoking the web engine's getDocument() method.

The following code obtains a Document (org.w3c.dom.Document) instance assuming the web engine is finished loading the HTML or XML content.

import javafx.application.Application;
import javafx.concurrent.Worker.State;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
//from www . ja v a  2 s  .  c o  m
public class Main extends Application {
  public static void main(String[] args) {
    Application.launch(args);
    
  }

  @Override
  public void start(Stage primaryStage) {
    WebEngine webEngine = new WebEngine();
    webEngine.getLoadWorker().stateProperty()
        .addListener((obs, oldValue, newValue) -> {
          if (newValue == State.SUCCEEDED) {
            System.out.println("finished loading");
            org.w3c.dom.Document   xmlDom  = webEngine.getDocument();
            System.out.println(xmlDom);
          }
        }); // addListener()

    // begin loading...
    webEngine.load("http://www.java2s.com");

    Group root = new Group();
    Scene scene = new Scene(root, 300, 250);

    primaryStage.setScene(scene);
    primaryStage.show();
  }
}

Obtain the raw XML data as a string of text

The following code converts an XML DOM into a String.

import java.io.StringWriter;
//  w  w w.j ava2s .  c  o  m
import javafx.application.Application;
import javafx.concurrent.Worker.State;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

public class Main extends Application {
  public static void main(String[] args) {
    Application.launch(args);

  }

  @Override
  public void start(Stage primaryStage) {
    WebEngine webEngine = new WebEngine();
    webEngine
        .getLoadWorker()
        .stateProperty()
        .addListener(
            (obs, oldValue, newValue) -> {
              System.out.println(newValue);
              if (newValue == State.SUCCEEDED) {
                System.out.println("finished loading");
                try {
                  TransformerFactory transformerFactory = TransformerFactory
                      .newInstance();
                  Transformer transformer = transformerFactory.newTransformer();
                  StringWriter stringWriter = new StringWriter();
                  transformer.transform(new DOMSource(webEngine.getDocument()),
                      new StreamResult(stringWriter));
                  String xml = stringWriter.getBuffer().toString();
                  System.out.println(xml);
                } catch (Exception e) {
                  e.printStackTrace();
                }

              }
            }); // addListener()

    // begin loading...
    webEngine.load("http://www.java2s.com");

    Group root = new Group();
    Scene scene = new Scene(root, 300, 250);

    primaryStage.setScene(scene);
    primaryStage.show();
  }
}

Raw HTML5 Content via the JavaScript Bridge

JavaFX's WebEngine API has a JavaScript bridge that allows Java code to invoke JavaScript functions or script code inside HTML5 content.

To obtain the raw HTML5 you will need to interact with the JavaScript bridge to access the web content's DOM using the web engine's executeScript() method.

The following code accesses the HTML document (DOM) to obtain the raw content from the documentElement.outerHTML:

String html  = (String)  webEngine.executeScript("document.documentElement.outerHTML");
import javafx.application.Application;
import javafx.concurrent.Worker.State;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
//from  w w  w  .  ja v  a  2s .  co  m
public class Main extends Application {
  public static void main(String[] args) {
    Application.launch(args);
  }
  @Override
  public void start(Stage primaryStage) {
    WebEngine webEngine = new WebEngine();
    webEngine
        .getLoadWorker()
        .stateProperty()
        .addListener(
            (obs, oldValue, newValue) -> {
              System.out.println(newValue);
              if (newValue == State.SUCCEEDED) {
                System.out.println("finished loading");
                String html = (String) webEngine
                    .executeScript("document.documentElement.outerHTML");
                System.out.println(html);

              }
            }); 

    webEngine.load("http://www.java2s.com");

    Group root = new Group();
    Scene scene = new Scene(root, 300, 250);

    primaryStage.setScene(scene);
    primaryStage.show();
  }
}

Communicating from Java to JavaScript

The following code shows how to call JavaScript function from Java code.

Suppose we have a web page which has the following JavaScript Function

... 
<script>
function  sayHello( msg ) {
    document.getElementById('my_message').innerHTML = msg;
}
</script>
<div id="my_message"></div>

We can call the function from Java code webEngine.executeScript("sayHello('Hi there');");

Communicating from JavaScript to Java

JavaFX allows JavaScript code to make calls into Java code.

import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
import jdk.nashorn.api.scripting.JSObject;
/*  w  w  w  .j a  v a 2 s. c o  m*/
public class Main extends Application {
  public static void main(String[] args) {
    Application.launch(args);
  }

  @Override
  public void start(Stage primaryStage) {
    WebEngine webEngine = new WebEngine();
    webEngine.getLoadWorker().stateProperty()
        .addListener((obs, oldValue, newValue) -> {
          if (newValue == Worker.State.SUCCEEDED) {

            JSObject jsobj = (JSObject) webEngine.executeScript("window");
            jsobj.setMember("ABCD", new HelloWorld());
          }
        });

    webEngine.load("http://www.java2s.com");

    Group root = new Group();
    Scene scene = new Scene(root, 300, 250);

    primaryStage.setScene(scene);
    primaryStage.show();
  }
}

class HelloWorld {
  public String sayGoodbye(String name) {
    return "hi:" + name;
  }
}

JavaScript Code Calling Java Code

<script>
function sayGoodbye(name)  {
var  message  = ABCD.sayGoodbye(name);
document.getElementById('my_message').innerHTML = message;
}
</script>

<div  id="my_message"></div>