gpt4 book ai didi

Javafx 进度更新不够快

转载 作者:行者123 更新时间:2023-12-02 03:03:30 25 4
gpt4 key购买 nike

我正在逐行解析大文件,文件大小可能从几千行到数百万行。当文件很小(例如,只有几万行)时,所有组件(下图中红色箭头所示的组件)都会立即逐行更新,从而真实地指示进程的位置。当文件较大时,更新会有很大的延迟,可能需要长达30秒的时间指标才能反射(reflect)进度!我可以手动调整它的大小以刷新显示。

enter image description here

逐行流过文件时调用的方法是 updateProgress()。其中,progressPrevVal 从 0 到 1(每个增量为 1.0/2,675,150),并且 lineNum 如果我们使用图像中的示例。

完整代码如下:

import javafx.application.Application;
import javafx.application.Platform;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.stage.Stage;

public class DxProgressIndicator extends Application {

private static ProgressBar pb;
private static ProgressIndicator pi;
private static TextField tfNumbers;
private static Label lblLineNumVal;
private static Label lblAllLines;
private static double progressIncrement;
private static double progressPrevVal;
private static int lineNum;
private static Label lblFile;

@Override
public void start(Stage stage) {
Group root = new Group();
Scene scene = new Scene(root);
stage.setScene(scene);
stage.setTitle("Dexter Parser");

lblFile = new Label();
final HBox hbFile = new HBox();
hbFile.setAlignment(Pos.CENTER_LEFT);
Label lblCurrentFile = new Label("Current file: ");
lblCurrentFile.setMinWidth(90);
lblCurrentFile.setFont(Font.font(null, FontWeight.BOLD, 13));
hbFile.getChildren().addAll(lblCurrentFile, lblFile);

pb = new ProgressBar(0);
pb.setMinWidth(450);
pi = new ProgressIndicator(0);

final HBox hbPis = new HBox(10);
hbPis.setAlignment(Pos.CENTER_LEFT);
hbPis.getChildren().addAll(pb, pi);

lblLineNumVal = new Label();
lblLineNumVal.setMaxWidth(200);

Label slash = new Label(" / ");

lblAllLines = new Label();

final HBox hbLines = new HBox();
hbLines.setAlignment(Pos.CENTER_LEFT);
Label lblLineNum = new Label(" Currently parsing Line # : ");
lblLineNum.setFont(Font.font(null, FontWeight.BOLD, 12));
hbLines.getChildren().addAll(lblLineNum, lblLineNumVal, slash, lblAllLines);

tfNumbers = new TextField();
tfNumbers.setEditable(false);
tfNumbers.setMaxWidth(100);

final HBox hbTrxValues = new HBox();
hbTrxValues.setAlignment(Pos.CENTER_LEFT);
Label lblNumbers = new Label("(transaction, step, record) = ");
lblNumbers.setFont(Font.font(null, FontWeight.BOLD, 12));
hbTrxValues.getChildren().addAll(lblNumbers, tfNumbers);

final VBox vb = new VBox(10);
vb.getChildren().addAll(hbFile, hbPis, hbLines, hbTrxValues);
vb.setPadding(new Insets(10));

scene.setRoot(vb);
stage.show();
}

public static void updateProgress() {
Platform.runLater(() -> {
progressPrevVal += progressIncrement;
pb.setProgress(progressPrevVal);
pi.setProgress(progressPrevVal);
lblLineNumVal.setText(Integer.toString(lineNum++));
});
}

public static void setFileMetadata(String str) {
Platform.runLater(() -> {
lblAllLines.setText(str);
progressIncrement = 1 / Double.valueOf(str);
progressPrevVal = 0d;
lineNum = 1;
});
}

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

从客户端的 main 方法中,一旦我在自己的线程中启动 GUI,如下所示:

    Runnable task = () -> {
DxProgressIndicator.main(null);
};
Thread thread = new Thread(task);
thread.start();

然后我可以浏览该文件,逐行流式传输,如下所示:

