2

我是 JavaFX 编程的新手。我有一个应用程序,其中包含一个简单的登录页面,如此处示例中所述我将 StringProperty 添加到 actiontarget 元素。因此,当 actiontarget 中的文本发生更改时,我想要一个内部带有 webview 的新 FXML 文件,从 FXMLLoader 加载并在屏幕上显示。下面是我得到的例外。我可以加载任何其他 fxml 文件,其中没有 webview,没有问题。在此先感谢。下面的代码示例异常:

java.lang.IllegalStateException: Not on FX application thread; currentThread = Thread-3
at com.sun.javafx.tk.Toolkit.checkFxUserThread(Toolkit.java:237)
at com.sun.javafx.tk.quantum.QuantumToolkit.checkFxUserThread(QuantumToolkit.java:397)
at com.sun.webpane.sg.prism.InvokerImpl.checkEventThread(InvokerImpl.java:33)
at com.sun.webpane.platform.WebPage.<init>(WebPage.java:189)
at com.sun.webpane.sg.ImplementationManager.createPage(ImplementationManager.java:57)
at com.sun.webpane.sg.ImplementationManager.createPage(ImplementationManager.java:51)
at javafx.scene.web.WebEngine.<init>(WebEngine.java:704)
at javafx.scene.web.WebEngine.<init>(WebEngine.java:691)
at javafx.scene.web.WebView.<init>(WebView.java:245)
at student.WebBrowser.<init>(WebBrowser.java:31)
at Login.Login.replaceSceneContent(Login.java:171)
at Login.Login.access$000(Login.java:66)
at Login.Login$2.changed(Login.java:143)
at Login.Login$2.changed(Login.java:137)
at com.sun.javafx.binding.ExpressionHelper$SingleChange.fireValueChangedEvent(ExpressionHelper.java:196)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:100)
at javafx.beans.property.StringPropertyBase.fireValueChangedEvent(StringPropertyBase.java:121)
at javafx.beans.property.StringPropertyBase.markInvalid(StringPropertyBase.java:128)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:161)
at javafx.beans.property.StringPropertyBase.set(StringPropertyBase.java:67)
at javafx.scene.text.Text.setText(Text.java:188)
at Login.Client.run(Client.java:66)

首先我的听众:

// Add change listener
    sp.addListener(new ChangeListener<String>() {
        @Override
        public void changed(ObservableValue<? extends String> ov, String t, String t1) {

            if(t1.equalsIgnoreCase("user authenticated successfully")){
                try {
                    replaceSceneContent(cb.getSelectionModel().getSelectedItem().toString()+".fxml",primaryStage);
                    System.out.println("everything ok");
                } catch (Exception ex) {
                    System.out.println("something went wrong");
                    ex.printStackTrace();
                }
            }
        }
    });

第二个我的方法:replaceSceneContent(String fxml, Stage stage)

private Parent replaceSceneContent(String fxml, Stage stage) throws Exception {
    Parent page = (Parent) FXMLLoader.load(getClass().getResource("/FXML_Files/"+fxml), null, new JavaFXBuilderFactory());      
    Scene scene = stage.getScene();
    if (scene == null) {
        scene = new Scene(page, 700, 450);
        stage.setScene(scene);
    } else {
        stage.getScene().setRoot(page);
    }
    if(fxml.equalsIgnoreCase("Student.fxml")){
        Pane spane = (Pane) page.lookup("#pane");
        WebBrowser wb = new WebBrowser();           
        spane.getChildren().add(wb);            
    }
    return page;
}

和我的 WebBrowser 类类似 NetBeans7.2 中的例子:

public class WebBrowser extends Pane {

    public WebBrowser() {

        WebView view;
        final WebEngine eng;    
        view = new WebView();
        view.setMinSize(10, 10);
        view.setPrefSize(500, 400);
        eng = view.getEngine();
        eng.load("http://www.oracle.com/us/index.html");

        VBox.setVgrow(this, Priority.ALWAYS);
        setMaxWidth(Double.MAX_VALUE);
        setMaxHeight(Double.MAX_VALUE);

        final TextField locationField = new TextField("http://www.oracle.com/us/index.html");
        locationField.setMaxHeight(Double.MAX_VALUE);
        Button goButton = new Button("Go");
        goButton.setDefaultButton(true);
        EventHandler<ActionEvent> goAction = new EventHandler<ActionEvent>() {
            @Override public void handle(ActionEvent event) {
                eng.load(locationField.getText().startsWith("http://") ? locationField.getText() :
                        "http://" + locationField.getText());
            }
        };

        goButton.setOnAction(goAction);
        locationField.setOnAction(goAction);
        eng.locationProperty().addListener(new ChangeListener<String>() {
            @Override public void changed(ObservableValue<? extends String> observable, String oldValue, String newValue) {
                locationField.setText(newValue);
           }
        });
        GridPane grid = new GridPane();
        ButtonsEvents be = new ButtonsEvents();
        TilePane tp = be;
        tp.setAlignment(Pos.CENTER);
        grid.setVgap(5);
        grid.setHgap(5);
        GridPane.setConstraints(locationField, 0, 0, 1, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.SOMETIMES);
        GridPane.setConstraints(goButton,1,0);
        GridPane.setConstraints(view, 0, 1, 2, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.ALWAYS);
        GridPane.setConstraints(tp, 0, 2, 2, 1, HPos.CENTER, VPos.CENTER, Priority.ALWAYS, Priority.NEVER);
        grid.getColumnConstraints().addAll(
                new ColumnConstraints(100, 100, Double.MAX_VALUE, Priority.ALWAYS, HPos.CENTER, true),
                new ColumnConstraints(40, 40, 40, Priority.ALWAYS, HPos.CENTER, true)
        );
        grid.getChildren().addAll(locationField, goButton,view, tp);
        getChildren().add(grid);
    }

    @Override 
    protected void layoutChildren() {
        List<Node> managed = getManagedChildren();
        double width = getWidth();
        double height = getHeight();
        double top = getInsets().getTop();
        double right = getInsets().getRight();
        double left = getInsets().getLeft();
        double bottom = getInsets().getBottom();
        for (int i = 0; i < managed.size(); i++) {
            Node child = managed.get(i);
            layoutInArea(child, left, top,
                           width - left - right, height - top - bottom,
                           0, Insets.EMPTY, true, true, HPos.CENTER, VPos.CENTER);
        }
    }
  }
4

1 回答 1

0

如例外中所述,JavaFX 场景图中的更改只能在 JavaFX 应用程序线程中进行。要确保您的代码在此线程中运行,请尝试以下操作:

Platform.runLater(new Runnable() {
             @Override
             public void run() {
                 // This method is invoked on JavaFX thread
                 replaceSceneContent(cb.getSelectionModel().getSelectedItem().toString()+".fxml",primaryStage);
             }
         });

javafx 管理器将在未来某个时间点在正确的线程上运行此代码。

更多信息: http ://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

于 2012-10-31T08:47:37.540 回答