JavaFX 使用 JavaScript 调用 Java 方法

Kür*_*oro 2 javascript java javafx

我的应用程序完全采用 Web 文档形式(HTML、CSS 和 JavaScript)设计,我仅使用 JavaFX WebView 将其作为普通资源加载。

我想使用 JavaScript 从我的一个类(Java 代码)中调用一个方法。

例如,一个简单的 Hello World 到控制台:

public class Hello {
  public void world() {
    System.out.println("Hello World!");
  }
}
Run Code Online (Sandbox Code Playgroud)

world()在这种情况下如何调用该方法?

所以我的页面代码是这样的:

<!-- onlick action from a button calls hello() function -->
<button onclick="hello();" value="Invoke"></button>

<script>
  function hello() {
    /* CODE WHICH INVOKE A JAVA METHOD */
  }
</script>
Run Code Online (Sandbox Code Playgroud)

有什么方法可以实现这一目标吗?


更新

注意:对于那些正在寻找有关如何实现这一点的完整和简单示例的人,您可以测试下面编写的所有以下代码。

感谢@Oshan_Mendis 先生的回答,我终于实现了我的目标。此示例基于 Oracle 文档中的本教程:6 Making Upcalls from JavaScript to JavaFX

但在这里,我将使用我自己的代码,主要目标是使用 HTML 页面中的 JavaScript 从 Java 代码调用方法。

文件内容:

Controller.java   /* Controller class for WebView */
Hello.java        /* Class in which method(s) will be invoked */
Main.java         /* Main class (launches the application) */
main.fxml         /* Main layout (WebView) */
index.html        /* Main layout web page content */
Run Code Online (Sandbox Code Playgroud)

1. 创建主类 (Main.java)

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {
  @Override
  public void start(Stage stage) throws Exception {
    /* The root layout of the application, an FXML contains the WebView layout. */
    Parent root = FXMLLoader.load(Main.class.getResource("/main.fxml"));
    Scene scene = new Scene(root);
    stage.setScene(scene);
    stage.show();
  }
  public static void main(String[] args) {
    launch(args);
  }
}
Run Code Online (Sandbox Code Playgroud)

2. 准备主布局(main.fxml)

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.web.WebView?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns="http://javafx.com/javafx/8"
      xmlns:fx="http://javafx.com/fxml/1"
      fx:controller="Controller"  <!-- The controller class for this layout -->
      prefHeight="400.0"
      prefWidth="300.0">
  <children>
    <!-- Given the webView ID to initiate the web page -->
    <WebView fx:id="webView" />
  </children>
</VBox>
Run Code Online (Sandbox Code Playgroud)

3.设置网页(Controller.java)

import java.net.URL;
import java.util.ResourceBundle;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker.State;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;

public class Controller implements Initializable {
  private WebEngine webEngine;
  @FXML private WebView webView;
  @Override
  public void initialize(URL location, ResourceBundle resources) {
    /* Load the web page URL (location of the resource) */
    URL url = Controller.class.getResource("/index.html");
    webEngine = webView.getEngine();
    webEngine.load(url.toExternalForm());
    /* Set the State listener as well as the name of the JavaScript object and its
     * corresponding Java object (the class in which methods will be invoked) that
     * will serve as the bridge for the two objects.
     */
    webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
      @Override
      public void changed(ObservableValue<? extends State> observableValue, State oldState, State newState) {
        if (newState == State.SUCCEEDED) {
          JSObject window = (JSObject) webEngine.executeScript("window");
          /* The two objects are named using the setMember() method. */
          window.setMember("invoke", new Hello());
        }
      }
    });
  }
}
Run Code Online (Sandbox Code Playgroud)

4.首选类及其调用方法(Hello.java)

public class Hello {
  public void world() {
    System.out.println("Hello World!");
  }
}
Run Code Online (Sandbox Code Playgroud)

5. 主要布局网页内容(index.html)

<!DOCTYPE html>
<html>
  <head>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script>
      function helloWorld() {
        /* JavaScript object name and the method to invoke */
        invoke.world();
      }
    </script>
  </head>
  <body>
    <!-- onlick event calls helloWorld() function -->
    <button onclick="helloWorld()">INVOKE</button>
  </body>
</html>
Run Code Online (Sandbox Code Playgroud)

注意:在这种情况下,您可以执行除 onclick 事件之外的其他与鼠标相关的事件,例如:onmouseenter、onmouseover、onmousemove、onmouseup 等。但我不确定这些是否是唯一支持的调用方法事件。

小智 5

这在从 JavaScript 回调到 Java下的Java API 文档中得到了很好的解释

public class JavaApplication {
    public void exit() {
        Platform.exit();
    }
}
...
JavaApplication javaApp = new JavaApplication();
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("app", javaApp);
Run Code Online (Sandbox Code Playgroud)

然后,您可以从 HTML 页面引用对象和方法:

<a href="" onclick="app.exit()">Click here to exit application</a>
Run Code Online (Sandbox Code Playgroud)

  • 重要说明:自 Java 8u101 以来存在 [bug](/sf/ask/2933220811/)。`javaApp` 应该定义在一个私有字段中,以防止垃圾收集删除它。局部变量一开始似乎可以工作,但会随机停止工作。 (9认同)