【问题标题】:Java Swing webEngine.executeScript not firing within HTML Javafx webviewJava Swing webEngine.executeScript 未在 HTML Javafx webview 中触发
【发布时间】:2019-04-05 18:55:28
【问题描述】:

嘿,我已经有一段时间了。到目前为止,我似乎无法从我所看到的所有示例中得到正确的答案。这似乎很容易,但我输了。

我的 HTML:

WebView webView = new WebView();

webView.getEngine().setJavaScriptEnabled(true);
webView.setContextMenuEnabled(false);
webView.getEngine().loadContent(""+
"<!DOCTYPE html>\r\n" + 
    "<html>\r\n" + 
        "<head>\r\n" + 
        "</head>\r\n" +
        "<body>" +
                    "<div class=\"chatbox\" style=\"document.body.style.overflow = 'hidden';\">\r\n" + 
                    "       <div class=\"chatlogs\">\r\n" + 
                    "           <div class=\"animated animatedFadeInUp fadeInUp\">" +
                    "                   <div class=\"chat friend\">\r\n" + 
                    "                   <div class=\"user-photo\"><img src=\"" + pic1 + "\"></div>\r\n" + 
                    "                   <p class=\"chat-message\">Whats up!</p>\r\n" + 
                    "                   <span class=\"timefriend\">11:01pm Oct 25 2019</span>\r\n" + 
                    "               </div>\r\n" + 
                    "           </div>" +
                    "           <div class=\"animated animatedFadeInUp fadeInUp\">" +
                    "               <div class=\"chat self\">\r\n" + 
                    "                   <div class=\"user-photo\"><img src=\"" + pic2 + "\"></div>" + 
                    "                   <p class=\"chat-message\">Not much yo!</p>\r\n" + 
                    "                   <span class=\"timeself\">11:01 PM | Oct 11 2019</span>\r\n" + 
                    "               </div>\r\n" + 
                    "           </div>\r\n" + 
                    "           <div class=\"animated animatedFadeInUp fadeInUp\">" +
                    "               <div class=\"chat friend\">\r\n" + 
                    "                   <div class=\"user-photo\"><img src=\"" + pic1 + "\"></div>" + 
                    "                   <p class=\"chat-message\">Whats up!</p>\r\n" + 
                    "                   <span class=\"timefriend\">11:01 PM | Oct 11 2019</span>\r\n" + 
                    "               </div>\r\n" + 
                    "           </div>\r\n" + 
                    "           <div class=\"animated animatedFadeInUp fadeInUp\">" +
                    "               <div class=\"chat friend\">\r\n" + 
                    "                   <div class=\"user-photo\"><img src=\"" + pic1 + "\"></div>" + 
                    "                   <p class=\"chat-message\">Whats up!</p>\r\n" + 
                    "                   <span class=\"timefriend\">11:01 PM | Oct 11 2019</span>\r\n" + 
                    "               </div>\r\n" + 
                    "           </div>\r\n" + 
                    "           <div id=\"nextChatHolder\"></div>" +
                    "       </div>\r\n" + 
                    "   </div>\r\n" +
                    "   <div class=\"footer\"></div>" + 
                    "   <script language=\"javascript\">\r\n" + 
                    "       function app.test() {\r\n" + 
                    "           window.scrollBy(0, 20); \r\n" + 
                    "           alert('done');\r\n" +
                    "       }\r\n" + 
                    "   </script>" +
                    "</body>\r\n" + 
                "</html>");

这是我正在使用的java(并试图开始工作):

webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<State>()
            {
                public void changed(ObservableValue<? extends State> o, State old, final State state)
                {
                    if (state == State.SUCCEEDED)
                    {
                        JSObject win = (JSObject) webView.getEngine().executeScript("window");
                        win.setMember("app", new JavaApp());
                        //webView.getEngine().executeScript("javaObj.start()");
                    }
                }
            });

private class JavaApp {
        public void test() {
            Platform.exit();
        }
    }

我认为这样做:

function app.test() {\r\n" + 
    window.scrollBy(0, 20); \r\n" + 
    alert('done');\r\n" +
}

并通过以下方式调用它:

