GeorgePap
GeorgePap

Reputation: 307

Change between two FXML files in JavaFX2.2 on change Listener

i am new in JavaFX programming. I have an Application, with a simple login page as described in the example here, and i add a StringProperty to the actiontarget element. So when the text changes inside the actiontarget i want a new FXML file with a webview inside, to load from the FXMLLoader and be dipslayed on the screen. Below is the exception i get. I can load any other fxml file, without a webview inside it, without a problem. Thanks in advance.Code samples below The exception :

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)

First my listener:

// 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();
                }
            }
        }
    });

Second my method : 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;
}

And my WebBrowser class similar to the example in 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);
        }
    }
  }

Upvotes: 2

Views: 1568

Answers (1)

zhujik
zhujik

Reputation: 6574

As stated in the exception, changes in the JavaFX scene graph can only be made in the JavaFX application thread. To make sure your code is run in this thread, try the following:

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

The javafx manager will run this code at some point in the future on the correct thread.

More information: http://docs.oracle.com/javafx/2/threads/jfxpub-threads.htm

Upvotes: 0

Related Questions