我目前是一名计算机科学专业的学生,正在使用GUI开展我的第一个项目。我遇到了程序滞后的问题。我们的教授指导我们为此目的使用Threads。虽然我们没有在课堂上做过任何例子,但他告诉过我们。我正在使用一个线程从iTunes Search API下载信息。
问题
当我第一次打开程序时,应该显示一个进度条(它确实如此),并且应该更新下载的进度。虽然,我还没有找到那个部分,我试图先用Timer创建一个模拟进度条。但是,当我这样做时,进度条仅更新为2.0%并被卡住。我相信这是因为generateURLS
方法阻止了Timer。但我想,计时器会在自己的Thread上运行,从而导致它不会阻塞。我真的很想澄清一下这个!
public void start(Stage stage) {
StackPane root = new StackPane();
VBox mainContent = new VBox();
Scene scene = new Scene(root);
ProgressBar loadingOverlay = new ProgressBar();
stage.setTitle("Gallery");
stage.setScene(scene);
Runnable r = () -> {
String[] URLS = Controls.generateURLS("rock", 50);
Platform.runLater(() -> {
images.fill(URLS);
root.getChildren().remove(loadingOverlay);
stage.sizeToScene();
});
};
Thread t = new Thread(r);
t.setDaemon(true);
new Timer().scheduleAtFixedRate(new TimerTask(){
double percent = 0;
@Override
public void run(){
percent += 0.01;
loadingOverlay.setProgress(percent);
}
}, 0, 1000);
t.start();
stage.show();
}
使用Gson库生成URLS的代码:
static JsonElement parseQuery (String query, int numberOf) throws IOException {
query = "https://itunes.apple.com/search?limit="+numberOf+"&term=" + URLEncoder.encode(query);
URL url = new URL(query);
InputStreamReader reader = new InputStreamReader(url.openStream());
JsonParser jp = new JsonParser();
return jp.parse(reader);
}
static String[] generateURLS (String query, int numberOf) {
String[] URLS = new String[numberOf];
try {
JsonElement json = parseQuery(query, numberOf);
JsonObject root = json.getAsJsonObject(); // root of response
JsonArray results = root.getAsJsonArray("results"); // "results" array
int numResults = results.size(); // "results" array size
for (int i = 0; i < numResults; i++) {
JsonObject result = results.get(i).getAsJsonObject(); // object i in array
JsonElement artworkUrl100 = result.get("artworkUrl100"); // artworkUrl100 member
if (artworkUrl100 != null) { // member might not exist
String artUrl = artworkUrl100.getAsString(); // get member as string
URLS[i] = artUrl; // print the string
} // if
} // for
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return URLS;
}
答案 0 :(得分:0)
由于我没有代码的可运行示例,我不能说你为什么会遇到滞后问题。
因此,删除sizeToScene
后调用ProgressBar
可能会“重新显示”。这可以解释为什么进度停止在2.0% - 这是因为进度条不再在屏幕上活动,但由于某种原因,UI尚未刷新。
我可以帮助您的一件事是,您可以如何正确更新进度条。
理解,大多数GUI框架都不是线程安全的,这意味着您应该尝试从主事件线程之外更新它们。以这种方式使用java.util.Timer
不仅不能让您准确了解已完成的工作量,而且还没有以线程安全的方式执行。
相反,我为您的示例代码添加了一个实现了一个简单的可观察属性,该属性可用于监视对进度状态的更改,并允许感兴趣的各方(即观察者)相应地执行某些任务。
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLEncoder;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.beans.property.ReadOnlyDoubleProperty;
import javafx.beans.property.ReadOnlyDoubleWrapper;
import javafx.beans.value.ObservableValue;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
public class Test extends Application {
@Override
public void start(Stage stage) {
StackPane root = new StackPane();
VBox mainContent = new VBox();
Scene scene = new Scene(root);
ProgressBar loadingOverlay = new ProgressBar();
root.getChildren().add(loadingOverlay);
stage.setTitle("Gallery");
stage.setScene(scene);
Query query = new Query();
query.progressProperty().addListener((ObservableValue<? extends Number> observable, Number oldValue, Number newValue) -> {
Platform.runLater(() -> {
loadingOverlay.setProgress(newValue.doubleValue());
});
});
Runnable r = () -> {
try {
query.parseQuery("rock", 50);
} catch (IOException ex) {
ex.printStackTrace();
}
Platform.runLater(() -> {
System.out.println("Done");
root.getChildren().remove(loadingOverlay);
root.getChildren().add(new Button("All done here"));
stage.sizeToScene();
});
};
new Thread(r).start();
stage.show();
}
public class Query {
private ReadOnlyDoubleWrapper progressProperty;
public Query() {
progressProperty = new ReadOnlyDoubleWrapper(this, "progress");
}
public ReadOnlyDoubleProperty progressProperty() {
return progressProperty;
}
void parseQuery(String query, int numberOf) throws IOException {
query = "https://itunes.apple.com/search?limit=" + numberOf + "&term=" + URLEncoder.encode(query);
URL url = new URL(query);
progressProperty.set(0.0);
try (InputStreamReader reader = new InputStreamReader(url.openStream())) {
for (int index = 0; index <= numberOf; index++) {
double progress = index / (double) numberOf;
progressProperty.set(progress);
try {
Thread.sleep(500);
} catch (InterruptedException ex) {
}
}
}
// JsonParser jp = new JsonParser();
// return jp.parse(reader);
}
// static String[] generateURLS(String query,^ int numberOf) {
// String[] URLS = new String[numberOf];
// try {
// JsonElement json = parseQuery(query, numberOf);
//
// JsonObject root = json.getAsJsonObject(); // root of response
// JsonArray results = root.getAsJsonArray("results"); // "results" array
// int numResults = results.size(); // "results" array size
// for (int i = 0; i < numResults; i++) {
// JsonObject result = results.get(i).getAsJsonObject(); // object i in array
// JsonElement artworkUrl100 = result.get("artworkUrl100"); // artworkUrl100 member
// if (artworkUrl100 != null) { // member might not exist
// String artUrl = artworkUrl100.getAsString(); // get member as string
// URLS[i] = artUrl; // print the string
// } // if
// } // for
// } catch (IOException e1) {
// // TODO Auto-generated catch block
// e1.printStackTrace();
// }
// return URLS;
// }
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
我的“直觉”感觉是,您的下载代码正在完成并且进度条已被删除,但由于我目前不理解的原因,UI尚未更新。当我添加按钮时,进度条被正确删除。
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLEncoder;
import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
public class Test extends Application {
@Override
public void start(Stage stage) {
StackPane root = new StackPane();
Scene scene = new Scene(root);
ProgressBar loadingOverlay = new ProgressBar();
root.getChildren().add(loadingOverlay);
stage.setTitle("Gallery");
stage.setScene(scene);
Query query = new Query("", 50);
loadingOverlay.progressProperty().bind(query.progressProperty());
query.setOnSucceeded((event) -> {
System.out.println("Done");
root.getChildren().remove(loadingOverlay);
root.getChildren().add(new Button("All done here"));
stage.sizeToScene();
});
new Thread(query).start();
stage.show();
}
public class Query extends Task<URL[]> {
private String query;
private int count;
public Query(String query, int count) {
this.query = query;
this.count = count;
}
@Override
protected URL[] call() throws Exception {
query = "https://itunes.apple.com/search?limit=" + count + "&term=" + URLEncoder.encode(query);
URL url = new URL(query);
try (InputStreamReader reader = new InputStreamReader(url.openStream())) {
for (int index = 0; index <= count; index++) {
updateProgress(index, count);
try {
Thread.sleep(250);
} catch (InterruptedException ex) {
}
}
}
return new URL[0];
}
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}