Solved

doEvents in Java

Posted on 2001-07-23
5
4,913 Views
Last Modified: 2007-11-27
Is there a statement in Java that is similar to the Visual Basic DoEvents statement?  I would like to update a progress bar while running a series of tasks.  After each task I set a progress bar value but the progress bar is not updated until all of the tasks complete.
0
Comment
Question by:rossc
5 Comments
 
LVL 2

Expert Comment

by:iDeb
ID: 6310080
In java you need to register listeners for events you want to track. So if you wish to track the Mouse events like mousedown, up etc..in a certain class, you have to implement the MouseListener interface. What that means is your class must implement the methods in the MouseListener interface. Once you do that, in the main or elsewhere you add your object as a listener. For. e.g. in your Frame class you do this.addListener(<object of your class which implements the MouseListener interface>....when you do this, for all mouse events your class' methods will be invoked.....more work than the DoEvents of VB...but neat....
0
 
LVL 2

Expert Comment

by:iDeb
ID: 6310103
for your purpose, if you're using a JProgressBar, you might just have to call a setValue and then repaint everytime a task completes......you might be missing the repaint part
0
 
LVL 1

Expert Comment

by:phiro
ID: 6311977
You may consider letting the process you are following in the progress bar run in another thread.

 
0
 
LVL 19

Accepted Solution

by:
Jim Cakalic earned 50 total points
ID: 6313691
You are probably doing your processing as part of some event that occurred in your UI, right? Like maybe the user presses a JButton. You have an ActionListener registered on the JButton and your actionPerformed method looks something like:

   public void actionPerformed(ActionEvent e) {
       setup JProgressBar
       task loop:
           do a task
           update the progress bar
       cleanup
   }

Let me know if I'm off base here. What is happening is that AWT (and thus Swing) handles events on a single thread which is created when your UI is "realized". That thread does all the event dispatching for Swing/AWT components used in your application. When an event like a button press occurs, it delivers it to the target component, your JButton, which gets all it's registered ActionListeners and calls their actionPerformed methods one at a time. This is all happening on the AWT event dispatch thread. Since requests to repaint are queued on the EventQueue serviced by the dispatch thread, the fact that you are blocking that thread from going about it's normal activities "freezes" your UI until the actionPerformed method completes.

The best way to work around that is to start another thread on which the non-UI processing will be done. The first step is to create a Runnable with the work to be done in it's run method. Use that Runnable (created here from an anonymous inner class) to construct a new Thread object and start the Thread.

   private JProgressBar bar;
   public void actionPerformed(ActionEvent e) {
           ... setup the progress bar, put it in the containment hierarchy,
           ... whatever you're already doing is probably okay as long as the
           ... JProgressBar variable is an instance field of the class

           Thread th = new Thread(new Runnable() {
               public void run() {
                   task loop:
                       do a task
                       update the progress bar
                   cleanup
               }
           });
           th.start();
       }
   }

This introduces a new wrinkle, though. During the processing we want to update a JProgressBar. Before we moved this code to another thread, it was executing in the event dispatch thread by virtue of the fact that it was occuring in the actionPerformed method. But now it is running on another thread. Great. Unfortunately, it means that you cannot update the JProgressBar component directly by calling its methods. This is because Swing is not thread-safe. Swing components should only be updated from the event dispatch thread.

How to do it then? Use the SwingUtilities class. Here is a basic skeleton that shows what you would do in the loop of your run method above.

  while (continueWorking) {
      ... do some work
 
      // time to update progress
      private class ProgressUpdater implements Runnable {
          private JProgressBar _bar;
          private int _value;

          ProgressUpdater(JProgressBar bar, int value) {
              _bar = bar;
              _value = value;
          }
          public void run() {
              _bar.setValue(_value);
          }
      }

      try {
          Runnable updater = new ProgressUpdater(pbar, n);
          SwingUtilities.invokeAndWait(updater);
      } catch (Exception e) {
          // ignore or do whatever
      }

      ... maybe more work
  }


The basics of this are that we have some bit of code that we want to be invoked on the event dispatch thread. The way SwingUtilities lets us do that is by putting the code we want invoked in the run method of a Runnable object which it will then put on the EventQueue. The invokeAndWait method will wait until the requested action has occurred -- probably what you want. There is another invokeLater method which queues the event and continues. Using that will probably result in stalling again because your work thread could possibly get too much of the available CPU and prevent the UI from updating in a timely manner.

Anyway, the assumption I made here was that the JProgressBar object was available -- probably as an instance variable. You probably wouldn't need to pass them to the constructor of the ProgressUpdater but I showed that happening for completeness. The value n is the progress bar value you went to set. It is definitely best that these be passed as arguments like this. You have to do it in a constructor because the run method doesn't take any arguments.

You could move the ProgressUpdater class definition out of the method if you felt better about it. Just so long as it remains in the same class as the rest of the code. Not just in the same source file. It should be a private member of the same class.

Let me know if you have any problem with this and I'll help you work through it. I didn't test this code but it is cut and paste from working code that I have. If you'd like additional material on this topic, you might have a look at the Java Tutorial:
    http://java.sun.com/docs/books/tutorial/uiswing/components/progress.html

Of course, I'd be remiss if I didn't mention that JComponent declares a paintImmediately method which "Paints the specified region in this component and all of its descendants that overlap the region, immediately. It's rarely necessary to call this method. In most cases it's more efficient to call repaint, which defers the actual painting and can collapse redundant requests into a single paint call. This method is useful if one needs to update the display while the current event is being dispatched." Here is an example of how to call this method:

    JProgressBar bar = ...
    bar.paintImmediately(bar.getBounds());

Best regards,
Jim Cakalic
0
 

Author Comment

by:rossc
ID: 6322716
jim_cakalic,

You are right, the problem is that the GUI is not being updated until all of the processes have completed.  I used your code and move the processes to another thread but the progress bar still didn't update until everything completed.  To be sure the problem wasn't with the progress bar, I added code to update a label during processing and it also didn't change until all of the processes completed.

I even tried using a progress monitor but it never appeared.  Could be that I got the code for the progress monitor wrong though.
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

For customizing the look of your lightweight component and making it look lucid like it was made of glass. Or: how to make your component more Apple-ish ;) This tip assumes your component to be of rectangular shape and completely opaque. (COD…
Are you developing a Java application and want to create Excel Spreadsheets? You have come to the right place, this article will describe how you can create Excel Spreadsheets from a Java Application. For the purposes of this article, I will be u…
Viewers learn about the “while” loop and how to utilize it correctly in Java. Additionally, viewers begin exploring how to include conditional statements within a while loop and avoid an endless loop. Define While Loop: Basic Example: Explanatio…
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

20 Experts available now in Live!

Get 1:1 Help Now