Default LookAndFeel

I’m trying to use LookAndFeel::setDefaultLookAndFeel() in the editor but the child components are instantiated before my constructor runs so it’s not affecting them. How would I go about doing this? I’m aware that I can manually set the LookAndFeel on every class but setting a default seems much cleaner.

All you need to do is to create a CustomLookAndFeel class (derived from LookAndFeel_V4) and once you set your editor to use it, all child components will use it as their default LNF. Nice and clean. (remember to set call setLookAndFeel(nullptr) in the destructor)

That’s what I’m doing. But as far as I can tell, the set default does not update existing elements.

IIRC, setting the default look-and-feel doesn’t trigger any sort of callbacks so your child components won’t know when it has changed in order to pick up its changes.

You could instead call setLookAndFeel() on the top-level component and have the child components override lookAndFeelChanged() to be notified when this happens. With this approach it’s usually best to also override parentHierarchyChanged() depending on the order in which you set the look-and-feel and add the children.

If you do want to go with the setDefaultLookAndFeel() approach, then I would recommend calling it before you create any sort of UI. I.e. in juce::JUCEApplication::initialise(), or in juce::AudioProcessor::createEditor() depending on your project type. That way all your components can guarentee the correct look-and-feel will be available for their entire lifetime.

2 Likes

No need to call setDefault in this case.

Create your class:

CustomLookAndFeel : public LookAndFeel_V4
{
     ...
}

Create a class member in the editor:
CustomLookAndFeel customLookAndFeel;
In editor constructor:
setLookAndFeel(&customLookAndFeel);
In editor destructor:
setLookAndFeel(nullptr);

That still won’t resolve the issue of child components not having access to the required look-and-feel until after they’re added to the parent. It sounds like OP is wanting to access the look-and-feel in the constructor of the child components, which will be called before the parent’s constructor is called.

In general I would avoid trying to access the look-and-feel in a component’s constructor and instead use lookAndFeelChanged(), parentHierarchyChanged(), resized(), and/or paint() to access it.

1 Like

Your solution of calling the setDefault function in the processor works the best. I forgot the processor directly handles the editor, otherwise I would’ve gone straight to that.

In my specific use-case, I’m looking to store all my UI related constants in a custom LookAndFeel. In my Component constructors, I’m dynamic casting the result of getLookAndFeel() to obtain a convenient reference for the rest of the class. If there’s a more direct way of accomplishing this then let me know, but this solution does work.

1 Like

If you are super extra sure that all your components will only ever use one single instance of your custom LookAndFeel, then you can make it a singleton like this:

class CustomLookAndFeel
{
public:
    static CustomLookAndFeel* getInstance ()
    {
        static CustomLookAndFeel instance;
        return &instance;
    }

private:
    /* constructor made private to make sure that no other instances
    can be created */ 
    CustomLookAndFeel();
}

And at that point, you can call CustomLookAndFeel::getInstance() to obtain a pointer to it wherever you need it, both for setLookAndFeel() and setDefaultLookAndFeel(), and even in constructors of Components.

My final solution was making a custom component class that casts it to my CustomLookAndFeel in its constructor. This way my class methods get access to it automatically without manually casting it each time.

Sorry, just read this now. Did you try to call the callback lookAndFeelChanged() manually at the end of your constructor?

I think everything was resolved.