AlertWindow progressbar issue


#1

Hello, I have a simple project with a custom AlertWindow and I don’t understand why the progress bar doesn’t repaint itself. The progress goes from 0% to 100% directly without all percents between. Even with a bigger timer interval, there is no gui update …

The Alertwindow is a member of window that display it on mouse up
image

I know there is a ThreadWithProgressWindow but I want to understand why here it’s not working :slight_smile:

EDIT : With more tests I found that with a sleep time of 500 there is the issue, but with less than 495 there is not the issue. I guess 495-500 is the latency with the sleep. But still is a problem because in the real use case I have, the tasks may be longer than 500ms.


#2

Division of two integers will truncate decimals. So:

percent = i / imax;

Will effectively yield 0.0 (integer 0 implicitly cast to double) until i == imax which will then yield 1.0. You’ll want to use double i, imax; or just cast when doing the division:

percent = (double)i / (double)imax;


#3

Oops ! I did the mistake when I created the example, but I have a more complex class that have the issue without this little error. I edited my main post, thank you ! :slight_smile:


#4

Your task is running on the same thread that you’re trying to repaint with. If you run a timer (which does time using its own thread under the hood) at 500ms and the timer callback sleeps for 500ms, when the sleeping ends the timer callback will run again.

It’s very likely you’re blocking the repaint from ever happening because the main thread is constantly in this loop of the someTasks() function. Remember that calling repaint() just marks a region dirty, the actual time when the screen is updated is dictated by the OS.

When you use 495 you’re not causing it to be such a direct callback loop so the message manager is able to trigger the repaint events.

Usually you would use progress bars/displays for operations that don’t run on the main UI thread. If they’re running on the UI thread then the GUI is tied up until the tasks are finished.


#5

Thank you for your reply TonyAtHarrison :slight_smile:

But I thought the Timer juce was running in MessageThread too. And if the message Thread was blocked, the timer would simply be called late. It’s not the case ?

So, even if each task ends relatively shortly (500ms is long, but not that long) and let the messageThread continue, the repaint event could be ignored by the OS ?
If you’re right, it means that I have no other choices than use an other thread to make my tasks and update the GUI properly.

I made some others tests, and when I put the content of the timerCallBack() in paint() and call repaint() in the timerCallBack, the repaints goes like I expected they did. But it’s so dirty, and make me more confused about what’s going on … ^^’


#6

The timer runs (i.e. calculates time) its own thread, but the actual timer callbacks are dispatched in the message thread

What I meant in the previous post was that you aren’t letting the main thread continue if the time for startTimer() and sleep() is so close (or the same). When they’re the same effectively the timer thread constantly tells the main thread to sleep… so that’s likely all the main thread can do instead of being able to repaint or handle other events.

If you don’t mind blocking the UI thread (keyboard/mouse events, etc.) you could do this approach instead of using a separate thread.

For that approach think of it kind of like a render loop: the timer triggers the ‘loop’ to start, you update your state (the logic previously in timerCallback()), and then render.

However, the operating system can choose to drop or coalesce repaint calls… so putting the update logic in repaint only is useful for certain cases. In the case I used it in the state we were updating was some cached path stuff, which is only ever used by the paint() function anyway. It wouldn’t be a suitable approach for non-graphical related state in my opinion.


#7

Your solution is not really usable. In that you trying to run a progress bar on a process that is running on the Message Thread. Your Timer and Thread::sleep are both running on the Message Thread


#8

Ok, I think I get it. And that explains why juce implemented a ThreadWithProgressBar class. I would have prefered not to use thread because of data access questions, but it seems to be the better solution inmy case too.

Yes, I thought it wasn’t a problem until those tests. I didn’t know that Thread::sleep is asynchrone