(SOLVED) Repaint() ignores opacity and repaints parent Component

Hey guys!

I’m running into some CPU issues with repainting and hope that anyone could help :slight_smile:

I have a small MIDI activity LED Component. It sets a “needs repaint” flag when it receives a MIDI event. The LED component checks the flag using a Timer, and calls repaint() if needed.

The LED has setPaintingIsUnclipped(true) and setOpaque(true). [EDIT] The issue occurs no matter if I call setPaintingIsUnclipped or not.

When the LED calls repaint(), it goes into internalRepaintUnchecked, and then, without checking for opacity, straight into parentComponent->internalRepaint().

I’ve set breakpoints in the paint() method of my background component. It’s getting called repeatedly, and the clip region seems to be the area below the LED. I might be missing something, but considering the LED is opaque, why is the parent being repainted?

Another thing I noticed is that if two small Components need to be repainted, and they are in two opposite corners of the UI, JUCE repaints almost the entire background, and not just the small areas below each of the two Components. Is this intended?

You probably don’t want both of these on, conceptually they’re kinda mutually exclusive and you may run into some issues having both of them on outside of the issue you’re experiencing.

I would only use setPaintingIsUnclipped(true) for things that may be transparent but will only draw inside their bounds, and setOpaque(true) for things that draw over their entire bounds

This may depend on the platform, for instance I know the CoreGraphics backend on OSX will coalesce the separate rectangles into one big region

Thanks @TonyAtHarrison! That’s very helpful insight, especially about Core Graphics (I’m on OSX). Important to know.

You probably don’t want both of these on, conceptually they’re kinda mutually exclusive

That’s interesting; could you explain why they’re exclusive, and what types of issues could happen? Because from the docs they sound unrelated, one is about transparency, the other about bounds.
I’ve removed the setPaintingIsUnclipped call, but the parent still repaints…

Only conceptually, so to speak, as you can have both on… but how can a Component be opaque and draw anywhere on screen? It would really mean only the lowest Component in the hierarchy could be seen if we really enforced the rule of “fill the entire clip region if you’re marking yourself opaque” :slight_smile:

You’ll run into the issue that you’re seeing, for one. Also seen here:

And on top of that there will actually be unnecessary clipping because JUCE isn’t checking the “unclipped painting” flag of siblings when drawing each child. So excludeClipRegion() is still used for all these component bounds, even though the components aren’t clipping anyway when they draw themselves:

1 Like

Ok, that makes sense in a way.

Thanks for the link! :+1: I’ve enabled the JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS flag mentioned there, and it’s much better now. I’ll keep an eye out if anything else has a disadvantage from it, but maybe it’s better to keep it on for my purposes.

From what I can tell now, some of my opaque components cause the background to be repainted because I have a scaling AffineTransform on my entire UI. So even though they are opaque, at the borders they have to be mixed with the background because their position is between pixels.

I should mention that this won’t work on the latest macOS SDK / Xcode 10… I spoke with @t0m about it at ADC and Apple broke an API JUCE needs for determining the dirty regions :slightly_frowning_face:

We use it too so we’re staying on Xcode 9.x for the time being