简体   繁体   中英

Flex AS3: ProgressBar doesn't move

I am a little stuck and need some advice/help.

I have a progress bar:

<mx:ProgressBar id="appProgress" mode="manual" width="300" label="{appProgressMsg}" minimum="0" maximum="100"/>

I have two listener functions, one sets the progress, and one sets the appProgressMsg:

public function incProgress(e:TEvent):void {
    var p:uint = Math.floor(e.data.number / e.data.total * 100);
    trace("Setting Perc." + p);
    appProgress.setProgress(p, 100);
}
public function setApplicationProgressStep(e:TEvent):void {
    trace("Setting step:" + e.data);
    appProgressMsg = e.data;
}

I want to reuse this progress bar alot. And not necessarily for ProgressEvents, but when going through steps.

For instance, I loop over a bunch of database inserts, and want to undate the progress etc.

Here is a sample:

public function updateDatabase(result:Object):void {
    var total:int = 0;
    var i:int = 0;
    var r:SQLResult;
    trace("updateDatabase called.");
    for each (var table:XML in this.queries.elements("table")) {
        var key:String = table.attribute("name");
        if (result[key]) {
            send(TEvent.UpdateApplicationProgressStep, "Updating " + key);
            i = 1;
            total = result[key].length;
            for each (var row:Object in result[key]) {
                //now, we need to see if we already have this record.
                send(TEvent.UpdateApplicationProgress, { number:i, total: total } );
                r = this.query("select * from " + key + " where server_id = '" + row.id + "'");
                if (r.data == null) {
                    //there is no entry with this id, make one.
                    this.query(table.insert, row);
                } else {
                    //it exists, so let's update.
                    this.update(key, row);
                }
                i++;
            }
        }

    }
}

Everything works fine.

That is, the listener functions are called and I get trace output like:

updateDatabase called.
Setting step:Updating project
Setting Perc 25
Setting Perc 50
Setting Perc 75
Setting Perc 100

The issue is, only the very last percent and step is shown. that is, when it's all done, the progress bar jumps to 100% and shows the last step label.

Does anyone know why this is?

Thanks in advance for any help, Jason

The new code, which works awesomely I might add:

public function updateDatabase(result:Object, eindex:int = 0, sindex:int = 0 ):void {
    var total:int = 0;
    var i:int = 0;
    var j:int;
    var r:SQLResult;
    var table:XML;
    var key:String;
    var elems:XMLList = this.queries.elements("table");
    var startTime:int = getTimer();
    var row:Object;
    for (i = eindex; i < elems.length(); i++) {
        table = elems[i];
        key = table.attribute("name");
        if (!result[key])
            continue;
        total = result[key].length;
        send(TEvent.UpdateApplicationProgressStep, "Updating " + key);
        for (j = sindex; j < result[key].length; j++) {
            if (getTimer() - startTime > 100) {
                setTimeout(updateDatabase, 100, result, i, j);
                send(TEvent.UpdateApplicationProgress, { number:j, total: total } );
                return;
            }
            row = result[key][j];
            r = this.query("select * from " + key + " where server_id = '" + row.id + "'");
            if (r.data == null) {
                //there is no entry with this id, make one.
                this.query(table.insert, row,false);
            } else {
                //it exists, so let's update.
                this.update(key, row,false);
            }
        }
        send(TEvent.UpdateApplicationProgress, { number:1, total: 1 } );
    }
}

Flash is single threaded. The display will not update until your function returns. For this reason, you should never have any code that runs for longer than about 100ms (1/10th of a second), otherwise the UI (or even the entire browser) will appear to be locked up.

The general solution is to split up your work over multiple frames, here is some pseudo-code:

function doWork(arg1:Obj, arg2:Obj, start:int=0) {
   var startTime = getTimer(); // store starting time
   for(i=start; i<length; i++) {
     if(getTimer() - startTime > 100) { // see if we've been working too long
        trace("Current progress: "+(i/length * 100)+"%");
        updateProgress( i / length );
        setTimeout(doWork, 100, arg1, arg2, i); // schedule more work to be done
        return; // stop current loop
     }
     trace("Working on item "+i);
     // processing here
   }
   trace("All work done");
}

doWork(data1, data2); // start the work

Your pseudo-code works for updating the progress bar however in my case my "work" was copying of files from DVD to the appStorageDirectory which seem to reintroduce the same issue that your work around resolved - the progress bar now does not update

Here is my hack of your solution

function doWork(arg1:int, arg2:int, start:int=0) {
    var startTime = getTimer(); // store starting time
    for(var i:int=start; i<arg2; i++) {
        if(getTimer() - startTime > 100 ) { // see if we've been working too long
          trace("Current progress: "+(i/arg2 * 100)+"%");
          setTimeout(doWork, 100, i, arg2, i); // schedule more work to be done
          return; // stop current loop
      }
      trace("Working on item "+i);
      dispatchEvent(new progressMadeEvent("incrementChange",i,arg2))
      var dir:String = copyRes[i].nativePath.toString().split(OSSep).pop()
    copyRes[i].copyTo(appStore.resolvePath(dir)) // copies dir from DVD to appStorageDir
    }
    trace("All work done");
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM