Questions paint() resized() and AnimatedAppComponent

Hello I have some questions about the topics in the title:

  1. Is the paint function repeadetly called in a loop somewhere or is it only called when resized() has been triggered?

  2. I tried around with the whole ui-component-nested-hierarchy thingy. Everything worked fine until I turned one of my child components into a class that is derived from AnimatedAppComponent instead of just Component. I wanted to animate some basic geometry(like in the tutorial).
    Only an instance of that class inside my MainComponent worked fine. It animated an ellipse in a simple sinusoidal way. However as soon as I brought in other components (derived from the normal component class) the background went black and nothing worked anymore.

I integrated the update() and everything, in fact I basically stole the class from the Animating Geometry tutorial.
Is there maybe something I have to care about with the AnimatedAppComponent? For ex.: If used, must it then be my MainComponent that is derived from it or something?
Theres nothing about it in the tutorial though and the class doc also has no warning.
I also tried changing the order in which the different components were added and made visible. Nothing made a difference.

paint() is called whenever the given Component is flagged as needing a repaint. This happens automatically when the component is resized (and various other times) and can be done manually by calling repaint().

juce::AnimatedAppComponent is typically only used for top-level components in a project. I can’t say exactly why you’re experiencing the error you described but I would start by not using juce::AnimatedAppComponent.

If you want a component to be repainted regularly you could use a juce::Timer, like so:

class MyAnimatedComponent : public juce::Component,
                            public juce::Timer
{
public:
    MyAnimatedComponent()
    {
        startTimerHz (60);
    }

private:
    void paint(juce::Graphics& g) override
    {
        // ...
    }

    void timerCallback() override
    {
        repaint();
    }
};

Ok great, then I will in future just skip the “unnecessary middle-man” AnimatedAppComponent and use Timer instead. Thanks!

1 Like

Yes, that’s a good way. The only thing to take away from looking in the AnimatedAppComponent is to update your model in the timer, not in the paint(). The intervals of paint() are non deterministic, while the timerCallback is (within the limits of the Timer/MessageManager accuracy).

void timerCallBack() override
{
    advanceModel();
    repaint();
}

But that is really not reason enough to use that class.

2 Likes

Speaking about timer accuracy… I know this is a little bit above my skill level right now anyways but I started wondering which kind of timer one would use for something like an arpeggiator or sequencer…

In that case no timer at all. A timer fires in real time, e.g. against the wall clock.

MIDI events are timestamped against the audio clock, and that is what you have to synchronise to.
Audio clock means simply counting samples.

We speak of realtime processing, but that is misleading. Actually we execute a callback that needs to produce enough samples until the next callback occurs. But the callback is not actually running during the whole time span.

Hope that helps

1 Like

That went right over my head haha
I think I better practice more and come back to those topics when I´m really ready.

Thanks anyways!

I know this thread is super old but anyway…

I built the tutorial as is and then did a remake with a class inheriting from Component and Timer instead.

When I compare the app made with AnimatedAppComponent and the one inheriting from Component and Timer the animations looks identical but on my computer (MacBook 2016, i7 processor, Mojave) the ActivityMonitor will more or less constantly show a CPU-percentage difference:
AnimatedAppComponent: 10%
Inheriting from Component and Timer: 15%

That’s quite a difference!

My imlpementation is identical apart from one int for frameCount used instead of the getFrameCounter(), it’s ++updated in the timerCallback which is set at 17ms (corresponding to 60 fps).

So it seems it can be worth using AnimatedAppComponent instead of a Component when possible.

one thing i learned lately is that a component is almost always improved by setting setBufferedImage(true). it makes your component save the last painted state in a temporary image. when now another component overlaps this component, or any other reason why your component would have to repaint now it will not call paint again but just draw that image from last time. it will only actually call paint if you or anyone actively calls repaints on it. that gives you pretty much full control over the paint routine. then instead of using AnimatedAppComponent you just let the component, that should have an animation, inherit from juce::Timer and use the timerCallback() method to update things. in there you can clearly define in which cases repaint is needed at all, which sometimes improves things a bit

setBufferedToImage (true); is a powerful tool but don’t overuse it! You should only ever use it if you’re sure that painting the component will be slower than painting an image of the same size. You should always benchmark a component before buffering it to an image.

I’ve found that in almost all cases, drawing an image is much slower than just rendering the path, or whatever you’re drawing.

Text is maybe the only time where I’ll always buffer to an image as text rendering is particularly expensive. Rendering text over a spectrogram for example, it’s usually much faster to render your FFT with 1000+ points using a smoothed path and a gradient fill, than it is to render a dozen or so labels for the frequency markers.

2 Likes

ok, maybe it’s not as easy as i thought. but i do have to say my current project has a lot of text in it, so maybe that’s just the reason why it felt like a general improvement. i mean text is everywhere. names, parameter values, signs… all that. and it’s getting even worse when components overlap. say you have something overlap a parameter. the parameter itself might have quite a complicated paint method already but then a popup window is displayed on top. you definitely want to be in control of the paint calls a bit