Callback on repaint?


#1

I’m in a situation where I need to know when a component has repainted itself. I can use the (very handy) Timer::callAfterDelay method to delay things, which works most of the time, but obviously the delay required varies across devices. Also feels too much like a hack.

Would be nice to have an optional callback parameter to e.g.

repaint (std::function<void()> callback = nullptr)

so we know when a repaint has completed.

Unless there is another way around this problem?

EDIT - rereading the documentation, I see this may not be possible as it’s waiting for the OS to do the redrawing…


#2

Why do you need to know once it’s been repainted?
The paint method should just draw the current state of the data, maybe there’s another event you should be hooking in to?

(Also be careful with Timer::callAfterDelay, if you call this from your paint method, you’ll likely get a lot of callbacks, especially if your component is continuously being repainted, moved or animated in some other way).


#3

Also note, that it is bad practise to add side effects to painting,
a) because they happen indeterministic (as a result of occlusions on the screen, resize or move actions and so on
b) they might slow down painting
c) bugs are hard to find there

Only paint in paint!

Good luck


#4

I’m not calling callAfterDelay from within the paint method - I’m using it to refresh a component which relies on some processing. I’ve nailed it down with lambda callbacks so I know when the processing has completed, but even with that it still occasionally fails to redraw unless I introduce a delay.


#5

Is the processing on a background thread? Is it possible that the thread hasn’t actually finished and committed the results before the painting happens?

Is it the paint method that’s not getting called or is the data you’re painting not ‘complete’ when the paint method is called?


#6

Yes, its processing on a background thread. Pretty sure the paint method is getting called but the data is not yet complete. The thread calls triggerAsyncUpdate on completion (which should then trigger the repaint). Strange as there’s nothing on the thread that looks asynchronous.


#7

Are you aware of the flow of repaint() and paint()?

The repaint only marks an area as dirty. In the juce_Component.cpp you see, that only the heavyWeightPeer calls the paint() callback. Otherwise it will stop at the component with no parent, see here:

The entry for the actual paint() is ComponentPeer::handlePaint() (easily found with a breakpoint)

So I think you don’t get a paint call without an addToDesktop()


#8

That looks like a good clue. The component in question is embedded in an iOS UIView, and so Juce may think its not visible and therefore not schedule it for repainting. Some more investigation needed…