asyncExec 不适用于文件复制进度
asyncExec doesn't work for file copy progress
我在使用线程刷新由 SWT 构建的图形用户界面时遇到了一个大问题。我已经研究了文档,但无法理解。
任务是将文件夹的所有文件(仅文件,不包括子目录)复制到给定的目标文件夹。
在这个过程中我计算了已经完成的文件的大小和剩余时间。
然后在每次迭代中,我尝试通过步进进度条和更改状态标签来显示此信息。
代码如下所示:
public class MyClass {
private Display display;
private ProgressBar progressBar;
private Label statusLabel;
private File inputFile;
private File outputFolder;
...
public void init(File inputFile, File outputFolder) {
this.inputFile = inputFile;
this.outputFolder = outputFolder;
progressBar.setSelection(0);
statusLabel.setText("");
}
private class CopyFileTask implements Runnable {
@Override
public void run() {
long processedSize = 0L;
long startTime = System.currentTimeMillis();
long totalSize = 0L;
try {
File[] entries = inputFile.getParentFile().listFiles();
for (File theEntry : entries) {
if (theEntry.isFile()) {
totalSize += theEntry.length();
}
}
for (File theEntry : entries) {
if (theEntry.isFile()) {
String entryName = theEntry.getName();
File file = new File(outputFolder, entryName);
InputStream fis = new FileInputStream(theEntry);
FileOutputStream fos = new FileOutputStream(file);
try {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
processedSize += len;
showProgressInfo(startTime, processedSize, totalSize);
}
} finally {
try {
fis.close();
fos.close();
} catch (IOException e) {
}
}
}
}
} catch (Exception e) {
Log.error(e);
}
}
private void showProgressInfo(long startTimeMillis, long processedSize, long totalSize) {
int percent = (int) ((double) processedSize / (double) totalSize * 100.0);
progressBar.setSelection(percent);
long elapsedTimeSeconds = (System.currentTimeMillis() - startTimeMillis) / 1000L;
long remainingSize = totalSize - processedSize;
long remainingTimeSeconds = (long) ((double) remainingSize
/ (double) processedSize * elapsedTimeSeconds);
statusLabel.setText(formatFileSize(processedSize)
+ " of "
+ formatFileSize(totalSize)
+ " - Remaining: "
+ secondsToString(remainingTimeSeconds));
}
private String formatFileSize(long value) {
// return value in Bytes, KB, MB, GB
}
private String secondsToString(long value) {
// return value in MM:SS
}
}
}
我通过点击一个按钮开始这个过程:
startButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
display.asyncExec(new CopyFileTask());
}
});
现在我的问题是 GUI 冻结,直到整个过程完成,或者换句话说 - 标签和进度条仅在最后刷新。
您应该从不同的线程在 selectionListener 中开始更新:
startButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
Thread thread = new Thread(new CopyFileTask());
thread.start();
}
});
然后 post 使用 asyncExec() 从当前线程到显示线程进行进度更新,例如:
...
final long tmpStartTime = startTime;
final long tmpProcessedSize = processedSize;
final long tmpTotalSize = totalSize;
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
showProgressInfo(tmpStartTime, tmpProcessedSize, tmpTotalSize);
}
});
...
我在使用线程刷新由 SWT 构建的图形用户界面时遇到了一个大问题。我已经研究了文档,但无法理解。
任务是将文件夹的所有文件(仅文件,不包括子目录)复制到给定的目标文件夹。
在这个过程中我计算了已经完成的文件的大小和剩余时间。
然后在每次迭代中,我尝试通过步进进度条和更改状态标签来显示此信息。
代码如下所示:
public class MyClass {
private Display display;
private ProgressBar progressBar;
private Label statusLabel;
private File inputFile;
private File outputFolder;
...
public void init(File inputFile, File outputFolder) {
this.inputFile = inputFile;
this.outputFolder = outputFolder;
progressBar.setSelection(0);
statusLabel.setText("");
}
private class CopyFileTask implements Runnable {
@Override
public void run() {
long processedSize = 0L;
long startTime = System.currentTimeMillis();
long totalSize = 0L;
try {
File[] entries = inputFile.getParentFile().listFiles();
for (File theEntry : entries) {
if (theEntry.isFile()) {
totalSize += theEntry.length();
}
}
for (File theEntry : entries) {
if (theEntry.isFile()) {
String entryName = theEntry.getName();
File file = new File(outputFolder, entryName);
InputStream fis = new FileInputStream(theEntry);
FileOutputStream fos = new FileOutputStream(file);
try {
byte[] buffer = new byte[1024];
int len;
while ((len = fis.read(buffer)) > 0) {
fos.write(buffer, 0, len);
processedSize += len;
showProgressInfo(startTime, processedSize, totalSize);
}
} finally {
try {
fis.close();
fos.close();
} catch (IOException e) {
}
}
}
}
} catch (Exception e) {
Log.error(e);
}
}
private void showProgressInfo(long startTimeMillis, long processedSize, long totalSize) {
int percent = (int) ((double) processedSize / (double) totalSize * 100.0);
progressBar.setSelection(percent);
long elapsedTimeSeconds = (System.currentTimeMillis() - startTimeMillis) / 1000L;
long remainingSize = totalSize - processedSize;
long remainingTimeSeconds = (long) ((double) remainingSize
/ (double) processedSize * elapsedTimeSeconds);
statusLabel.setText(formatFileSize(processedSize)
+ " of "
+ formatFileSize(totalSize)
+ " - Remaining: "
+ secondsToString(remainingTimeSeconds));
}
private String formatFileSize(long value) {
// return value in Bytes, KB, MB, GB
}
private String secondsToString(long value) {
// return value in MM:SS
}
}
}
我通过点击一个按钮开始这个过程:
startButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
display.asyncExec(new CopyFileTask());
}
});
现在我的问题是 GUI 冻结,直到整个过程完成,或者换句话说 - 标签和进度条仅在最后刷新。
您应该从不同的线程在 selectionListener 中开始更新:
startButton.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event e) {
Thread thread = new Thread(new CopyFileTask());
thread.start();
}
});
然后 post 使用 asyncExec() 从当前线程到显示线程进行进度更新,例如:
...
final long tmpStartTime = startTime;
final long tmpProcessedSize = processedSize;
final long tmpTotalSize = totalSize;
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
showProgressInfo(tmpStartTime, tmpProcessedSize, tmpTotalSize);
}
});
...