3

Problem When a button is clicked, it needs to pop up a loading GIF, while a very long process is executed. This pop up automatically closes when the process is completed.

My Approach

    if (evt.getSource() == processButton) {

            ImageIcon loading = new ImageIcon("img/loading.gif");
            final JLabel loaderLabel = new JLabel("loading", loading, JLabel.CENTER);
            Thread t = new Thread(new Runnable() {

                @Override
                public void run() {
                    ProcessFrame.this.frame.add(loaderLabel);
                }

            });
        process(); // long process
        loaderLabel.setVisible(false);
    }

ProcessFrame is the main JFrame which the user interacts with.

What problem am I running into?

The loading image never pops up (or atleast as a label). Followed some of the posts on SO, but in vain so far. Where am I getting wrong?

Alternative

Using SwingWorker. However, how do I know the SLEEP_TIME given the process is being executed? Or more precisely, when and how do I integrate the SwingWorker with the process() method running?

  SwingWorker<Void, Void> mySwingWorker = new SwingWorker<Void, Void>(){
     @Override
     protected Void doInBackground() throws Exception {

        Thread.sleep(SLEEP_TIME);
        return null;
     }
  };
mohitm
  • 153
  • 10
  • Is there any reason you are adding the label to the frame from a seperate Thread? Why not simply add it to the frame (without the Thread)? – TT. Jan 11 '16 at 11:38
  • Yeah, because not doing so affects EDT, and no change is observed. http://stackoverflow.com/questions/12566311/displaying-gif-animation-in-java – mohitm Jan 11 '16 at 11:41
  • Well you need to use a thread that sychronizes properly with your GUI Thread. Use `SwingUtilities.invokeLater` instead of using a regular `Thread`. – TT. Jan 11 '16 at 11:42
  • Also your blocking process runs on your GUI thread, so your GUI thread will block completely. You need to use a seperate `Thread` for your blocking process. – TT. Jan 11 '16 at 11:44
  • @TT Just tried with SwingUtilities. Didn't work, again :( Throws Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException – mohitm Jan 11 '16 at 12:02
  • In short: write your program to execute your blocking process (`process();` in your code) to run in a seperate `Thread`. Have the thread communicate to your form when it is completed (by using `SwingUtilities.invokeLater` to alert the form that the process finished). – TT. Jan 11 '16 at 12:30
  • 1
    For [example](http://stackoverflow.com/a/4530659/230513) – trashgod Jan 11 '16 at 12:40

2 Answers2

2

This...

Thread t = new Thread(new Runnable() {
    @Override
    public void run() {
        ProcessFrame.this.frame.add(loaderLabel);
    }
});

is a bad idea as you are violating the single thread rules of Swing (and you never start the Thread)

It should be something more like...

ProcessFrame.this.frame.add(loaderLabel);
ProcessFrame.this.frame.revalidate();
ProcessFrame.this.frame.repaint();

You should then run the process(); // long process in a SwingWorker, using it's PropertyChangeSupport to determine when the worker has finished, as an example

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
1

I got this resolved. So I'm posting here my solution to my own problem. Thanks to the comments earlier. Hope this helps someone who runs into same sort of problem.

JDialog loadingDialog = new JDialog();

public void createDialog(JDialog d) {

    JLabel l = new JLabel(new ImageIcon(("img/loading.gif")));
    d.setSize(100, 100);
    d.add(l);
    d.setVisible(true);
    d.isAlwaysOnTop();
}
// other methods ... and now defining ActionPerformed method for the button below
private void processButtonActionPerformed(ActionEvent evt) {
    if (evt.getSource() == processButton) {
        createDialog(dialogLoading);
        SwingWorker<Boolean, Void> worker = new SwingWorker<Boolean, Void>() {
        @Override
            protected Boolean doInBackground() throws Exception {
                process(); // this is the long process
                return true;
            }   
            protected void done() {
                boolean status;
                try {
                    status = get();
                    dialogLoading.setVisible(false);
                } catch (InterruptedException e) {
                    // This is thrown if the thread's interrupted.
                } catch (ExecutionException e) {
                    // This is thrown if we throw an exception
                    // from doInBackground.
                }
            }
       };
       worker.execute();
    }
}
mohitm
  • 153
  • 10