簡體   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