Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detect URL change in JavaFX WebView

In JavaFX's WebView I am struggling to detect change in URL.

I have this method in a class:

public Object urlchange() {
    engine.getLoadWorker().stateProperty().addListener(new ChangeListener<State>() {
        @Override
        public void changed(ObservableValue ov, State oldState, State newState) {
            if (newState == Worker.State.SUCCEEDED) {
                return engine.getLocation()); 
            }
        }
    });         
}

and I am trying to use it for an object called loginbrowser like:

System.out.print(loginbrowser.urlchange());

Can you see what I've done wrong?

like image 786
user6130327 Avatar asked Mar 30 '16 23:03

user6130327


1 Answers

(Part of) what you are doing wrong

The code you provided in your question doesn't even compile. The changed method of a ChangeListener is a void function, it can't return any value.

Anyway, loading of stuff in a web view is an asynchronous process. If you want the value of the location of the web view after the web view has loaded, you need to either wait for the load to complete (inadvisable on the JavaFX application thread, as that would hang your application until the load is complete), or be notified in a callback that the load is complete (which is what the listener you have is doing).

(Probably) what you want to do

Bind some property to the location property of the web engine. For example:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.web.*;
import javafx.stage.Stage;

public class LocationViewer extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Label location = new Label();

        WebView webView = new WebView();
        WebEngine engine = webView.getEngine();
        engine.load("http://www.fxexperience.com");

        location.textProperty().bind(engine.locationProperty());

        Scene scene = new Scene(new VBox(10, location, webView));
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

The above code will update the location label whenever the location of the web view changes (try it by running the code then clicking on some links). If you wish to only update the label once a page has successfully loaded, then you need a listener based upon the WebView state, for example:

import javafx.application.Application;
import javafx.concurrent.Worker;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.scene.web.*;
import javafx.stage.Stage;

public class LocationAfterLoadViewer extends Application {
    @Override
    public void start(Stage stage) throws Exception {
        Label location = new Label();

        WebView webView = new WebView();
        WebEngine engine = webView.getEngine();
        engine.load("http://www.fxexperience.com");

        engine.getLoadWorker().stateProperty().addListener((observable, oldValue, newValue) -> {
            if (Worker.State.SUCCEEDED.equals(newValue)) {
                location.setText(engine.getLocation());
            }
        });

        Scene scene = new Scene(new VBox(10, location, webView));
        stage.setScene(scene);
        stage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

If you run the last program and click on some links, you will notice it delays the updating of the location label until after the pages you click on completely finish loading, as opposed to the first program which updates the label as soon as the location changes, regardless of whether the load takes a while or indeed works at all.

Answers to additional questions

How can I use the url value in the label in a conditional statement? I want an action to be preformed if it changed from the original one.

location.textProperty().addListener((observable, oldValue, newValue) -> {
    // perform required action.
});
like image 173
jewelsea Avatar answered Sep 19 '22 11:09

jewelsea