来自JavaScript的JavaFXWebView向上调用不';行不通
我有一个JavaFXWebView,希望从WebView中显示的“test.html”调用类“JavaBridge”的方法“hello”。 为什么这样不行?我要确保“bridge”对象只在页面完全呈现时添加到window.object,所以这可能不是问题所在。我也看不出HTML有什么问题 下面是HTML代码(“test.HTML”):来自JavaScript的JavaFXWebView向上调用不';行不通,javascript,java,html,javafx,webview,Javascript,Java,Html,Javafx,Webview,我有一个JavaFXWebView,希望从WebView中显示的“test.html”调用类“JavaBridge”的方法“hello”。 为什么这样不行?我要确保“bridge”对象只在页面完全呈现时添加到window.object,所以这可能不是问题所在。我也看不出HTML有什么问题 下面是HTML代码(“test.HTML”): 下面是Java代码: import javafx.application.Application; import javafx.beans.value.Cha
下面是Java代码:
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import netscape.javascript.JSObject;
public class HelloWorld extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
java.net.URI uri = java.nio.file.Paths.get("test.html").toAbsolutePath().toUri();
WebView root = new javafx.scene.web.WebView();
root.getEngine().load(uri.toString());
root.getEngine().
getLoadWorker().
stateProperty().
addListener(new ChangeListener < State > () {
@Override public void changed(ObservableValue ov, State oldState, State newState) {
if (newState == Worker.State.SUCCEEDED) {
System.out.println("READY");
JSObject jsobj = (JSObject) root.getEngine().executeScript("window");
jsobj.setMember("bridge", new JavaBridge());
}
}
});
primaryStage.setScene(new javafx.scene.Scene(root, 800, 600));
primaryStage.show();
}
}
class JavaBridge {
public void hello() {
System.out.println("hello");
}
}
导入javafx.application.application;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.concurrent.Worker;
导入javafx.concurrent.Worker.State;
导入javafx.scene.scene;
导入javafx.scene.control.Button;
导入javafx.scene.layout.StackPane;
导入javafx.stage.stage;
导入javafx.scene.web.WebEngine;
导入javafx.scene.web.WebView;
导入netscape.javascript.JSObject;
公共类HelloWorld扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
java.net.URI URI=java.nio.file.Paths.get(“test.html”).toabsolutionPath().toUri();
WebView root=newjavafx.scene.web.WebView();
root.getEngine().load(uri.toString());
root.getEngine()。
getLoadWorker()。
stateProperty()。
addListener(新的ChangeListener(){
@覆盖公共无效已更改(ObservalEvalue ov、State oldState、State newState){
if(newState==Worker.State.successed){
System.out.println(“就绪”);
JSObject jsobj=(JSObject)root.getEngine().executeScript(“窗口”);
setMember(“bridge”,新的JavaBridge());
}
}
});
setScene(新的javafx.scene.scene(root,800600));
primaryStage.show();
}
}
类JavaBridge{
公共空间{
System.out.println(“你好”);
}
}
您的内部类应该在主类中。它应该是公开的。像这样:
import java.net.URL;
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.concurrent.Worker.State;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import netscape.javascript.JSObject;
public class HelloWorld extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
final URL url = getClass().getResource("test.html");
WebView root = new javafx.scene.web.WebView();
root.getEngine().load(url.toExternalForm());
root.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
@Override
public void changed(ObservableValue ov, State oldState, State newState) {
if (newState == Worker.State.SUCCEEDED) {
System.out.println("READY");
JSObject jsobj = (JSObject) root.getEngine().executeScript("window");
jsobj.setMember("bridge", new JavaBridge());
}
}
});
primaryStage.setScene(new javafx.scene.Scene(root, 800, 600));
primaryStage.show();
}
public class JavaBridge {
public void hello() {
System.out.println("hello");
}
}
}
import java.net.URL;
导入javafx.application.application;
导入javafx.beans.value.ChangeListener;
导入javafx.beans.value.observeValue;
导入javafx.concurrent.Worker;
导入javafx.concurrent.Worker.State;
导入javafx.scene.web.WebView;
导入javafx.stage.stage;
导入netscape.javascript.JSObject;
公共类HelloWorld扩展了应用程序{
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
最终URL=getClass().getResource(“test.html”);
WebView root=newjavafx.scene.web.WebView();
root.getEngine().load(url.toExternalForm());
root.getEngine().getLoadWorker().stateProperty().addListener(新的ChangeListener()){
@凌驾
公共无效已更改(ObservalEvalue ov、State oldState、State newState){
if(newState==Worker.State.successed){
System.out.println(“就绪”);
JSObject jsobj=(JSObject)root.getEngine().executeScript(“窗口”);
setMember(“bridge”,新的JavaBridge());
}
}
});
setScene(新的javafx.scene.scene(root,800600));
primaryStage.show();
}
公共类JavaBridge{
公共空间{
System.out.println(“你好”);
}
}
}
在Java 10.0.2上使用此桥接功能时,我注意到它工作不一致。Javascript向上调用并非一直有效
经过研究,我发现这个OpenJDK错误与Java垃圾收集器有关,这似乎也发生在普通JDK上:
实际上,根据,建议将桥存储到变量中,以避免Java GC收集对象
在向类中添加私有变量后,JS到Java调用在我的应用程序中开始一直起作用。我也遇到了同样的问题,解决这个问题的唯一方法是将桥存储在静态变量上。 这是一个使用JavaFXFileChooser的示例
public class Controller implements Initializable {
@FXML private WebView webview;
@FXML private JFXButton btn_insertimg;
@FXML private AnchorPane anchorpane;
private WebEngine webEngine;
public static Bridge bridge; //it's important to be static
@Override
public void initialize(URL location, ResourceBundle resources) {
webEngine = webview.getEngine();
webEngine.getLoadWorker().stateProperty().addListener(
(ov, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
//todo when the document is fully loaded
FileChooser fileChooser=new FileChooser();
bridge=new Bridge(webview,fileChooser);
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("myFileChooser", bridge);
System.out.println("member "+window.getMember("myFileChooser").toString());;
}//end of SUCCEEDED state
});
webEngine.load(getClass().getResource("/patient/texteditor/summernote.html").toExternalForm());
}
public class Bridge{
FileChooser fileChooser;
WebView webView;
Bridge(WebView webView,FileChooser fileChooser){
this.webView=webView;
this.fileChooser=fileChooser;
}
public void display(){
fileChooser.showOpenDialog(webView.getScene().getWindow());
}
}
}
无论它是一个内部类,还是在自己的源文件中定义的顶级类,将其公开是很重要的。谢谢,我来自一种没有定义为public的类默认为public的语言。你能给我推荐一个编辑器,让我概括一下我的类的签名吗?:)在JavaFX13上对我不起作用。它显示的是“准备好了”,但不是“你好”。你知道这是为什么吗?谢谢,谢谢!你的回答一下子帮我解决了两个问题:)
public class Controller implements Initializable {
@FXML private WebView webview;
@FXML private JFXButton btn_insertimg;
@FXML private AnchorPane anchorpane;
private WebEngine webEngine;
public static Bridge bridge; //it's important to be static
@Override
public void initialize(URL location, ResourceBundle resources) {
webEngine = webview.getEngine();
webEngine.getLoadWorker().stateProperty().addListener(
(ov, oldState, newState) -> {
if (newState == Worker.State.SUCCEEDED) {
//todo when the document is fully loaded
FileChooser fileChooser=new FileChooser();
bridge=new Bridge(webview,fileChooser);
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("myFileChooser", bridge);
System.out.println("member "+window.getMember("myFileChooser").toString());;
}//end of SUCCEEDED state
});
webEngine.load(getClass().getResource("/patient/texteditor/summernote.html").toExternalForm());
}
public class Bridge{
FileChooser fileChooser;
WebView webView;
Bridge(WebView webView,FileChooser fileChooser){
this.webView=webView;
this.fileChooser=fileChooser;
}
public void display(){
fileChooser.showOpenDialog(webView.getScene().getWindow());
}
}
}