FR: componentLookAndFeelChanged() in ComponentListener

We’re trying to solve the problem of having Components with custom look and feel methods being implemented in a custom LookAndFeel class without the need to dynamic_cast to our custom type from Component::getLookAndFeel() every time the component is painted.

E.g. instead of

void paint (juce::Graphics& g) override
    if (auto laf = dynamic_cast<LookAndFeelMethods*>(&getLookAndFeel())

we can have

void paint (juce::Graphics& g) override

Currently our lookAndFeelHandlerObject is a templated class that holds a pointer to a nested LookAndFeelMethods struct that each of our custom components has (similar to how juce components do it). The class privately inherits from Component and adds itself as a child to our custom components so it can receive callbacks when its look and feel changes (and therefor the parent’s) where it can then update the pointer it holds.

This method is a little hacky as we have to have a Component that’s not actually acting as a ‘real’ component. It would be a lot nicer if we could have it as a ComponentListener instead but currently there’s no componentLookAndFeelChanged() callback in ComponentListener.

1 Like


Any arguments for or against this?

Maybe there’s a completely different technique to all this that we’ve completely missed. Any suggestions would be very much appreciated!

If you only need this in your own custom components, you could write a very tiny extension to Component (untested, but should communicate the general idea):

struct LnFBroadcastComponent : public juce::Component
    struct Listener
        virtual ~Listener() noexcept = default;
        virtual void lnfChanged() = 0;

    void lookAndFeelChanged() override { ([] (auto& l) { l.lnfChanged(); }); }

    void addLnfListener (Listener* l) { listeners.add (l); }
    void removeLnfListener (Listener* l) { listeners.remove (l); }

    juce::ListenerList<Listener> listeners;

Then, your components which need LnF notifications can just derive from this type instead. Might something like that work?