0

Possible Duplicate:
Java GUI JProgressBar not painting
Can a progress bar be used in a class outside main?

I am using Netbeans drag and drop to do an application. I will get input from user and use the input to run my algorithm. The algorithm will take different time to run and then show its result in a new frame. While waiting the algorithm to run, I wish to add in a progress bar. I add in the below code when the user click the button submit input.

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {   

    final JProgressBar bar = new JProgressBar(0,250000);
    bar.setValue(1000);
    bar.setIndeterminate(false);
    JOptionPane jO = new JOptionPane(bar);

    Thread th = new Thread(){

    public void run(){
        for(int i = 1000 ; i < 250000 ; i+=10000){
           bar.setValue(i);
            try {
                Thread.sleep(100);
           } catch (InterruptedException e) {
            }
        }
    }
};
th.start();

final JDialog dialog = jO.createDialog(jO,"Experiment X");
dialog.pack();
dialog.setVisible(true);

//Algorithm goes here

The progressbar do show up and run.But when the progress bar value is update until the end, only my algorithm run. I see through others example, but I not really understand how it works.

Can someone tell me where I got wrong?

Community
  • 1
  • 1
yt729
  • 11
  • 5
  • 1
    This has been asked and answered many times. Use a background thread such as can be provided by a SwingWorker. Please read the progressbar and swingworker tutorials for more on this which Google will help you find. – Hovercraft Full Of Eels Dec 31 '12 at 03:37
  • Here are the tutorial links: [progressbar tutorial](http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html), [concurrency in swing (and SwingWorker tutorial)](http://docs.oracle.com/javase/tutorial/uiswing/concurrency/index.html) – Hovercraft Full Of Eels Dec 31 '12 at 03:42
  • *"..then show its result in a new frame."* See [The Use of Multiple JFrames, Good/Bad Practice?](http://stackoverflow.com/a/9554657/418556) for assessment (bad) and alternatives (many). – Andrew Thompson Dec 31 '12 at 05:01

1 Answers1

4

Some of the most important concepts in Swing are

DO NOT perform any long running/blocking operations within the Event Dispatching Thread (ETD). This will cause the UI to appear "frozen" and non-responsive. What's nice is, you seem to understand this.

DO NOT create or modify ANY ui component from any thread OTHER then the EDT. You're not doing this.

You best cause of action is to take advantage of the SwingWorker, this allows you to perform long running operations, while providing progress feedback to listeners.

public class TestProgress {

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

    public TestProgress() {
        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;
            }
        }
    }
}

You're other choice would be to use a ProgressMonitor or, if you're really desperate, use SwingUtilities#invokeLater(Runnable), but, I'd really encourage you to use SwingWorker instead ;)

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366