Search code examples
javajavafxjsoup

Updating UI from another Thread extended Class


What I want to do:

[Web Scraping with Jsoup]

Adding elements to a TableView from an another Thread extended Class.

Button click -> start Thread -> Thread add elements to TableView.

Files

|javafxapplication5
|-->FXMLDocuments.fxml
|-->FXMLDocumentController.java
|-->JavaFXApplication5.java
|-->Scraper.java

FXMLDocumentController.java

package javafxapplication5;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;


public class FXMLDocumentController implements Initializable {
    Scraper scraper = new Scraper();
    
    @FXML
    private Label label;
    
    @FXML
    private Button shareButton;
    
    @FXML
    private TextField searchInput;

    @FXML
    private Button searchTorrents;

    @FXML
    private void handleButtonAction(ActionEvent event) {
        System.out.println("You clicked me!");
    }
    
    @FXML
    private void setMouseEntered(MouseEvent event)
    {
        searchTorrents.setStyle("-fx-border-color:blue");
    }
    @FXML
    private void setMouseLeaved(MouseEvent event)
    {
        searchTorrents.setStyle("-fx-border-color:black");
    }
    
    @FXML
    private void shareButton(ActionEvent event)
    {
        Alert alert = new Alert(Alert.AlertType.INFORMATION);
        alert.setHeaderText("Hai cliccato il bottone share");
        alert.showAndWait();
    }
    
    @FXML
    private void scrapButton(ActionEvent event)
    {
        scraper.start();
    }
     
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }    
    
}

Scraper.java

package javafxapplication5;

import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;


public class Scraper extends Thread{
    public void run()
    {
        Document doc;
        try {
            doc = Jsoup.connect("https://www.allkeyshop.com/blog/daily-deals/").get();
            Elements gamesNames = doc.select(".search-results-row-game-title");
            for (Element element:gamesNames)
            {
                //Update TableView
            }
        } catch (IOException ex) {
            Logger.getLogger(TorrentScraper.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}

I hope is everything clear, if not please answer me with a constructive suggestion.


Solution

  • Here is an example you can use as a guide. The URL you use does not have a result list. I would suggest you use something like https://www.allkeyshop.com/blog/catalogue/search-game/. It appears, what comes after the hyphen is what is being searched. You may need to do a few complicated searches to see how the URL changes.

    This example uses Task. In the Task setOnSuccedded updates the TableView.

    Main

    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import javafx.application.Application;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.concurrent.Task;
    import javafx.concurrent.WorkerStateEvent;
    import javafx.scene.Scene;
    import javafx.scene.control.Button;
    import javafx.scene.control.TableColumn;
    import javafx.scene.control.TableView;
    import javafx.scene.control.TextField;
    import javafx.scene.control.cell.PropertyValueFactory;
    import javafx.scene.layout.VBox;
    import javafx.stage.Stage;
    import org.jsoup.Jsoup;
    import org.jsoup.nodes.Document;
    import org.jsoup.nodes.Element;
    import org.jsoup.select.Elements;
    
    /**
     * JavaFX App
     */
    public class App extends Application
    {
    
        @Override
        public void start(Stage primaryStage)
        {
            TableView<JSoupData> tvMain = new TableView();
            ObservableList<JSoupData> tableItems = FXCollections.observableArrayList();
            tvMain.setItems(tableItems);
    
            TableColumn<JSoupData, String> tcTagName = new TableColumn<>("Tag Name");
            tcTagName.setCellValueFactory(new PropertyValueFactory<>("tagName"));
            TableColumn<JSoupData, String> tcText = new TableColumn<>("Text");
            tcText.setCellValueFactory(new PropertyValueFactory<>("text"));
            tvMain.getColumns().add(tcTagName);
            tvMain.getColumns().add(tcText);
    
            TextField tfUrl = new TextField("https://www.allkeyshop.com/blog/catalogue/search-game/");
            tfUrl.setPromptText("Enter URL Here!");
    
            Button btnProcess = new Button("Process URL");
            btnProcess.setOnAction((t) -> {
                btnProcess.setDisable(true);
    
                Task<List<JSoupData>> task = scrapper(tfUrl.getText());
                task.setOnSucceeded((WorkerStateEvent t1) -> {
                    List<JSoupData> tempList = task.getValue();
                    tableItems.setAll(tempList);
                    btnProcess.setDisable(false);
                });
                Thread thread = new Thread(task);
                thread.setDaemon(true);
                thread.start();
            });
            VBox root = new VBox(tvMain, tfUrl, btnProcess);
    
            Scene scene = new Scene(root);
            primaryStage.setScene(scene);
            primaryStage.show();
        }
    
        public static void main(String[] args)
        {
            launch();
        }
    
        public Task<List<JSoupData>> scrapper(String url)
        {
            Task<List<JSoupData>> scrapperTask = new Task<List<JSoupData>>()
            {
                @Override
                protected List<JSoupData> call()
                {
                    List<JSoupData> jSoupDatas = new ArrayList();
                    try {
                        System.out.println("url: " + url);
                        Document document = Jsoup.connect(url).get();
                        System.out.println("Title: " + document.title());
                        Elements gamesNames = document.select(".search-results-row");
                        System.out.println("search-results-row");
                        for (Element element : gamesNames) {
                            jSoupDatas.add(new JSoupData(element.tagName(), element.text()));
                            System.out.println("Tag Name: " + element.tagName() + " - Text: " + element.text());
                        }
                    }
                    catch (IOException e) {
                        System.out.println(e.toString());
                    }
    
                    return jSoupDatas;
                }
            };
    
            return scrapperTask;
        }
    }
    

    JSoupData

     *
     * @author sedrick (sedj601)
     */
    public class JSoupData
    {
    
        private String tagName;
        private String text;
    
        public JSoupData(String tagName, String text)
        {
            this.tagName = tagName;
            this.text = text;
        }
    
        public String getText()
        {
            return text;
        }
    
        public void setText(String text)
        {
            this.text = text;
        }
    
        public String getTagName()
        {
            return tagName;
        }
    
        public void setTagName(String tagName)
        {
            this.tagName = tagName;
        }
    
        @Override
        public String toString()
        {
            StringBuilder sb = new StringBuilder();
            sb.append("JSoupData{tagName=").append(tagName);
            sb.append(", text=").append(text);
            sb.append('}');
            return sb.toString();
        }
    }
    

    enter image description here