为什么我';我无法通过JavaFXWebView中的JavaScript调用从html内容调用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) {   

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

Java类

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团队可以在以后的版本中删除该类。您应该使用
    平台
    类中的方法
  • 您几乎肯定希望Javascript回调与当前的
    解决方案
    实例交互,而不是与您创建的任意实例交互。(如果您在内部类中,请使用
    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");
        }
    
    }