来自JavaScript的JavaFXWebView向上调用不';行不通

来自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

我有一个JavaFXWebView,希望从WebView中显示的“test.html”调用类“JavaBridge”的方法“hello”。 为什么这样不行?我要确保“bridge”对象只在页面完全呈现时添加到window.object,所以这可能不是问题所在。我也看不出HTML有什么问题

下面是HTML代码(“test.HTML”):


下面是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());
        }
    }

}