从另一个线程更新 UI 扩展 Class
Updating UI from another Thread extended Class
我想做的事情:
[使用 Jsoup 进行网页抓取]
从另一个扩展线程向 TableView 添加元素 Class。
单击按钮 -> 启动线程 -> 线程向 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);
}
}
}
我希望一切都清楚,如果没有,请用建设性的建议回答我。
通常,Platform.runLater()
可用于在 JavaFX 应用程序线程上执行这些更新。
这里有一个示例,您可以将其用作指南。您使用的 URL
没有结果列表。我建议你使用 https://www.allkeyshop.com/blog/catalogue/search-game/
之类的东西。看来,连字符后面的是正在搜索的内容。您可能需要进行一些复杂的搜索才能查看 URL
的变化。
本示例使用 Task
。在 Task
setOnSuccedded
更新 TableView
.
主要
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();
}
}
我想做的事情:
[使用 Jsoup 进行网页抓取]
从另一个扩展线程向 TableView 添加元素 Class。
单击按钮 -> 启动线程 -> 线程向 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);
}
}
}
我希望一切都清楚,如果没有,请用建设性的建议回答我。
通常,Platform.runLater()
可用于在 JavaFX 应用程序线程上执行这些更新。
这里有一个示例,您可以将其用作指南。您使用的 URL
没有结果列表。我建议你使用 https://www.allkeyshop.com/blog/catalogue/search-game/
之类的东西。看来,连字符后面的是正在搜索的内容。您可能需要进行一些复杂的搜索才能查看 URL
的变化。
本示例使用 Task
。在 Task
setOnSuccedded
更新 TableView
.
主要
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();
}
}