webView.getEngine().executeScript("test()");

即使这样也行不通...../

webView.getEngine().executeScript("alert('testing')");

【问题讨论】:

    标签: java eclipse javafx webview


    【解决方案1】:

    从 JavaScript 调用 Java 方法

    对于从 JavaScript 调用 Java 方法 JavaApp#test(),实现的最重要部分已经包含在您的 second 代码 sn-p 中。只有调用本身仍然丢失,例如

    <button onclick='app.test();'>Call JavaApp#test-method</button>
    

    但是,必须考虑两件重要的事情:首先,嵌套类JavaApp必须public。其次,应用程序必须持有对 JavaApp-instance 的引用,这是 JavaScript 回调执行方法所需的(参见 hereCalling back to Java from JavaScript 部分)。

    因此你必须修改你的代码如下:

    JavaApp javaApp = new JavaApp();             // Hold a reference...
    webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
        public void changed(ObservableValue<? extends State> o, State old, final State state) {
            if (state == State.SUCCEEDED) {
                JSObject win = (JSObject) webView.getEngine().executeScript("window");
                win.setMember("app", javaApp);   // Use the reference...
            }
        }
    });
    

    public class JavaApp {                       // Change the access modifier from private to public...
        public void test() {
            Platform.exit();
        }
    }
    

    从 Java 调用 JavaScript 方法

    如果您想从 Java 调用 JavaScript 方法,例如test(),这是用

    完成的
    webView.getEngine().executeScript("test()");
    

    作为一个例子,我使用您的第三个​​ sn-p 中给出的test()-方法,但是名称必须app.test() 更改为@987654336 @。如果调用webView.getEngine().executeScript("test()");,则执行test(),但alert() 方法的例外。这是因为对于某些 JavaScript 方法(如 window.alert()),WebEngine 将请求转发给回调(onAlertwindow.alert() 的情况下)。如果未定义回调,则忽略请求(请参阅here用户界面回调部分)。例如,alert() 的回调可以定义如下:

    webView.getEngine().setOnAlert(event -> showAlert(event.getData()));
    

    其中showAlert(String msg) 是自定义方法,msg 包含原始消息(done 在您的test() 方法的情况下),例如:

    private void showAlert(String msg){
        Alert alert = new Alert(AlertType.INFORMATION);
        alert.setTitle("Custom Alert");
        alert.setHeaderText("");
        alert.setContentText(msg);
        alert.showAndWait();
    }
    

    您可以在How can I make JavaFX web browser displays alert and confirm message 中找到更多示例。

    编辑:

    从 JavaScript 调用 Java 方法的示例代码:当按下按钮时,从 JavaScript 调用 Java 方法 JavaApp#test(),它在 textarea 中输出文本 done

    import javafx.application.Application;
    import javafx.concurrent.Worker.State;
    import javafx.geometry.Insets;
    import javafx.scene.Scene;
    import javafx.scene.control.TextArea;
    import javafx.scene.layout.VBox;
    import javafx.scene.web.WebEngine;
    import javafx.scene.web.WebView;
    import javafx.stage.Stage;
    import netscape.javascript.JSObject;
    
    public class WebViewExecuteJavaFromJavaScript extends Application {
    
        private TextArea textArea;
    
        private static String HTML_STRING = "" +
            "<!DOCTYPE html>\r\n" + 
            "<html>\r\n" + 
            "    <head>\r\n" + 
            "    </head>\r\n" +
            "    <body>" +
            "        <button onclick='app.test();'>Call Java-method JavaApp#test()...</button>" +    // Call Java-method JavaApp#test()...
            "    </body>\r\n" + 
            "</html>";
    
        @Override
        public void start(final Stage stage) {
    
            WebView webView = new WebView();
            WebEngine webEngine = webView.getEngine();
            webEngine.setJavaScriptEnabled(true);
            webEngine.loadContent(HTML_STRING);
    
            JavaApp javaApp = new JavaApp();    
            webEngine.getLoadWorker().stateProperty().addListener((o, oldState, newState) -> {
                if (newState == State.SUCCEEDED) {
                    JSObject win = (JSObject) webView.getEngine().executeScript("window");
                    win.setMember("app", javaApp);                                                   // Enable call of Java-method from JavaScript...
                }
            });
    
            textArea = new TextArea();
            textArea.setWrapText(true);
    
            VBox root = new VBox();
            root.setPadding(new Insets(5));
            root.setSpacing(5);
            root.getChildren().addAll(webView, textArea);
    
            Scene scene = new Scene(root); 
            stage.setTitle("Demo: Execute Java from JavaScript");
            stage.setScene(scene);
            stage.setWidth(450);
            stage.setHeight(300); 
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    
        public class JavaApp {
            public void test() {
                textArea.setText(textArea.getText() + "done ");
            }
        }
    }
    

    从 Java 调用 JavaScript 方法的示例代码:按下按钮时,从 Java 调用 JavaScript 方法 test(),它在文本区域和对话框中输出文本 done

    import javafx.application.Application;
    import javafx.geometry.Insets;
    import javafx.scene.Scene;
    import javafx.scene.control.Alert;
    import javafx.scene.control.Alert.AlertType;
    import javafx.scene.control.Button;
    import javafx.scene.layout.VBox;
    import javafx.scene.web.WebEngine;
    import javafx.scene.web.WebView;
    import javafx.stage.Stage;
    
    public class WebViewExecuteJavaScriptFromJava extends Application {
    
        private static String HTML_STRING = "" +
            "<!DOCTYPE html>\r\n" + 
            "<html>\r\n" + 
            "    <head>\r\n" + 
            "    </head>\r\n" +
            "    <body>" +
            "        <textarea id=\"textarea\" name=\"textarea\" cols=55 rows=3 wrap=\"virtual\"></textarea>" + 
            "        <script language=\"javascript\">\r\n" + 
            "            function test() {\r\n" + 
            "                textarea.value+='done '; \r\n" + 
            "                alert('done');\r\n" +                                      // Is ignored as long as no callback is defined...
            "            }\r\n" + 
            "        </script>" +
            "    </body>\r\n" + 
            "</html>";
    
        @Override
        public void start(final Stage stage) {
    
            WebView webView = new WebView();
            WebEngine webEngine = webView.getEngine();
            webEngine.setJavaScriptEnabled(true);
            webEngine.loadContent(HTML_STRING);
            webEngine.setOnAlert(event -> showAlert(event.getData()));                  // Define callback for JavaScript-alert...
    
            Button button = new Button("Call JavaScript-method test()...");
            button.setOnAction(event -> webView.getEngine().executeScript("test()"));   // Call JavaScript-method test()...
    
            VBox root = new VBox();
            root.setPadding(new Insets(5));
            root.setSpacing(5);
            root.getChildren().addAll(button, webView);
    
            Scene scene = new Scene(root); 
            stage.setTitle("Demo: Execute JavaScript from Java");
            stage.setScene(scene);
            stage.setWidth(450);
            stage.setHeight(300); 
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    
        private void showAlert(String msg){
            Alert alert = new Alert(AlertType.INFORMATION);
            alert.setTitle("Custom Alert");
            alert.setHeaderText("");
            alert.setContentText(msg);
            alert.showAndWait();
        }
    }
    

    【讨论】:

    • 似乎没有调用 javascript。我在 html 页面上放置了一个调用相同函数 (test()) 的按钮,当我启动它时它什么也不做,但如果我单击该按钮,它会显示来自 java 的警报框。我需要能够在我的应用程序中调用该 test() 函数并启动它。
    • 我建议不要使用 JavaScript-alert 进行初始测试,因为它仅在实现 setOnAlert/showAlert-stuff 之后才有效。使用另一个输出,例如在 textarea 或类似的地方。如果 JavaFX->JavaScript 调用本身有效,alert-callback 可以稍后实现(如果需要的话)。实际上,实现并不是很复杂。也许我们正在谈论不同的目的,或者在您的环境中存在其他问题。我认为最简单的方法是发布我的测试代码,它在我的机器上运行没有任何问题。
    猜你喜欢
    • 2021-02-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-02
    • 1970-01-01
    相关资源
    最近更新 更多