Probably a long shot, but it keeps bubbling to the surface so I’ll throw it out there.
It would be amazing if the framework helped us access paint call frequency / times. For example the ability to supply a callback function to be run “beforePaint” and “afterPaint”. Or a macro that when enabled dumps some internal timing information from paintComponentAndChildren into the component’s properties.
It came up again because I’m working on the next version of my component inspector and would love to display the last paint timings of the selected component in the inspector to aid with debugging.
This is somewhat relevant, so just making sure you’re aware of the VBlankAttachment class. All such attachments are triggered before the paint() calls for that particular frame. So this probably meets the beforePaint requirement. I can’t recall anything for afterPaint though.
This looks like a great way to get notified of the when the peer starts painting. For example, to calculate the overall frame rate (or one half of the data needed to determine overall paint time).
I couldn’t figure out how to only get notified when the call pertains to a specific component, though…
I tried adding an VBlankAttachment with a DBG in it for a component and it constantly fires (vs. firing when the specific component’s is dirty, visible, etc). It seems like the component relationship exists only to choose which peer the callback is attached to? So it doesn’t seem like it would be usable for a per-component beforePaint…
Btw, looks like the filenames have a typo: VBlankAttachement.h (extra e).
You’re right, it’s called at every VBLank event, and it’s main use case is to update the Component’s state in lockstep with the screen refresh and have smooth animations that way. So you’d actually call repaint() from inside a VBlank callback when necessary.
The Component relationship is indeed for deciding which peer to attach to.
I can see now that it’s not exactly useful for your use case, because it doesn’t in any way line up with the paint times of one particular Component. In fact first all VBlankAttachment will be notified, then all Components that need it will be redrawn. So there will be a varying amount of time before the VBlank and the call time of paint() for one particular Component depending on how long other components took to paint.
I’d like to say it’s the VBlankAttaché’s job to relay these events, so there’s an extra ment at the end , but you’re right.
Ahhhh, awesome, so this is the underpinning of animation support? Meaning, I can toss out all the timers I’m using for animation and replace them with a VBlankAttachment which passes a callback that calls repaint() to have perfectly synced frames. Looking forward to giving that a go!
I can see now that it’s not exactly useful for your use case
It will let me add an FPS counter to the inspector (which is cool!), but I’m hoping the framework can provide a bit of debugging/introspection/hooks at the per-component level…
This is exactly the type of tooling I’d love to be able to build for the community. Guarded with a macro (so it can also run in Release) is perfect, though for everyone to take advantage of the tool as a module, callbacks would need to be in JUCE proper….
If it can be of any help, I have this little class template that acts as a wrapper for any Component, to inject code to be executed together with its paint() method.
See the doc there for explaination
/** Adds to a Component a std::function member that is called when its paint()
method is invoked.
auto label = WithLambdaPaint <juce::Label> ("my label", "Some text");
label.onPaint = [this] (Graphics& g)
// this code is "injected" before the actual Label::paint()
g.fillRect (label.getLocalBounds ().reduced (10));
paintBaseClass (g); // <- this calls Label::paint()
template <typename BaseComponent>
class WithLambdaPaint : public BaseComponent
using BaseComponent::BaseComponent; // import the same constructors of the base class
/** When this member has a value, the `paint()` callback of this class
invokes it and returns. In that case, it's up to the assigned functional to
call the paint behaviour of `BaseComponent`, if desired.
Because `paint()` is a protected function of JUCE Components, the public
`paintBaseClass()` function is provided, which can be called in place of
`BaseComponent::paint()` where needed.
When this member has no value, the `paint()` callback of this class invokes
`BaseComponent::paint()` directly, preserving the existing behaviour of
`BaseComponent` when it is not customized via `onPaint`. */
std::function <void (juce::Graphics&)> onPaint;
void paintBaseClass (juce::Graphics& g)
public: // overridden methods
void paint (juce::Graphics& g) override
And thanks for sharing reFX JUCE fork ! It contains a bunch of fixes i was looking for, but never had the time to investigate into JUCE internals ! Really hope some of those fixes will get into JUCE someday, but i my usual feeling is coming back on this one…