Show indeterimante progress bar in JDialog in a thread and simultaneously run a task in another thread

When the user clicks the button, a long task is launched, lasting about 10 seconds. During this time, I want to show a progress bar to the user. But the main thread must wait for the workflow to complete, because the workflow will set the variable that the main thread will use. If I do not wait for the workflow, I will get a NullPointerException when using the variable. Therefore, after completing the work cycle, I will also close the progress bar dialog box.

When I wait for a workflow using join() , a progress bar dialog box appears (interestingly, without a progress bar) and hangs there.

 Thread runnable = new Thread() { public void run() { try { System.out.println("thread basladi"); threadAddSlaveReturnMessage = request.addSlave( ipField.getText(), passField.getText(), nicknameField.getText()); System.out.println("thread bitti"); } catch (LMCTagNotFoundException e) { e.printStackTrace(); } } }; Thread runnable_progress = new Thread() { public void run() { JTextArea msgLabel; JDialog dialog; JProgressBar progressBar; final int MAXIMUM = 100; JPanel panel; progressBar = new JProgressBar(0, MAXIMUM); progressBar.setIndeterminate(true); msgLabel = new JTextArea("deneme"); msgLabel.setEditable(false); panel = new JPanel(new BorderLayout(5, 5)); panel.add(msgLabel, BorderLayout.PAGE_START); panel.add(progressBar, BorderLayout.CENTER); panel.setBorder(BorderFactory.createEmptyBorder(11, 11, 11, 11)); dialog = new JDialog(Frame.getFrames()[0], "baslik", true); dialog.getContentPane().add(panel); dialog.setResizable(false); dialog.pack(); dialog.setSize(500, dialog.getHeight()); dialog.setLocationRelativeTo(null); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setAlwaysOnTop(false); dialog.setVisible(true); msgLabel.setBackground(panel.getBackground()); } }; runnable.start(); System.out.println("runnable start"); runnable_progress.start(); System.out.println("progress start"); runnable.join(); System.out.println("runnable join"); runnable_progress.join(); System.out.println("progress join"); if (threadAddSlaveReturnMessage.equalsIgnoreCase("OK")) { fillInventoryTable(inventoryTable); JOptionPane.showMessageDialog(this, messages.getString("centrum.addslavepanel.SUCCESS"), null, JOptionPane.INFORMATION_MESSAGE); } 

"connection of progress"

not printed.

+4
source share
3 answers
  • you have a problem with Concurency is Swing , your GUI is displayed after all threads are completed

  • you can navigate with JProgressBar (I'm talking about your code), but you should

    • create and show JDialog , create once and reuse this container

    • then run Thread ,

    • better could be from Runnable#Thread

    • the output in the Swing GUI must be enclosed in invokeLater()

  • this is exactly what you need to use SwingWorker and PropertyChangeListener

+3
source

You can use SwingWorker here . A brief example:

 /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.godel.nio; import java.awt.BorderLayout; import java.util.List; import javax.swing.*; /** * * @author internet_2 */ public class Test { public static void main(String[] args) { new Test().doJob(); } public void doJob() { JTextArea msgLabel; JProgressBar progressBar; final int MAXIMUM = 100; JPanel panel; progressBar = new JProgressBar(0, MAXIMUM); progressBar.setIndeterminate(true); msgLabel = new JTextArea("deneme"); msgLabel.setEditable(false); panel = new JPanel(new BorderLayout(5, 5)); panel.add(msgLabel, BorderLayout.PAGE_START); panel.add(progressBar, BorderLayout.CENTER); panel.setBorder(BorderFactory.createEmptyBorder(11, 11, 11, 11)); final JDialog dialog = new JDialog(); dialog.getContentPane().add(panel); dialog.setResizable(false); dialog.pack(); dialog.setSize(500, dialog.getHeight()); dialog.setLocationRelativeTo(null); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); dialog.setAlwaysOnTop(false); dialog.setVisible(true); msgLabel.setBackground(panel.getBackground()); SwingWorker worker = new SwingWorker() { @Override protected void done() { // Close the dialog dialog.dispose(); } @Override protected void process(List chunks) { // Here you can process the result of "doInBackGround()" // Set a variable in the dialog or etc. } @Override protected Object doInBackground() throws Exception { // Do the long running task here // Call "publish()" to pass the data to "process()" // return something meaningful return null; } }; worker.execute(); } } 

Edit: " publish ( )" should be called in "doInBackground ()" to pass data to "process ()".

+4
source

As mentioned in previous answers, SwingWorker is the way to go if you want to use concurrency with Swing.
I found this SwingWorker and the ProgressBar guide very helpful in understanding how it all works.

Returning to your real problem: I assume that you are using a graphical interface because you stated that the user should click a button. The question is, what does your "main thread" do? Does it really need to work all the time? Does not look like it. Since you said that the thread needs a variable that is set by another thread, which is the result of user interaction. In short: why should this be run if it depends on user interaction?
The usual way would be to get all the necessary data first, and then do the calculations or something else. In your case, either run everything in one background thread (first set the variable, and then the rest), run the ActionListener of your button, or start another thread after the stream in which you set the variable to complete.
You can, for example, use the done() method provided by SwingWorker to run the next task. Or, if you really need to, you can wait in a loop for task.isDone() to return true . But be sure to also check isCancelled() .

In any case, I think you should reconsider your design. Because what I see from the limited information presented seems too complicated for me.

+2
source

All Articles