Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

doEvents in Java

Posted on 2001-07-23
5
Medium Priority
?
5,448 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 150 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

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

For beginner Java programmers or at least those new to the Eclipse IDE, the following tutorial will show some (four) ways in which you can import your Java projects to your Eclipse workbench. Introduction While learning Java can be done with…
Java contains several comparison operators (e.g., <, <=, >, >=, ==, !=) that allow you to compare primitive values. However, these operators cannot be used to compare the contents of objects. Interface Comparable is used to allow objects of a cl…
Viewers will learn how to properly install Eclipse with the necessary JDK, and will take a look at an introductory Java program. Download Eclipse installation zip file: Extract files from zip file: Download and install JDK 8: Open Eclipse and …
How to fix incompatible JVM issue while installing Eclipse While installing Eclipse in windows, got one error like above and unable to proceed with the installation. This video describes how to successfully install Eclipse. How to solve incompa…
Suggested Courses

927 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