![](/img/trans.png)
[英]When I invoke a Java function from my Javascript code, WebView crashes. Why?
[英]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());
您的代码还有许多其他问题:
JFrame
必须在 AWT 事件调度线程上构造(同样的规则也适用于修改JFrame
中显示的组件)。 您可以通过在SwingUtilities.invokeLater(...)
中包装对createUI()
的调用来做到这一点。Solution
JFrame
的子类,以及在createUI()
中创建新的JFrame
。 由于您从不使用Solution
子类JFrame
的事实,因此您应该删除它。PlatformImpl
不是公共 API 的一部分:因此 JavaFX 团队可以在以后的版本中删除该 class。 您应该使用Platform
class 中的方法。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.