Search code examples
javamultithreadingwaitjprogressbar

Continue once the thread returns true


I am having trouble getting my code to 'pause' until the thread is finished. My program is simply a JProgressBar inside a frame. I am using a loop located inside a thread, which loops every 10 milliseconds and adds +1 to the progress bar. The end result will make the bar look animated as its value increases from 0 to 100.

Now, the problem is getting the code to 'wait' until the progress bar hits value 100. As you can see in the code, I would like to have buttons re-enabled only when the progress bar reaches value 100. As of right now, the buttons seem to get re-enabled simultaneously as the progress bar is increasing.

    disableButtons();

    // loop and animate the progress bar
    for (int i = 0; i <= 100; i++) {
        Game.setProgBar_loading(i);

        // wait a number of milliseconds
        try {
            Thread.sleep(10);

        } catch (InterruptedException e) {}

    }

    enableButtons();

Solution

  • You could nest Loading class in Program and then access Program's variables from there, and then pretty much copy this part of the code: // <TODO> re-enable all buttons into the end of the loop. Something like this:

    class Program {
        // assuming you have these buttons:
        private JButton button1;
        private JButton button2;
        private JButton button3;
    
        // snip
    
        public Program() {
    
            // assuming there's initialization code for the above buttons somewhere...
            // button1 = new ...
            // button2 = new ...
            // button3 = new ...
    
            // frame initializing
            setResizable(false);
            setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            setLocationRelativeTo(null);
            setBounds(100, 100, 890, 480);
            getContentPane().setLayout(null);
            setVisible(true);
    
            // create the loading bar
            loadingBar = new JProgressBar();
            loadingBar.setBounds(10, 11, 864, 23);
            getContentPane().add(loadingBar);
    
            // <TODO> disable all buttons
            button1.setEnabled(false);
            button2.setEnabled(false);
            button3.setEnabled(false);
    
            // animate the loading bar
            Loading thread = new Loading();
            new Thread(thread).start();
    
            // do not re-enable the buttons here yet.
        }
    
        // snip
    
        public class Loading implements Runnable {
            @Override
            public void run() {
    
                // loop and increment loading bar's value
                for (int i = 0; i <= 100; i++) {
                    Program.setProgressBar(i);
    
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {}
    
                }
    
                // re-enable the buttons here instead
                button1.setEnabled(true);
                button2.setEnabled(true);
                button3.setEnabled(true);
            }
        }
    }
    

    EDIT: To generalize your Loading class and reuse it later you could create an interface that contains methods such as beforeExecute() and afterExecute(). Take that interface as an argument to Loading's constructor and save it as a member so you can later call the interface's methods from within run():

    public interface LoadingHandler {
        public void beforeExecute();
        public void afterExecute();
    }
    
    public class Loading implements Runnable {
        private LoadingHandler handler;
    
        public Loading(LoadingHandler handler) {
            this.handler = handler;
        }
    
        @Override
        public void run() {
            // disableButtons();
            // use interface's methods instead:
            handler.beforeExecute();
    
            // loop and animate the progress bar
            for (int i = 0; i <= 100; i++) {
                Game.setProgBar_loading(i);
    
                // wait a number of milliseconds
                try {
                    Thread.sleep(10);
    
                } catch (InterruptedException e) {}
    
            }
    
            // enableButtons();
            // use interface's method instead:
            handler.afterExecute();
        }
    }
    

    Then, in your GUI's thread you would do something like this:

    Loading thread = new Loading(new LoadingHandler() {
        @Override
        public void beforeExecute() {
            disableButtons();
        }
    
        @Override
        public void afterExecute() {
            enableButtons();
        }
    });
    
    new Thread(thread).start();