[英]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.