Southpaw Hare
Southpaw Hare

Reputation: 1593

Progress Bar does not update Immediately

I am attempting to use both a Progress Bar and a Label to show the progress of a discreet number of operations. Every time I update both, the label updates immediately, while the progress bar has a noticeable delay before it changes.

I have a test dialog where, when I press a button, I update both the label and the progress bar to reflect an increase of 1. This happens immediately in the code without any loops or threads being called (eliminating any threading-related issues as being the cause) - just a simple changing of values. When this happens, the Label updates immediately, while the Progress Bar waits for about half a second before updating visually. This leads to instances where it will say, for instance, "2 out of 3" when it briefly but noticably shows 1/3 of the bar filled.

enter image description here

import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;

public class ProgressBarTest extends Shell {

    private ProgressBar progressBar;
    private Label lblXOfX;
    private Button btnGo;

    public static void main(String args[]) {
        try {
            Display display = Display.getDefault();
            ProgressBarTest shell = new ProgressBarTest(display);
            shell.open();
            shell.layout();
            while (!shell.isDisposed()) {
                if (!display.readAndDispatch()) {
                    display.sleep();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public ProgressBarTest(Display display) {
        super(display, SWT.SHELL_TRIM);
        createContents();
    }

    protected void createContents() {
        setText("SWT Application");
        setSize(450, 300);
        setLayout(new GridLayout());

        progressBar = new ProgressBar(this, SWT.NONE);
        progressBar.setMaximum(3);
        progressBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));

        lblXOfX = new Label(this, SWT.NONE);
        lblXOfX.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, false, false, 1, 1));
        lblXOfX.setText("x of x");

        btnGo = new Button(this, SWT.NONE);
        btnGo.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent arg0) {
                go();
            }
        });
        btnGo.setText("Go");
    }

    @Override
    protected void checkSubclass() {
        // Disable the check that prevents subclassing of SWT components
    }

    protected void go() {

        int iCur = progressBar.getSelection();
        iCur++;
        if (iCur > progressBar.getMaximum())
            iCur = 0;

        progressBar.setSelection(iCur);
        lblXOfX.setText(String.format("%s of %s", iCur, progressBar.getMaximum()));
    }

}

This occurs despite using the Progress Bar's internal variable to keep track of the value, and using that value to update the label.

Notably, changing the progress bar's "State" property to "ERROR" or "PAUSED" eliminates the issue.

Is this some sort of bug with animation? Is this just an issue with a specific version of Windows, such as the Windows 7 that I am using? Or is it something else?

Upvotes: 7

Views: 3175

Answers (4)

Sarima
Sarima

Reputation: 749

I encountered this problem a few weeks ago, when using a bargraph to show the progress of ~500 operations completed consecutively. I found that the processes were finished much before the bargraph had even got halfway. I used the code below as a work around:

bargraph.value = (Target + 1)
bargraph.value = (Target)

Where bargraph is the name of your object, and target is where you want it to move to.

Because the bargraph has a graphical aspect, the marquee effect, it takes time to catch up. Even though the graphical side could be showing a value of 50, the actual bargraph.value could be 60! By setting the value to a level, and then reducing it by one, the bargraph instantly(ish) updates the graphical side.

EDIT

As the comment below shows, the answer above may not work when you are trying to set the value to maximum.

Now, i havent tried this but i think something along the lines of below would work:

if (bargraph.value <> Target) then
   if (Target = bargraph.maximumvalue) then
      bargraph.maximumvalue = Target + 1
      bargraph.value = (Target + 1)
      bargraph.value = (Target)
      bargraph.maximumvalue = Target
   else
      bargraph.value = (Target + 1)
      bargraph.value = (Target)
   end if
else
end if

As i said, untested, but the principle should work.

Upvotes: 1

dARKpRINCE
dARKpRINCE

Reputation: 1568

I have tested the code provided by you using the lasted version of SWT (4.3 Final Release - 5 June 2013) under Windows 7 SP 1 and Windows XP SP3. In both cases the progress bar updated without delay. Maybe an update of the SWT library will help.

Upvotes: 1

n3k0
n3k0

Reputation: 579

You can follow this tutorial, it describes how you can make Eclipse Jobs in order to execute long jobs apart of the EDT, and just updates the state of your components. Hope this helps, Cheers!

Upvotes: 1

greg-449
greg-449

Reputation: 111217

It looks like this may be a bug in the Windows version of ProgressBar as the code works on Linux and Mac OS X.

The Windows version of ProgressBar.setSelection does have some code that says it is trying to deal with an issue that sounds like this but it is only done if the state is not Normal - which may be be why it works on the Error and Paused state. Their fix just does the selection again so maybe calling setSelection twice would work!

Upvotes: 4

Related Questions