What is WEB Core equivalent to VCL Application.ProcessMessages ?

I'm trying to update a TWebProgressBar and the whole thing finishes before the UI ever updates.

In VCL you'd call Application.ProcessMessages

How do you get the same effect in WEB Core?

Can you describe in a little more detail the item being monitored? There are different approaches possible depending on what is going on.

For example, if you want a progress bar for a large download, you can check out this post:

If you just have a simple loop that's doing something in a series of steps, it may be that JavaScript never has a chance to do anything else while the loop is running. You can maybe convince it otherwise by inserting an artificial delay. Kind of like what Application.processMessages does, but in this case, it is giving the browser an opportunity to refresh. Actually more like a sleep function though implemented rather differently. Generally not a good idea performance-wise, but performance isn't the only priority of course. First, define a sleep function, may be in WebFormCreate:

asm   
  window.sleep = async function(msecs) {return new Promise((resolve) => setTimeout(resolve, msecs)); }
end;

Then, whenever you want to insert a tiny delay, try something like this. Any method that uses this will need to have the [async] attribute:

asm await sleep(50) end;

The delay does not need to be very large to get the intended effect. There may be other options, depending on what it is that is being measured. Also, if you're just wanting to show that something is "busy" rather than a specific amount of progress, animated icons work pretty well for this. For example, if Font Awesome is part of your project, you can add a label or a button somewhere with an icon that spins while the work is being done.

WebButton1.Caption := '<i class="fa-solid fa-atom fa-spin"></i>';

And then remove the 'fa-spin' class when you're done.

WebButton1.Caption := '<i class="fa-solid fa-atom"></i>';

I've got a loop processing several states inside of a Case block that are preparing a Web Audio buffer. When it hits the Play state, the await resumes after Start is called, but there's a callback for when it finishes. In VCL parlance, I'd just call Application.ProcessMessages and it wouldn't steal the CPU or lock everything else in the UI out. But in this case, nothing else happens until the callback gets control when it's done. Then it shows the trackbar filling up and the other messages that were pending for debugging. The loop just doesn't have anything to wait on, so it just sucks up all of the browser's attention.

It would be nice if there was a way to issue an await on some variable changing state, like what you can do in Dephi's IDE when debugging. Given how weird JS is, there may well be... are you aware of anything?

for example:

await( currentState = time_to_eat );

where some other thing would set currentState periodically with different values.

I could make a service like that, but the timeliness might be a bit elastic if it was running remotely.

Sounds like the icon spinner might be the better approach here, if the actual progress isn't slow and gradual, particularly if it isn't a long period of time? How much time are we talking about?

Other than sleeping between periods of work (like sleep whenever you update the progress bar) I'm not aware of any special JavaScript shenanigans that can help, but maybe others might.

I'm looking for a progress bar, not a busy-spinner.

I guess I could just let it fall out the end of the loop and then use a timer to update the prog bar...

I realize - the spinner doesn't get blocked the way the progress bar does, just an option. Is there a place to insert a "sleep" call during the progress?

the web audio just keeps playing until it's finished or you stop it. The loop runs independently of it. I'm just trying to figure out how to update a progress bar. My code is doing that, but the display isn't being updated. The same thing can happen with VCL stuff, if you're in a tight loop and nothing causes the form to get attention, it won't update the screen unless you call Application.ProcessMessages.

The TWebProgressBar has no .Refresh method, but it does have .Invalidate -- unfortunately, it doesn't cause the bar to update until the loop quits running, which is when the buffer is fully played.

How did you get the prog bar on your player to update? Using a timer and polling the CurrentTime on the AudioContext? Or some other way?

Yes, exactly, via a separate Timer. Every 100ms it subtracts the start time from the current time and then updates whatever needs to be updated. But in this case, the "busy" thing is just the audio track playing, which isn't really a blocking thing.

Thanks, Andrew. In my case the progress bar went from invisible to working as intended by using sleep(1) after each Position update.

1 Like

I ran into a situation where there was a timing disparity between one thing finishing before another thing, and I was checking for the 2nd thing being ready and just bailed-out if it wasn't. I really wasn't expecting that to occur, and it surprised me to track it down and discover that was the problem.

So instead of exiting, I used this solution (with the 50 ms delay) and put it into a while loop to wait for a state flag to signify the 2nd thing was ready. I added a counter to it just for laughs and it said it looped 27 times while waiting. :slight_smile:

I put the sleep function definition in the initialization section at the bottom of the unit and it worked perfectly.

1 Like