从另一个线程更新UI的扩展类

huangapple go评论191阅读模式
英文:

Updating UI from another Thread extended Class

问题

我想要做的事情:

[使用Jsoup进行网页抓取]

从另一个扩展了Thread类的线程中将元素添加到TableView中。

按钮点击 -> 启动线程 -> 线程将元素添加到TableView中。

文件

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

希望一切都清楚,如果不清楚,请用建设性的建议回答我。

英文:

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.

答案1

得分: 1

以下是您要翻译的内容:

这里有一个示例,您可以用作指南。您使用的URL没有结果列表。我建议您使用类似于https://www.allkeyshop.com/blog/catalogue/search-game/的内容。看起来,连字符后面的内容是被搜索的内容。您可能需要进行一些复杂的搜索,以查看URL如何变化。

此示例使用了Task。在TasksetOnSucceeded中更新了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;

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

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

从另一个线程更新UI的扩展类

英文:

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&lt;JSoupData&gt; tvMain = new TableView();
ObservableList&lt;JSoupData&gt; tableItems = FXCollections.observableArrayList();
tvMain.setItems(tableItems);
TableColumn&lt;JSoupData, String&gt; tcTagName = new TableColumn&lt;&gt;(&quot;Tag Name&quot;);
tcTagName.setCellValueFactory(new PropertyValueFactory&lt;&gt;(&quot;tagName&quot;));
TableColumn&lt;JSoupData, String&gt; tcText = new TableColumn&lt;&gt;(&quot;Text&quot;);
tcText.setCellValueFactory(new PropertyValueFactory&lt;&gt;(&quot;text&quot;));
tvMain.getColumns().add(tcTagName);
tvMain.getColumns().add(tcText);
TextField tfUrl = new TextField(&quot;https://www.allkeyshop.com/blog/catalogue/search-game/&quot;);
tfUrl.setPromptText(&quot;Enter URL Here!&quot;);
Button btnProcess = new Button(&quot;Process URL&quot;);
btnProcess.setOnAction((t) -&gt; {
btnProcess.setDisable(true);
Task&lt;List&lt;JSoupData&gt;&gt; task = scrapper(tfUrl.getText());
task.setOnSucceeded((WorkerStateEvent t1) -&gt; {
List&lt;JSoupData&gt; 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&lt;List&lt;JSoupData&gt;&gt; scrapper(String url)
{
Task&lt;List&lt;JSoupData&gt;&gt; scrapperTask = new Task&lt;List&lt;JSoupData&gt;&gt;()
{
@Override
protected List&lt;JSoupData&gt; call()
{
List&lt;JSoupData&gt; jSoupDatas = new ArrayList();
try {
System.out.println(&quot;url: &quot; + url);
Document document = Jsoup.connect(url).get();
System.out.println(&quot;Title: &quot; + document.title());
Elements gamesNames = document.select(&quot;.search-results-row&quot;);
System.out.println(&quot;search-results-row&quot;);
for (Element element : gamesNames) {
jSoupDatas.add(new JSoupData(element.tagName(), element.text()));
System.out.println(&quot;Tag Name: &quot; + element.tagName() + &quot; - Text: &quot; + 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(&quot;JSoupData{tagName=&quot;).append(tagName);
sb.append(&quot;, text=&quot;).append(text);
sb.append(&#39;}&#39;);
return sb.toString();
}
}

从另一个线程更新UI的扩展类

答案2

得分: 0

通常,可以使用 Platform.runLater() 来在 JavaFX 应用程序线程上执行这些更新。

您可以从文档中获取更多信息 此处,以及从 此处 获取示例。

英文:

Usually, Platform.runLater() can be used to execute those updates on the JavaFX application thread.

You can get more information from documentation here and an example from here

huangapple
  • 本文由 发表于 2020年10月22日 03:20:06
  • 转载请务必保留本文链接:https://go.coder-hub.com/64470319.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定