How to display progress during a loop

I have a loop that renders several svg files to bitmaps. I’m looking for a simple way to display progress while looping.

Here’s my function. It doesn’t show the _tfProgess textfield at all. How do I free up the loop to allow the progress to update?

private function renderCards(themeIndex:Int, cardSize:Float, cardsPath:String, cardCount:Int):Array<Bitmap>
{
    var bitmapArray:Array<Bitmap> = new Array();
    
    _progressTimer.start();
    _tfProgress.visible = true;
    
    for (i in 0...cardCount) {
        
        var card = renderSVGtoBitmap(Std.int(cardSize), Std.int(cardSize), cardsPath + "/" + themeIndex + "/" + i + ".svg");

        bitmapArray.push(card);
    }
    
    _progressTimer.stop();
    _tfProgress.visible = false;
    
    return bitmapArray;
}

What targets you plan to support (flash / html5 / android / ios / etc.)?

Sorry. I’m targeting android and ios. I’m also using old haxe 2.10 NME 3.5.5 sinceI haven’t been able to get openfl working on my XP machine.

First of all, you must make you function asynchronous. Not sure about NME, but in OpenFL you can do following:

  1. Render card by card on every frame. This approach will work for all targets including flash, but can be laggy:
class Test {
    private var bitmapArray : Array<Bitmap>;
    private var currentCardIndex : Int;
    private var themeIndex : Int;
    private var cardSize : Float;
    private var cardsPath : String;
    private var cardCount : Int;
    private var onCardRenderedCallback : Array<Bitmap> -> Void;
    // more vars like _progressTimer and _tfProgress

    // more methods

    private function renderCards(themeIndex:Int, cardSize:Float, cardsPath:String, cardCount:Int, onCardRenderedCallback : Array<Bitmap> -> Void) : Void {
        this.themeIndex = themeIndex;
        this.cardSize = cardSize;
        this.cardsPath = cardsPath;
        this.cardCount = cardCount;
        this.onCardRenderedCallback = onCardRenderedCallback;

        bitmapArray = new Array();
        currentCardIndex = 0;

        _progressTimer.start();
        _tfProgress.visible = true;

        onNextTick(renderNextCard);
    }

    private function renderNextCard() : Void {
        if (currentCardIndex >= cardCount) {
            _progressTimer.stop();
            _tfProgress.visible = false;

            onCardRenderedCallback(bitmapArray);
            return;
        }

        var card = renderSVGtoBitmap(Std.int(cardSize), Std.int(cardSize), cardsPath + "/" + themeIndex + "/" + currentCardIndex + ".svg");
        bitmapArray.push(card);

        currentCardIndex++;
        onNextTick(renderNextCard);
    }

    private function onNextTick(callback : Void -> Void) : Void {
        // any method to run callback on next frame: timer or Event.ENTER_FRAME or anything else.
        // for simplification I use Actuate.timer
        Actuate.timer(0.001).onComplete(callback); 
    }
}
  1. Since you targeting native platforms, you can try to render cards in background thread. But I’m not sure if it is possible in Haxe 2.x.

P. S. Minute of self-promotion: for Haxe 3.x I would recommend hxbolts library. With this lib you can easily run what you want on background threads, and update results on UI thread.

1 Like

Thanks restorer. I appreciate the help. I’ll try this and check out the hxbolts library after some needed sleep.

It is entirely possible that such a loop would run to completion in less than one timer-tick.   You’re rendering about 52 SVG’s into bitmaps?   That doesn’t take long.

Otherwise:   within your loop, after so-many cards have been rendered, you must calculate percent-progress and then update the display, before resuming your loop.   Trouble is, the act of doing such a thing will slow-down the loop considerably.