0

In my JavaFX project, I have a listener on a WebView's WebEngine that waits for a website to fully render. Then I need to access the resulted DOM Document. This does not work if I don't know to which WebEngine the listener belongs!

Creating a variable or simply using the webView that exists is not an option! This is because I'm creating several webViews with ChangeListeners. How can I assign them to each other now?

webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
     public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
        if (newState == Worker.State.SUCCEEDED) {
            // Here I do my stuff
            // I need to access webView.getEngine().getDocument()
        }
     }
});

UPDATE

Here is a minimal working example for the problem I'm facing: https://github.com/mg98/StackOverflow-Demonstration

It is basically about: Main.java

package sample;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.concurrent.Worker;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
import org.w3c.dom.Document;

public class Main extends Application {

    private static Controller ctrl;
    private final static String[] urls = new String[] {
            "https://google.com",
            "https://youtube.com",
            "https://facebook.com",
            "https://twitter.com",
            "https://stackoverflow.com"
    };

    @Override
    public void start(Stage primaryStage) throws Exception{
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("sample.fxml"));
        Parent root = fxmlLoader.load();
        ctrl = fxmlLoader.getController();
        primaryStage.setTitle("Hello World");
        primaryStage.setScene(new Scene(root, 300, 275));
        primaryStage.show();

        findSomething();
    }


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


    private void findSomething() {
        for (int i = 0; i < 5; i++) {
            System.out.println("Request to " + urls[i]);
            WebView webView = ctrl.createWebView();
            webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
                public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState) {
                    if (newState == Worker.State.SUCCEEDED) {
                        // The BIG QUESTION is: What is the corresponding WebEngine to call?
                        Document doc = webView.getEngine().getDocument();
                        // As you will see, the responses print in totally random order
                        System.out.println(doc.getElementsByTagName("title").item(0).getTextContent());
                    }
                }
            });

            webView.getEngine().load(urls[i]);
        }
    }

}

Controller.java

package sample;

import javafx.fxml.FXML;
import javafx.scene.layout.VBox;
import javafx.scene.web.WebView;

public class Controller {

    @FXML
    private VBox browsers;


    @FXML
    protected void initialize() {
    }

    WebView createWebView() {
        WebView webView = new WebView();
        browsers.getChildren().add(webView);
        return webView;
    }

}

sample.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>


<GridPane alignment="center" hgap="10" vgap="10" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/9" fx:controller="sample.Controller">
   <columnConstraints>
      <ColumnConstraints />
   </columnConstraints>
   <rowConstraints>
      <RowConstraints />
   </rowConstraints>
   <children>
      <VBox fx:id="browsers" prefHeight="200.0" prefWidth="100.0" />
   </children>
</GridPane>
primarykey123
  • 137
  • 1
  • 9
  • Possible duplicate of [get the contents from the webview using javafx](https://stackoverflow.com/questions/14273450/get-the-contents-from-the-webview-using-javafx) – SedJ601 Aug 22 '18 at 00:46
  • 1
    What you are asking is unclear. Show a demo of what you have. – SedJ601 Aug 22 '18 at 00:47
  • @Sedrick Sorry. Basically I just need access inside the ChangeListener changed method of the WebEngine that the listener was assigned to. – primarykey123 Aug 22 '18 at 01:22
  • 1
    Please provide a [mcve] that demonstrates the problem. anyway, you seem to have the engine when you register the listener, so why not use it inside as well? – kleopatra Aug 22 '18 at 07:10
  • From your code you could simply call `webView.getEngine().getDocument()` inside the `changed` method. – Slaw Aug 22 '18 at 11:14
  • @kleopatra I cannot do that, because this code is inside a for loop. So that, at the time where listener triggers, the webengine very likely might be already another one. I will update my question for an example – primarykey123 Aug 22 '18 at 13:39
  • you did read the referenced help page - didn't you ;) Why don't you comply with its suggestion? Without, your question will most probably be closed because it's not answerable (and no, as stated in the help page as well, outside resources like gist are not good enough) – kleopatra Aug 22 '18 at 13:47
  • @kleopatra I read it. I don't know what is expected from me :( I provided full classes to my question now. – primarykey123 Aug 22 '18 at 14:04
  • now you are there .. nearly: missing fxml :) The point is that any potential helper can simply throw your code into her IDE and give it run. – kleopatra Aug 22 '18 at 14:10
  • the reason they appear to load randomly is because different sites take different time to complete their load. – SedJ601 Aug 22 '18 at 19:16

1 Answers1

1

Use WebView setUserData and a switch statement to keep up with changes that occur on different sites. If you click on one of the links on a site it will tell you which WebView handled the link.

private void findSomething()
{
    for (int i = 0; i < 5; i++) {
        System.out.println("Request to " + urls[i]);
        WebView webView = ctrl.createWebView();
        webView.setUserData(urls[i]);
        webView.getEngine().getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>()
        {
            @Override
            public void changed(ObservableValue ov, Worker.State oldState, Worker.State newState)
            {
                if (newState == Worker.State.SUCCEEDED) {
                    // The BIG QUESTION is: What is the corresponding WebEngine to call?
                    Document doc = webView.getEngine().getDocument();

                    String userData = webView.getUserData().toString();
                    switch (userData) {
                        case "https://google.com":
                            System.out.println(doc.getElementsByTagName("title").item(0).getTextContent());
                            System.out.println("Do something with the google site");
                            System.out.println("");
                            break;
                        case "https://youtube.com":
                            System.out.println(doc.getElementsByTagName("title").item(0).getTextContent());
                            System.out.println("Do something with the youtube site");
                            break;
                        case "https://facebook.com":
                            System.out.println(doc.getElementsByTagName("title").item(0).getTextContent());
                            System.out.println("Do something with the facebook site");
                            break;
                        case "https://twitter.com":
                            System.out.println(doc.getElementsByTagName("title").item(0).getTextContent());
                            System.out.println("Do something with the twitter site");
                            break;
                        case "https://stackoverflow.com":
                            System.out.println(doc.getElementsByTagName("title").item(0).getTextContent());
                            System.out.println("Do something with the stackoverflow site");
                            break;
                    }

                    // As you will see, the responses print in totally random order
                }
            }
        });

        webView.getEngine().load(urls[i]);
    }
}
SedJ601
  • 12,173
  • 3
  • 41
  • 59