My VBlankAttachment causes repainting whole parent Component, even the area which is not marked as “dirty” in repaint() and even though the “dirty” area is opaque. Is it normal behaviour? Or do I do something wrong?
I have plugin which has two main components.
One is remote panel (mainViewComponent) with standard plugin components like sliders, buttons etc. And that one is repainted only when needed.
And another one is frequency analyser (analyserViewComponent) which uses VBlankAttachment for smooth painting.
The problem is that when I set analyserViewComponent.setVisible(true); then VBlankAttachment causes repainting also mainViewComponent which I don’t need to and actually it is pain in the ass, because mainViewComponent::paint() is quite heavy and I don’t need to repaint it if not needed.
I set both components to setOpaque(true); and of course both components fill all bounds with solid colour. In addition both component doesn’t overlap each other.
Does anyone know what could cause such issue?
In more details the plugin works as follows:
Frequency analyser can be toggle on/off. When off then the whole component is set to setVisible(false);, and its VBlankAttachment is destroyed and whole plugin editor is resized to bounds required only for mainViewComponent. And then everything works fine (mainViewComponent is repainted only when required).
But when analyser is toggled on, then editor is resized to bounds required for both components so no one component overlaps another one. VBlankAttachment is set as follows:
OK, I found what causes my issue. I will try to explain if anyone has similar issue.
Unfortunately in my case there is no good solution. I have asctually two components which use VBlankAttachment. The fft analyser and level meter which is located on remote component. Even though level meter takes only small area part of the whole parent component the issue is because of composition (layout) of level meter and fft analyser which looks as follows:
So even though I call repaint only for orange components, the parent component does not draw list of rectangles but only single rectangle area (white frame) in which both orange repainted components can be fit.
So it looks like the only solution is to change the layout of components.
Hi there, I don’t think this has to do with the VBlankAttachment. I would expect the same to happen if you called repaint() using a timer.
You could try calling setBufferedToImage (true) on the remote panel. But for this to work the remote panel should not have children that will constantly get repainted. Turn it into a separate component. Add it, as well as the the level meter and the fft analyser, as children to the main view component. That way the remote panel, the fft analyser and the level meter are all siblings.
And, if on macOS, you could try the preprocessor definition JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS=1
Thanks aamf. Yes, you are right that described issue has nothing to do with VBlankAttachment. I forgot to mention about that in my own answer
But I have question to mentioned by you setBufferedToImage(true).
I try to understand it, what exactly it does. In documentation they say something like:
…so that when asked to redraw itself, it can use this buffer rather than actually calling the paint() method
I want avoid repainting if it is unnecessary. But it looks like it setBufferedToImage(true) causes that component is still repainted (even if not needed) but doesn’t call paint() method. So what in case if in my paint() method there is code that is lighter for rendering than painting buffered image? Does it make a sense to use setBufferedToImage(true) in such scenario?
By the way I am not sure if such case is even possible but my point is to ask if setBufferedToImage(true) will cause avoiding refreshing that part of screen which is ocupated by that Component.
I suppose it can be stupid question but I am not familiar in rendering, graphic cards etc.
@pajczur - are you on MacOS? This will almost definitely fix it. I had an issue where two LEDs on opposite sides of the GUI that happened to blink at the same time were refreshing the entire rectangle between them. This fixed it.
@stephenk - how did you find out that the rectangle in between was being refreshed? By enabling repaint debugging, checking if repaint() was being called, profiling… ?
@aamf - It was a while ago, but from some notes I made at the time:
I was able to prove this by putting this code in ComponentPeer::handlePaint(), in the JUCE_ENABLE_REPAINT_DEBUGGING section right after the g.FillAll(), to show the bounds of the clipRectangle. (JUCE_ENABLE_REPAINT_DEBUGGING must be enabled, but you can comment out the g.FillAll())
// TEMPORARY_EDIT
auto r = g.getClipBounds();
std::cerr << String::formatted("bounds x %03d, y %03d, w %03d, h %03d",
r.getX(), r.getY(), r.getWidth(), r. getHeight()) << "\n";
This lets us see the actual regions that are called to repaint, which JUCE_ENABLE_REPAINT_DEBUGGING does not display correctly.
…are you on MacOS? This will almost definitely fix it.
Yes I’ve just tested. Preprocessor definition JUCE_COREGRAPHICS_RENDER_WITH_MULTIPLE_PAINT_CALLS=1 fix it on Mac. But actually my client reported issue on Windows. So I need to find some good solution which would work on Windows too.
I’ve not seen it reported that Windows had this same exact problem, in the same way… My Windows version did not have the same problem as the Mac version. Maybe it’s something else…