Adding HTML Content to JavaFX Applications

Previous
Next

Beta Draft: 2013-09-17

5 Processing JavaScript Commands

This chapter extends the WebViewSample application and explains how to call JavaScript commands from JavaFX code.

The WebEngine class provides API to run a script within the context of the current HTML page.

Understanding the executeScript method

The executeScript method of the WebEngine class enables executing any JavaScript commands declared in the loaded HTML page. Use the following string to call this method on a web engine: webEngine.executeScript("<function name>");.

The method execution result is converted to a java.lang.Object instance by using the following rules:

  • JavaScript Int32 is converted to java.lang.Integer

  • JavaScript numbers are converted to java.lang.Double

  • JavaScript string values are converted to java.lang.String

  • JavaScript boolean values are converted to java.lang.Boolean

Refer to the API documentation for the WebEngine class for more information about the conversion results.

Calling JavaScript Commands from JavaFX Code

Extend the WebViewSample application to execute a JavaScript command that toggles the list of documents on the Java SE documentation page.

The modified application code shown in Example 5-1 creates an additional button to hide and show the Java SE documentation for the previous releases. The button is added to the toolbar only when the Documentation page is selected.

Example 5-1 Adding the Toggle Previous Docs button

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Pos;
import javafx.geometry.VPos;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Hyperlink;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;
import javafx.scene.paint.Color;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
 
public class WebViewSample extends Application {
 
    private Scene scene;
 
    @Override
    public void start(Stage stage) {
        // create scene
        stage.setTitle("Web View");
        scene = new Scene(new Browser(), 900, 600, Color.web("#666970"));
        stage.setScene(scene);
        // apply CSS style
        scene.getStylesheets().add("webviewsample/BrowserToolbar.css");
        // show stage
        stage.show();
    }
 
    public static void main(String[] args) {
        launch(args);
    }
}
 
class Browser extends Region {
 
    private HBox toolBar;
    final private static String[] imageFiles = new String[]{
        "product.png",
        "blog.png",
        "documentation.png",
        "partners.png",
    };
    final private static String[] captions = new String[]{
        "Products",
        "Blogs",
        "Documentation",
        "Partners",
    };
    final private static String[] urls = new String[]{
        "http://www.oracle.com/products/index.html",
        "http://blogs.oracle.com/",
        "http://docs.oracle.com/javase/index.html",
        "http://www.oracle.com/partners/index.html",
    };
    final ImageView selectedImage = new ImageView();
    final Hyperlink[] hpls = new Hyperlink[captions.length];
    final Image[] images = new Image[imageFiles.length];
    final WebView browser = new WebView();
    final WebEngine webEngine = browser.getEngine();
    final Button showPrevDoc = new Button("Toggle Previous Docs");
    private boolean needDocumentationButton = false;
 
    public Browser() {
        //apply the styles
        getStyleClass().add("browser");
 
        for (int i = 0; i < captions.length; i++) {
            // create hyperlinks
            Hyperlink hpl = hpls[i] = new Hyperlink(captions[i]);
            Image image = images[i] =
                    new Image(getClass().getResourceAsStream(imageFiles[i]));
            hpl.setGraphic(new ImageView(image));
            final String url = urls[i];
            final boolean addButton = (hpl.getText().equals("Documentation"));
 
            // process event 
            hpl.setOnAction(new EventHandler<ActionEvent>() {
                @Override
                public void handle(ActionEvent e) {
                    needDocumentationButton = addButton;
                    webEngine.load(url);
                }
            });
        }
 
     
        // create the toolbar
        toolBar = new HBox();
        toolBar.setAlignment(Pos.CENTER);
        toolBar.getStyleClass().add("browser-toolbar");
        toolBar.getChildren().addAll(hpls);
        toolBar.getChildren().add(createSpacer());
 
        //set action for the button
        showPrevDoc.setOnAction(new EventHandler() {
            @Override
            public void handle(Event t) {
                webEngine.executeScript("toggleDisplay('PrevRel')");
            }           
        });
       
        // process page loading
        webEngine.getLoadWorker().stateProperty().addListener(
            new ChangeListener<State>() {
                @Override
                public void changed(ObservableValue<? extends State> ov,
                    State oldState, State newState) {
                        toolBar.getChildren().remove(showPrevDoc);
                        if (newState == State.SUCCEEDED) {
                            if (needDocumentationButton) {
                                toolBar.getChildren().add(showPrevDoc);
                            }
                        }
                    }
                }
        );
 
        // load the home page        
        webEngine.load("http://www.oracle.com/products/index.html");
 
        //add components
        getChildren().add(toolBar);
        getChildren().add(browser);
    }
 
    private Node createSpacer() {
        Region spacer = new Region();
        HBox.setHgrow(spacer, Priority.ALWAYS);
        return spacer;
    }
 
    @Override
    protected void layoutChildren() {
        double w = getWidth();
        double h = getHeight();
        double tbHeight = toolBar.prefHeight(w);
        layoutInArea(browser,0,0,w,h-tbHeight,0,HPos.CENTER, VPos.CENTER);
        layoutInArea(toolBar,0,h-tbHeight,w,tbHeight,0,HPos.CENTER,VPos.CENTER);
    }
 
    @Override
    protected double computePrefWidth(double height) {
        return 900;
    }
 
    @Override
    protected double computePrefHeight(double width) {
        return 600;
    }
}

Loading always happens on a background thread. Methods that initiate loading return immediately after scheduling a background job. The getLoadWorker() method provides an instance of the Worker interface to track the loading progress. If the progress status of the Documentation page is SUCCEEDED, the Toggle Previous Docs button is added to the toolbar, as shown in Figure 5-1.

Figure 5-1 Toggle Previous Docs Button

Embedded browser with the navigation toolbar
Description of "Figure 5-1 Toggle Previous Docs Button "

The setOnAction method shown in Example 5-2 defines behavior for the Toggle Previous Docs button.

Example 5-2 Executing a JavaScript Command

showPrevDoc.setOnAction(new EventHandler() {
    @Override
    public void handle(Event t) {
        webEngine.executeScript("toggleDisplay('PrevRel')");
    }           
});

When the user clicks the Toggle Previous Doc button, the executeScript method runs the toggleDisplay JavaScript function for the Documentation page, and the documents for the previous Java releases appear, as shown in Figure 5-2. When the user performs another click, the toggleDisplay function hides the lists of the documents.

Figure 5-2 Showing the Java SE Documentation

Description of Figure 5-2 follows
Description of "Figure 5-2 Showing the Java SE Documentation"

Previous
Next