I have a SWT panel where I set a root folder and some parameters, and I want to do some calculations on each of the files found (DocumentTree). After each file processing, it should update the panel status bar (a label text), but it updates occur all at once after all processing is finished. I have searched similar problems with threads and SWT, but could not find the error in my code. Thanks in advance
public class MainPane {
private Display display;
private Shell shell;
// ... some controls ...
Label barStatus; // Should show the file/folder being processed, but it updates AFTER processing is finished!!!
public MainPane() {
display = Display.getDefault();
shell = new Shell(display);
shell.setLayout(null);
// ...Formating and controls placing...
}
public void open() {
shell.open();
shell.layout();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) {
display.sleep();
}
}
display.dispose();
}
}
public void setStatusbarText(String estado) {
try {
barStatus.setText(estado);
barStatus.update();
barStatus.getParent().layout(); // According to some answers in forums, it is neccessary to get labels redrawn
} catch (Exception e) {
System.out.println("ERROR: " + e);
}
}
}
public class MainPaneController implements SelectionListener {
private DocumentTree tree;
private MainPane mainPane;
// ... Some code ...
@Override
public void widgetSelected(SelectionEvent e) {
if (e.getSource() == mainPane.btnCalculateMetadata()) {
new Thread(new Runnable() { // Launch the action as parallel thread so the panel can be updated
public void run() {
metadataGenerationEvent();
}
}).run();
}
// .. More if clauses for other control events ...
}
public void metadataGenerationEvent() {
tree.metadataGeneration();
}
public void updateStatus(String tarea, String mensaje) {
String status = tarea + ": " + mensaje;
mainPane.getDisplay().asyncExec(new Runnable() { // Request label text update as a SWT display's thread not to raise an exception
public void run() {
mainPane.setStatusbarText(status);
}
});
}
}
public class DocumentTree {
// ... Data structure and some other methods ...
public void metadataGeneration() {
for (Documento document : this.documents) {
mainController.updateStatus("Calculating metadata of file", document.absolutePath()); // This should update the status BEFORE EACH file is processed, but status is updated alltogether AFTER ALL processing is finished
document.calculateMetadata(); // It takes some seconds for each one
}
}
}
You need to call the start
method of Thread
not run
. Only start
creates a new thread, so:
new Thread(new Runnable() { // Launch the action as parallel thread so the panel can be updated
public void run() {
metadataGenerationEvent();
}
}).start();
which can be shortened to:
new Thread(this::metadataGenerationEvent).start()
Or even look at CompletableFuture
rather than using Thread
directly.