繁体   English   中英

Why I'm unable to invoke Java methods from html content via the JavaScript call in JavaFX WebView?

[英]Why I'm unable to invoke Java methods from html content via the JavaScript call in JavaFX WebView?

我正在处理需要从 html 内容调用 java 方法的任务。 这是一个 swing 应用程序,我使用 JavaFX WebView 将 Z4C4AD5FCA2E7A3F74DBB1CED0038 内容加载到应用程序中。 但是当我尝试调用 Java 方法时它不起作用,有时它会给出致命错误并使应用程序崩溃。

Java class

class Solution extends JFrame { 
    
private JFXPanel jfxPanel;
static JFrame f; 

public static void main(String[] args) {
    new Solution().createUI();
}

    private void createUI() {
f = new JFrame("panel"); 

JPanel p = new JPanel(); 

jfxPanel = new JFXPanel();
createScene();
p.add(jfxPanel);

f.add(p);
f.setSize(300, 300); 
f.show(); 
    } 
    
    private void createScene() {
        
PlatformImpl.setImplicitExit(false);
PlatformImpl.runAndWait(new Runnable() {
@Override
public void run() {
BorderPane borderPane = new BorderPane();
WebView webComponent = new WebView();
WebEngine webEngine = webComponent.getEngine();

webEngine.load(TestOnClick.class.getResource("/mypage.html").toString());

borderPane.setCenter(webComponent);
Scene scene = new Scene(borderPane,300,300);
jfxPanel.setScene(scene);

JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", new Solution());
}
});
}
    
    public void onClick() {
        System.out.println("Invoked from JS");
    }
}

HTML

<button onclick="app.onClick()">Click ME</button>

请让我知道这里需要更改什么

文档中,用于回调的 class 和方法都必须是public的:

从 JavaScript 回调到 Java

JSObject.setMember 方法可用于启用从 JavaScript 到 Java 代码的向上调用,如以下示例所示。 Java 代码建立了一个名为 app. 这个 object 有一个公共成员,方法退出。

 public class JavaApplication { public void exit() { Platform.exit(); } }... JavaApplication javaApp = new JavaApplication(); JSObject window = (JSObject) webEngine.executeScript("window"); window.setMember("app", javaApp);

...

Java class 和方法都必须声明为 public。

(我的重点。)

您的Solution class 不是公开的,所以这不起作用。

此外,当加载新文档时, window将失去其属性。 由于加载是异步进行的,因此您需要确保在文档加载后在 window 上设置成员。 您可以通过documentProperty()上的侦听器执行此操作:

    webEngine.documentProperty().addListener((obs, oldDoc, newDoc) -> {
        JSObject window = (JSObject) webEngine.executeScript("window");
        window.setMember("app", this);          
    });

    webEngine.load(Solution.class.getResource("/mypage.html").toString());

您的代码还有许多其他问题:

  1. JFrame必须在 AWT 事件调度线程上构造(同样的规则也适用于修改JFrame中显示的组件)。 您可以通过在SwingUtilities.invokeLater(...)中包装对createUI()的调用来做到这一点。
  2. 目前尚不清楚为什么您将Solution JFrame的子类,以及createUI()中创建新的JFrame 由于您从不使用Solution子类JFrame的事实,因此您应该删除它。
  3. PlatformImpl不是公共 API 的一部分:因此 JavaFX 团队可以在以后的版本中删除该 class。 您应该使用Platform class 中的方法。
  4. 您几乎肯定希望 Javascript 回调与当前Solution实例交互,而不是您创建的任意实例。 (如果您在内部 class 中,请使用Solution.this访问周围 object 的当前实例。)

您的代码的工作版本是

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;

public class Solution  {

    private JFXPanel jfxPanel;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Solution()::createUI);
    }



    private void createUI() {
        JFrame f = new JFrame("panel");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel p = new JPanel();

        jfxPanel = new JFXPanel();
        createScene();
        p.add(jfxPanel);

        f.add(p);
        f.setSize(300, 300);
        f.setVisible(true);
    }

    private void createScene() {

        Platform.setImplicitExit(false);
        Platform.runLater(() -> {
            BorderPane borderPane = new BorderPane();
            WebView webComponent = new WebView();
            WebEngine webEngine = webComponent.getEngine();

            webEngine.documentProperty().addListener((obs, oldDoc, newDoc) -> {
                JSObject window = (JSObject) webEngine.executeScript("window");
                window.setMember("app", this);          
            });

            webEngine.load(Solution.class.getResource("/mypage.html").toString());

            borderPane.setCenter(webComponent);
            Scene scene = new Scene(borderPane, 300, 300);
            jfxPanel.setScene(scene);

        });
    }

    public void onClick() {
        System.out.println("Invoked from JS");
    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM