Hello,

Attempting to create a progress bar for awt-based application. I'm trying use a thread to do some simple animation to give the appearance that a frame (the progress bar) is incrementing. However, frame will not paint immediately.

Here's the code:

import java.awt.*;

/**
 *
 * @author user
 */
public class ProgressBar3 extends Frame implements Runnable
{
    
    private              int Count;
    private              int Max;
    private static final int FrameBottom = 24;
        
    private static String classArray[] = null;
    
    
    /** Creates a new instance of ProgressBar3 */
    public ProgressBar3() 
    {
        
    }

    public ProgressBar3 (String Title, int TotalItems)
    {
        super(Title);

        Count = 0;
        Max   = TotalItems;
        
        // Allowing this to be resized causes more trouble than it is worth
        // and the goal is for this to load and launch quickly!
        setResizable(false);
        //setLayout(null);
        //addNotify();  // this is needed in order to show correctly        
        //setLayout(new BorderLayout());    // not working                        
        /*setSize(getInsets().left + getInsets().right + 279,
                getInsets().top + getInsets().bottom + FrameBottom);
         */
        
        setSize(200, 50);   
        setLocation(50, 50);
        setBackground(Color.white);
                  
    }
    
    private void start()
    {
        Thread thread = new Thread(this);        
        thread.start();                       
    }
    
    
    public void run()
    {          
        while (true)
        {
            try
            {                                                
                Class c = Class.forName(classArray[Count]);
                updateProgress();
                Thread.sleep(10);                
            }            
            catch( Exception e)
            {
                break;
            }
        }
        
        // Or, try the following
        /*for (int i = 0; i < classArray.length; ++ i)
        {
            try
            {
                Class c = Class.forName(classArray[i]);
                Count = Count + 1;
                repaint();
            }
            catch (Exception e)
            {
                break;
            }
        }
         */            

        //repaint();        
        //dialog.setVisible(true);        
    }
        
    
    // Update the count and then update the progress indicator.  If we have
    // updated the progress indicator once for each item, dispose of the
    // progress indicator.
    public void updateProgress ()
    {
        ++Count;

        if (Count == Max)
            dispose();
        else
            repaint();
    }


    // Paint the progress indicator.
    public void paint (Graphics g)
    {
        //Dimension FrameDimension  = size();
        Dimension FrameDimension  = getSize();
        double    PercentComplete = (double)Count * 100.0 /(double)Max;
        int       BarPixelWidth   = (FrameDimension.width * Count)/ Max;

        // Fill the bar the appropriate percent full.
        //g.setColor (Color.red);
        g.setColor (Color.blue);
        g.fillRect (0, 0, BarPixelWidth, FrameDimension.height);

        // Build a string showing the % completed as a numeric value.
        String s = String.valueOf((int)PercentComplete) + " %";

        // Set the color of the text.  If we don't, it appears in the same color
        // as the rectangle making the text effectively invisible.
        g.setColor (Color.black);

        // Calculate the width of the string in pixels.  We use this to center
        // the string in the progress bar window.
        FontMetrics fm = g.getFontMetrics(g.getFont());
        int StringPixelWidth = fm.stringWidth(s);

        g.drawString(s, (FrameDimension.width - StringPixelWidth)/2, FrameBottom);        
    }
    
    public static void main(String[] args) 
    {
        ProgressBar3 progressBar = new ProgressBar3("", args.length+1);
        classArray = args;
        progressBar.setVisible(true);
        //progressBar.run();
        progressBar.start();
    }
                
    
}   // end class

any help is appreciated.

Hi,

I played around with your sample, rewrote it a little and it works. The only obvious thing which might cause a problem is that the Class.forName() fails to find the requested class and throws an exception. In this case the updateProgress() is not called. This is probably not what you want.

Hello,

Thx. for the response. It's appreciated. It appears that the Class.forName() works because the Progress Bar paints after the class that was preloaded by forName is made visible. That is, when the class, which is a dialog, is painted and made visible, only then the progress bar is painted.

Is it possible you can share what changes to make it work?


Your help is appreciated.

Hi,

Thx. for the input. However, the application is awt-based. No Swing allowed.

As I said I did not change very much.
I positition the text lower. it was clipped at the top and for testing I hardcoded an classArray with thousand times the same class.

BTW how long is your array in general, can it be that the array is small. So that the progressbar is disposed even before the AWT starts processing the painting requests.

In that case you have to consider if you even want to use a progressbar or buildin a threshold above which the progressbar is used.

- ronald

package nl.test.client;
import java.awt.*;
import java.util.Arrays;

/**
 *
 * @author user
 */
public class ProgressBar3 extends Frame implements Runnable
{
    
    private              int Count;
    private              int Max;
    private static final int FrameBottom = 40;
        
    private static String classArray[] = null;
    
    
    /** Creates a new instance of ProgressBar3 */
    public ProgressBar3() 
    {
        
    }

    public ProgressBar3 (String Title, int TotalItems)
    {
        super(Title);

        Count = 0;
        Max   = TotalItems;
        
        setResizable(false);
        setSize(200, 50);   
        setLocation(50, 50);
        setBackground(Color.white);
                  
    }
    
    private void start()
    {
        Thread thread = new Thread(this);        
        thread.start();                       
    }
    
    
    public void run()
    {          
        while (true)
        {
            try
            {                                                
                Class c = Class.forName(classArray[Count]);
                updateProgress();
                Thread.sleep(10);                
            }            
            catch( Exception e)
            {
                break;
            }
        }        
    }
        
    
    // Update the count and then update the progress indicator.  If we have
    // updated the progress indicator once for each item, dispose of the
    // progress indicator.
    public void updateProgress ()
    {
        ++Count;

        if (Count == Max)
            dispose();
        else
            repaint();
    }


    // Paint the progress indicator.
    public void paint (Graphics g)
    {
            //paint percentage ... and blue color.
    }
    
    public static void main(String[] args) 
    {
        ProgressBar3 progressBar = new ProgressBar3("", 1000);
    	classArray = new String[1000];
    	Arrays.fill(classArray, "nl.test.client.ProgressBar3");
    	progressBar.setVisible(true);
        //progressBar.run();
        progressBar.start();
    }
                
    
}   // end class

Hi Ronald,

Thanks for the response. It's appreciated. The array is not big at all. It contains about 3 to 4 dialogs. The purpose of this progress bar is give user notification while waiting for a dialog to appear on screen. The dialogs are to be preloaded via the progress bar. Unfortunately, the progress bar is not painting until the dialog itself becomes visible (i.e paints). It takes some time to load these dialogs, so the progress bar should have plenty of time to paint before it's disposed. Moreover, I have purposely added 1 to the length of the array so that progress bar does not reach 100% and hence not disposed, as a test.


any help is appreciated.

Hi,

I still do no follow completly the scenario. Class.forName() only loads a class and does not create one. However, If they are for instance singletons you might create them eagerly, but still you woudn't want them visible directly.

One other thing you try, I will, if I have some spare time. wrap the paint method in a panel and on panel use paintImmediately()

- in constructor:

Frame.setLayout(BorderLayout)
 Frame.add(panel, BorderLayout.CENTER)

- new class member:

Panel pane = new Panel() {
         public void paint() {
               ... draw.
         }
   };

- instead of repaint(), call panel.paintImmediately()


- ronald

Hi Ronald,

Thx. for your help. I apologize for the vague explanation or scenario. The scenario is as follows:

When a user clicks to open a dialog, there's currently no notification to the user while the dialog is loading to be displayed. Changing the mouse cursor to an hourglass, e.g. is not available due to the target device for application. As a result, attempting to create a progress bar that will preload the dialog(s) and give notification to the end-user. Once preloading is complete, the dialog is then instantiated and made visible.

Here's a sample:

String classArray[] = { "frmAccountSearch.dlgAccount",..... };
 ProgressBar3.main(classArrray);

dlgAccount1 = new frmAccountSearch.dlgAccount(this, true);
dlgAccount1.display();

The application is awt-based, so paintImmediately, a Swing method for JPanel can't be used, unfortunately.

Hopefully, this will help you help me because your help is much appreciated.

Jim

Hi,

OK. I understand now. Did you try the standalone ProgressBar I uploaded previously? Then we have a least established that the progressbar logic is working en there is a problem with how it's used.

what JDK are you using?

Hi Ronald,

Thx. for the response. The jdk level is 1.4.2. Unfortunately, I did not implement your code because Swing is required and the app is awt-based.


Jim

This article has been dead for over six months. Start a new discussion instead.