JavaFX WebView with JavaScript Commands

I wanted to use JavaFX for web pages test like Selenium, but I realized I have not had enough knowledge about JavaFX. So I started to learn about WebView and WebEngine.

  • Figure 1

WebView and 5 Buttons executing JavaScript commands

engine.load(...) starts a asynchronous loading and return immediately

        WebView webView = new WebView();
        engine = webView.getEngine();
        engine.load("http://localhost:8080/HelloSample");

So the buttons should be disabled as long as the web page is loading, except first button
This code uses addListener method but there are some other ways (F.Y.R:JavaFX 2.2)

        engine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
            @Override
            public void changed(ObservableValue<? extends State> ov, State oldState, State newState) {
                if (newState == State.SUCCEEDED && engine.getTitle().equalsIgnoreCase("Hello")) {
                    btnHello.setDisable(false);
                    btnMorning.setDisable(false);
                    btnClear.setDisable(false);
                    btnNotClear.setDisable(false);
                } else {
                    btnHello.setDisable(true);
                    btnMorning.setDisable(true);
                    btnClear.setDisable(true);
                    btnNotClear.setDisable(true);
                }
            }
        });
  • Figure 2

After we click the [Greet Hello] button

add the below code to the button's setOnAction:
1. Input the JavaFX to text
2. click the Hello radio botton
3. select the English
4. click the greet button

            public void handle(ActionEvent t) {
                engine.executeScript("document.getElementById('form1:name').value = 'JavaFX'");
                engine.executeScript("document.getElementsByName('form1:greetSel')[0].checked = true");
                engine.executeScript("document.getElementById('form1:language').options[0].selected = true");
                engine.executeScript("var btn = document.getElementById('form1:greet'); btn.click();");
            }
  • Figure 3

After we click the [Greet おはよう] button

This code is almost the same to the Figure 2

            public void handle(ActionEvent t) {
                engine.executeScript("document.getElementById('form1:name').value = 'JavaFX'");
                engine.executeScript("document.getElementsByName('form1:greetSel')[1].checked = true");
                engine.executeScript("document.getElementById('form1:language').options[1].selected = true");
                engine.executeScript("var btn = document.getElementById('form1:greet'); btn.click();");
            }

NOTE:
After Figure 2, I wanted to click [Greet おはよう] without clicking the [load Hello Screen] button.
But I could not find out the way about how to manage web page loading and control button handle method.

  • Figure 4

When we uses browsers after click the [Clear Name] button

  • can not open the confirm window like Figure 4

instead of this we have to use engine.setConfirmHandler method.
In this code shows how to control either ok or cancel button in the confirm window
I use the member variable isConfirmOK to do so, But I think there is another way....

        btnClear.setOnAction(getClearNameAction(true));          // 「ClearName(OK)」button setting OK for confirm window
        btnNotClear.setOnAction(getClearNameAction(false));   // 「ClearName(cancel)」button setting Cancel for confirm window
...
    private EventHandler<ActionEvent> getClearNameAction(final boolean isOK) {
        return new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                isConfirmOK = isOK;
                engine.executeScript("var btn = document.getElementById('form1:clearButton'); btn.click();");
            }
        };
    }
.....
        engine.setConfirmHandler(getConfirmAction());
......
    private Callback<String, Boolean> getConfirmAction() {
        return new Callback<String, Boolean>() {
            @Override
            public Boolean call(String p) {
                if (isConfirmOK) {
                    return true;
                }
                return false;
            }
        };
    }

Please feel free to give me any advice anytime.

  • all the code here
package test;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import javafx.util.Callback;

/**
 *
 * @author tomo
 */
public class HelloSampleTest extends Application{
    private WebEngine engine;
    private boolean isConfirmOK;

    @Override
    public void start(Stage stage) throws Exception {
        WebView webView = new WebView();
        engine = webView.getEngine();
        engine.load("http://localhost:8080/HelloSample");
        VBox box = new VBox();
        box.getChildren().add(webView);
        Button btnLoad = new Button("load Hello Screen");
        final Button btnHello = new Button("Greet Hello");
        btnHello.setDisable(true);
        final Button btnMorning = new Button("Greet おはよう");
        btnMorning.setDisable(true);
        final Button btnClear = new Button("clearName(OK)");
        btnClear.setDisable(true);
        final Button btnNotClear = new Button("clearName(cancel)");
        btnNotClear.setDisable(true);
        engine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
            @Override
            public void changed(ObservableValue<? extends State> ov, State oldState, State newState) {
                if (newState == State.SUCCEEDED && engine.getTitle().equalsIgnoreCase("Hello")) {
                    btnHello.setDisable(false);
                    btnMorning.setDisable(false);
                    btnClear.setDisable(false);
                    btnNotClear.setDisable(false);
                } else {
                    btnHello.setDisable(true);
                    btnMorning.setDisable(true);
                    btnClear.setDisable(true);
                    btnNotClear.setDisable(true);
                }
            }
        });
        HBox hbox = new HBox();
        hbox.setPadding(new Insets(15,12,15,12));
        hbox.setSpacing(10);
        hbox.setStyle("-fx-background-color: #336699;");
        hbox.getChildren().addAll(btnLoad, btnHello, btnMorning, btnClear, btnNotClear);
        box.getChildren().add(hbox);
        btnLoad.setOnAction(getLoadAction());
        btnHello.setOnAction(getHelloAction());
        btnMorning.setOnAction(getおはようAction());
        btnClear.setOnAction(getClearNameAction(true));
        btnNotClear.setOnAction(getClearNameAction(false));
        engine.setConfirmHandler(getConfirmAction());
        stage.setScene(new Scene(box, 800, 300));
        stage.show();
    }
    private EventHandler<ActionEvent> getLoadAction() {
        return new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                engine.load("http://localhost:8080/HelloSample");
            }
        };
    }

    private EventHandler<ActionEvent> getHelloAction() {
        return new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                engine.executeScript("document.getElementById('form1:name').value = 'JavaFX'");
                engine.executeScript("document.getElementsByName('form1:greetSel')[0].checked = true");
                engine.executeScript("document.getElementById('form1:language').options[0].selected = true");
                engine.executeScript("var btn = document.getElementById('form1:greet'); btn.click();");
            }
        };
    }
        private EventHandler<ActionEvent> getおはようAction() {
        return new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                engine.executeScript("document.getElementById('form1:name').value = 'JavaFX'");
                engine.executeScript("document.getElementsByName('form1:greetSel')[1].checked = true");
                engine.executeScript("document.getElementById('form1:language').options[1].selected = true");
                engine.executeScript("var btn = document.getElementById('form1:greet'); btn.click();");
            }
        };
    }

    private EventHandler<ActionEvent> getClearNameAction(final boolean isOK) {
        return new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent t) {
                isConfirmOK = isOK;
                engine.executeScript("var btn = document.getElementById('form1:clearButton'); btn.click();");
            }
        };
    }

    private Callback<String, Boolean> getConfirmAction() {
        return new Callback<String, Boolean>() {
            @Override
            public Boolean call(String p) {
                if (isConfirmOK) {
                    return true;
                }
                return false;
            }
        };
    }

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

The code is hosted on gist JavaFX using WebView · GitHub
So keep coding....