为什么我';我无法通过JavaFXWebView中的JavaScript调用从html内容调用Java方法?
我正在处理一项任务,该任务需要从html内容调用java方法。这是一个swing应用程序,我使用JavaFXWebView将HTML内容加载到应用程序中。但当我试图调用Java方法时,它不起作用,有时会出现致命错误并导致应用程序崩溃 Java类为什么我';我无法通过JavaFXWebView中的JavaScript调用从html内容调用Java方法?,java,javafx,javafx-webengine,javafx-webview,Java,Javafx,Javafx Webengine,Javafx Webview,我正在处理一项任务,该任务需要从html内容调用java方法。这是一个swing应用程序,我使用JavaFXWebView将HTML内容加载到应用程序中。但当我试图调用Java方法时,它不起作用,有时会出现致命错误并导致应用程序崩溃 Java类 class Solution extends JFrame { private JFXPanel jfxPanel; static JFrame f; public static void main(String[] args) {
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
点击我
请让我知道此处需要更改的内容,因为用于回调的类和方法必须是public
:
从JavaScript调用Java
JSObject.setMember方法对于从
将JavaScript转换为Java代码,如下例所示。
Java代码建立了一个名为app的新JavaScript对象。这
对象有一个公共成员,即方法出口
public class JavaApplication {
public void exit() {
Platform.exit();
}
}
...
JavaApplication javaApp = new JavaApplication();
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", javaApp);
Java类和方法必须同时声明为公共。
(我的重点。)
您的
解决方案
类不是公共类,因此这不起作用
此外,加载新文档时,窗口
将丢失其属性。由于加载是异步进行的,因此需要确保在加载文档后在窗口上设置成员。您可以通过documentProperty()
上的侦听器执行此操作:
您的代码还存在许多其他问题:
JFrame
s必须在AWT事件调度线程上构造(同样的规则也适用于修改JFrame
中显示的组件)。您可以通过在SwingUtilities.invokeLater(…)
中包装对createUI()
的调用来实现这一点解决方案
作为JFrame
的子类,并在createUI()
中创建一个新的JFrame
。由于您从未使用过Solution
子类JFrame
这一事实,因此应该删除它platformpl
不是公共API的一部分:因此,JavaFX团队可以在以后的版本中删除该类。您应该使用平台
类中的方法解决方案
实例交互,而不是与您创建的任意实例交互。(如果您在内部类中,请使用Solution。此可访问周围对象的当前实例。)
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");
}
}
你能公布你得到的确切错误吗?你是如何测试的?你的
解决方案
类必须是公共的
。(请参阅的“从Javascript调用Java”一节。还请注意模块化应用程序的要求。)可能是OT,但不应使用platformpl
类。使用Platform.setImplicitExit(…)
和Platform.runLater(…)
。您应该使用SwingUtilities.invokeLater()
在AWT事件调度线程上调用createUI()
。但正如建议的那样,发布完整的错误(堆栈跟踪)以获得精确的解决方案。@James\D感谢您的建议。我认为结合这些变化,效果很好。
webEngine.documentProperty().addListener((obs, oldDoc, newDoc) -> {
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", this);
});
webEngine.load(Solution.class.getResource("/mypage.html").toString());
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");
}
}