I am using CompletableFuture to run a long running operation. Meanwhile, i use SwingWorker to update a progress bar with increments of 5.
JProgressBar progressBar = new JProgressBar(); progressBar.setMinimum(0); progressBar.setMaximum(100); progressBar.setValue(0); progressBar.setStringPainted(true); CompletableFuture<NetworkToolsTableModel> completableFuture = CompletableFuture.supplyAsync(() -> asyncTask()); SwingWorker worker = new SwingWorker() { @Override protected Object doInBackground() throws Exception { int val = 0; while (!completableFuture.isDone()) { if (val < 100) { val += 5; progressBar.setValue(val); } Rectangle bounds = progressBar.getBounds(null); progressBar.paintImmediately(bounds); } return null; } }; worker.execute();
The progress bar doesn’t update until the asynchronous method is finished. I have also tried doing this operation on the EDT thread, but to no avail. What you are seeing is basically me trying to just do trial and error at this point.
Why is the progress bar not updating? How can I fix this?
Advertisement
Answer
Stop and take a closer look at Worker Threads and SwingWorker.
A SwingWorker
is meant to allow you to perform a long running task, which may produce intermediate results, and allow you to publish
those results back to the Event Dispatching Thread to be safely processed (via the process
method).
You “could” publish
the progress updates and update the progress bar in process
method, but SwingWorker
already provides a progress
property, which you can monitor. Take a look at the SwingWorker
JavaDocs for a number of ready made examples!
Run Example
import javax.swing.JFrame; import javax.swing.JPanel; import java.awt.*; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import javax.swing.*; public class Test { public static void main(String[] args) { new Test(); } public Test() { EventQueue.invokeLater(new Runnable() { @Override public void run() { try { UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException ex) { } catch (InstantiationException ex) { } catch (IllegalAccessException ex) { } catch (UnsupportedLookAndFeelException ex) { } ProgressPane progressPane = new ProgressPane(); JFrame frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.setLayout(new BorderLayout()); frame.add(progressPane); frame.setSize(200, 200); frame.setLocationRelativeTo(null); frame.setVisible(true); // progressPane.doWork(); } }); } public class ProgressPane extends JPanel { private JProgressBar progressBar; private JButton startButton; public ProgressPane() { setLayout(new GridBagLayout()); progressBar = new JProgressBar(); GridBagConstraints gbc = new GridBagConstraints(); gbc.gridx = 0; gbc.gridy = 0; add(progressBar, gbc); startButton = new JButton("Start"); gbc.gridy = 1; add(startButton, gbc); startButton.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { startButton.setEnabled(false); doWork(); } }); } public void doWork() { Worker worker = new Worker(); worker.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { progressBar.setValue((Integer) evt.getNewValue()); } } }); worker.execute(); } public class Worker extends SwingWorker<Object, Object> { @Override protected void done() { startButton.setEnabled(true); } @Override protected Object doInBackground() throws Exception { for (int index = 0; index < 1000; index++) { int progress = Math.round(((float) index / 1000f) * 100f); setProgress(progress); Thread.sleep(10); } return null; } } } }