在JavaFX webview中加载新页面

时间:2015-09-14 11:55:48

标签: javascript java webview javafx javafx-webengine

我目前正在开发一个Java应用程序,它使用JavaFX webview来显示其UI(使用HTML / CSS)。

一切正常但我在系统中加载新页面时遇到问题。当我这样做时,Java和新页面的JavaScript之间的通信似乎就被打破了。

这是我的代码:

** Broser **

public class Browser extends Region {

final WebView browser = new WebView();
final WebEngine webEngine = browser.getEngine();

public Browser() {
    //apply the styles
    getStyleClass().add("browser");
    // load the web page
    webEngine.load(some_url);

    JSObject jsobj = (JSObject) webEngine.executeScript("window");

    Bridge bridge = Bridge.getInstance();
    bridge.init(webEngine);

    jsobj.setMember("java", bridge);
    //add the web view to the scene
    getChildren().add(browser);

    }
}

** Bridge **

public class Bridge {
private static Bridge instance = null;

private WebEngine webEngine;

public Bridge () {
}

public static Bridge getInstance() {
    if(instance == null){
        instance = new Bridge();
    }
    return instance;
}

public void init(WebEngine webEngine) {
    if(this.webEngine == null) {
        this.webEngine = webEngine;
    }
}

public void btnStartSessionOnClick(String sessionName, String speakerNickname) {
    // Load the new page
    webEngine.load(some_other_url);
}
}

1 个答案:

答案 0 :(得分:2)

每当Web引擎加载新页面时,它都会替换DOM,因此存在不同的window对象。您定义的jsobj只设置一次,因此当加载新页面时,它将指向错误的对象。您需要在每次加载页面时重置此对象,您可以通过观察引擎的加载状态来执行此操作。

您的设计对我来说并没有多大意义:让windowjsobj)对象作为Bridge的一部分更有意义class,而不是应用程序类。由于Browser不是单身人士,因此将Bridge设为单身人士是没有意义的(例如,如果你的应用程序中有多个网页浏览量,那该怎么办?)。 p>

这是一个SSCCE:

package application;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class WebViewTest extends Application {

    @Override
    public void start(Stage primaryStage) {
        WebView webView = new WebView();
        WebEngine engine = webView.getEngine();

        Label output = new Label();

        Bridge bridge = new Bridge(engine);

        engine.load(getClass().getResource("/resources/First.html").toExternalForm());

        Button first = new Button("Load First");
        first.setOnAction(e -> engine.load(getClass().getResource("/resources/First.html").toExternalForm()));

        Button second = new Button("Load Second");
        second.setOnAction(e -> engine.load(getClass().getResource("/resources/Second.html").toExternalForm()));

        TextField textField = new TextField();
        Button button = new Button("Send");
        EventHandler<ActionEvent> handler = e -> {
            bridge.execute(result -> output.setText(result.toString()),
                    "showText", textField.getText());
            textField.setText("");
        };
        button.setOnAction(handler);
        textField.setOnAction(handler);

        HBox controls = new HBox(5, first, second, textField, button, new Label("Web page says: "), output);
        controls.setPadding(new Insets(10));

        BorderPane root = new BorderPane(webView, null, null, controls, null);
        Scene scene = new Scene(root);
        primaryStage.setScene(scene);
        primaryStage.show();
    }



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

Bridge类:

package application;

import java.util.function.Consumer;

import javafx.concurrent.Worker.State;
import javafx.scene.web.WebEngine;
import netscape.javascript.JSObject;

public class Bridge {


    private JSObject window ;

    public Bridge(WebEngine engine) {
        engine.getLoadWorker().stateProperty().addListener((obs, oldState, newState) -> {
            if (newState == State.SUCCEEDED) {
                window = (JSObject) engine.executeScript("window");
                window.setMember("application", this);
            }
        });
    }

    public void execute(Consumer<Object> callback, String function, Object... args) {
        callback.accept(window.call(function, args));
    }
}

一些简单的测试HTML文件,我在类路径根目录的resources文件夹中。

First.HTML:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>First</title>
<script>
    function showText(text) {
        document.getElementById("text").innerHTML = text;
        return text;
    }
</script>
</head>
<body>
    <p>This is the first page</p>
    <a href="Second.html">Go to the second page</a>
    <div id="text"></div>
</body>
</html>

和Second.html:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Second</title>
<script>
    function showText(text) {
        document.getElementById("text").innerHTML = text;
        return text;
    }
</script>
</head>
<body>
    <p>This is the second page</p>
    <a href="First.html">Go back to the first page</a>
    <div id="text"></div>
</body>
</html>