    try (Stream<String> stream = Files.lines(file)) {
stream.forEach(line -> {
DxProgressIndicator.updateProgress();
// a bunch of stuff to do with the line
});
} catch (IOException e) {
}

那么,我错过了什么?在处理非常大的文件时,如何强制刷新以便组件在每次迭代时顺利更新,而不是几乎每分钟更新一次?

谢谢。

最佳答案

使用 Task ,并调用 updateProgress() 以限制对 Platform.runLater() 调用的方式更新进度,以免淹没 FX 应用程序线程需要执行的更新太多。

所以你可以这样做:

public class ParseTask extends Task<Void> {

private final Path file ;
private long totalLines ;

public ParseTask(...) {
file = ... ;
totalLines = ... ;
}

public Void call() throws IOException {

// better to use AtomicLong here in case you parallelize the parsing
// at any point...
AtomicLong linesRead = new AtomicLong() ;

try (Stream<String> stream = Files.lines(file)) {
stream.forEach(line -> {
updateProgress(linesRead.incrementAndGet(), totalLines);
// do stuff with line...
});
}

return null ;
}

public long getTotalLines() {
return totalLines ;
}
}

然后

public class DxProgressIndicator {

private final VBox vb ;
private ProgressBar pb;
private ProgressIndicator pi;
private TextField tfNumbers;
private Label lblLineNumVal;
private Label lblAllLines;
private double progressIncrement;
private double progressPrevVal;
private int lineNum;
private Label lblFile;

private final DoubleProperty progress = new SimpleDoubleProperty();

public DoubleProperty progressProperty() {
return progress ;
}

public final double getProgress() {
return progressProperty().get();
}

public final void setProgress(double progress) {
progressProperty().set(progress);
}

public DxProgressIndicator() {

lblFile = new Label();
final HBox hbFile = new HBox();
hbFile.setAlignment(Pos.CENTER_LEFT);
Label lblCurrentFile = new Label("Current file: ");
lblCurrentFile.setMinWidth(90);
lblCurrentFile.setFont(Font.font(null, FontWeight.BOLD, 13));
hbFile.getChildren().addAll(lblCurrentFile, lblFile);

pb = new ProgressBar(0);
pb.setMinWidth(450);

pi = new ProgressIndicator(0);

pb.progressProperty().bind(progress);
pi.progressProperty().bind(progress);

final HBox hbPis = new HBox(10);
hbPis.setAlignment(Pos.CENTER_LEFT);
hbPis.getChildren().addAll(pb, pi);

lblLineNumVal = new Label();
lblLineNumVal.setMaxWidth(200);

Label slash = new Label(" / ");

lblAllLines = new Label();

final HBox hbLines = new HBox();
hbLines.setAlignment(Pos.CENTER_LEFT);
Label lblLineNum = new Label(" Currently parsing Line # : ");
lblLineNum.setFont(Font.font(null, FontWeight.BOLD, 12));
hbLines.getChildren().addAll(lblLineNum, lblLineNumVal, slash, lblAllLines);

tfNumbers = new TextField();
tfNumbers.setEditable(false);
tfNumbers.setMaxWidth(100);

final HBox hbTrxValues = new HBox();
hbTrxValues.setAlignment(Pos.CENTER_LEFT);
Label lblNumbers = new Label("(transaction, step, record) = ");
lblNumbers.setFont(Font.font(null, FontWeight.BOLD, 12));
hbTrxValues.getChildren().addAll(lblNumbers, tfNumbers);

vb = new VBox(10);
vb.getChildren().addAll(hbFile, hbPis, hbLines, hbTrxValues);
vb.setPadding(new Insets(10));

}

public Parent getRoot() {
return vb ;
}

public void setTotalLines(long totalLines) {
lblAllLines.setText(Long.toString(totalLines));
}

}

然后就

public class MyApp extends Application {

@Override
public void start(Stage primaryStage) {

ParseTask task = new ParseTask(...);

DxProgressIndicator indicator = new DxProgressIndicator();
indicator.setTotalLines(task.getTotalLines());
indicator.progressProperty().bind(task.progressProperty());

Scene scene = new Scene(indicator.getRoot());
primaryStage.setScene(scene);
primaryStage.setTitle("Dexter Parser");

primaryStage.show();

new Thread(task).start();
}
}

显然,您可能需要修改此细节 - 例如您可以执行 updateMessage(linesRead + "/"+ totalLines); 并将标签的文本绑定(bind)到任务的 messageProperty() - 但它应该为您提供基本概念。

关于Javafx 进度更新不够快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42098813/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com