【问题标题】:Load a new page in JavaFX webview在 JavaFX webview 中加载新页面
【发布时间】:2015-09-14 11:55:48
【问题描述】:

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

一切正常,但我无法在系统中加载新页面。当我这样做时,Java 和新页面的 JavaScript 之间的通信似乎中断了。

这是我的代码:

** 布罗泽 **

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);

    }
}

** 桥 **

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);
}
}

【问题讨论】:

  • 你所说的“通讯中断”是什么意思?
  • @fxm 很好,每当我尝试触发从 JavaScript 到 Java 的函数时,反之亦然,没有任何反应。

标签: javascript java webview javafx javafx-webengine


【解决方案1】:

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

您的设计对我来说意义不大:将window (jsobj) 对象作为Bridge 类的一部分而不是应用程序类对我来说更有意义。由于Browser 不是单例,因此将Bridge 设为单例是没有意义的(例如,如果您的应用程序中有多个Web 视图怎么办?)。

这是一个 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>

【讨论】:

    猜你喜欢
    • 2019-02-13
    • 1970-01-01
    • 2012-11-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-07
    • 2017-03-29
    • 1970-01-01
    • 2015-05-03
    相关资源
    最近更新 更多