setLookAndFeel (nullptr) triggers an assert failure in findColour ()


#1

Hi JUCErs,

As per the latest changes with clearing of the LookAndFeel (on switch to newer one or destruction of the PluginEditor), I am setting it to nullptr at the root of the components tree (currently that is the PluginEditor).

The issue I am having is within the calls to lookAndFeelChanged () method (triggered by the setLookAndFeel (nullptr) call) of child components that would be searching for a custom colour (defined in the now gone custom LookAndFeel).

Any guidelines on how to deal with this issue?

Basically, if I have custom colours (that aren’t defined in the default LookAndFeel), I would hit this assert in findColour () every time I reset the LookAndFeel. And I may need to reset it multiple times, during the lifetime of a PluginEditor, because that’s how I switch to different visual “themes”.

Cheers,
Nikolay


#2

hmm, that’s a little tricky. Can you not delete your GUI components before removing the L+F?


#3

Thanks for the response, Jules.

I guess you meant “can’t you delete your GUI components before removing the L+F?”?

If that was the question, then the answer is - No. I don’t only need to remove a L+F at destruction of the editor/app, I also need to switch to another L+F during the lifetime of the editor to switch between themes.

I posted a representative simplification of my scenario, here

The issue pops out at destruction time of the editor, but also on every selectTheme () call, in which components would not be getting the custom L+F and instead would be redirected to the default one .

Keeping a pool of L+F objects is also not an option:

  • currently, the assert from the topic I linked, would be hit when I delete the first item in the pool during destruction of the editor.

I think my only option is to dynamically cast and check which L+F I am using in lookAndFeelChanged ().


#4

Yes, that’d be an easy enough fix. I think there’s some kind of containsColour() method too that you could use.


#5

I think I tried this one, but (as it says in the documentation) it finds it only if set specifically for this component:

/** Returns true if the specified colour ID has been explicitly set for this
    component using the setColour() method.
*/
bool isColourSpecified (int colourId) const;

I think this will always return false for colours set directly in L+F constructor with setColour (). Can’t test it at the moment, but I believe I tested before posting.

Thank again, Jules.

Update:

  • But I may’ve tried it on the component instead of on the lookAndFeel object… When I get the chance I will try it again. Cheers!

#6

What if you tried to reset the new lnf BEFORE deleting the old one?
This is how I would write it:

void PluginEditor::selectTheme ()
{
    const String themeName = getThemeNameFromSomewhere ();
    ScopedPointer<LookAndFeel> newLookAndFeel;
    if (themeName == "X")
    {
        newLookAndFeel = new LookAndFeel_X ();
    }
    else
    {
        newLookAndFeel = new LookAndFeel_Y ();
    }

    if (newLookAndFeel) {
        setLookAndFeel (newLookAndFeel);
        lookAndFeel = newLookAndFeel.release();
    }
}

Hope that helps…


#7

This will trigger the assert from the linked topic. That was my approach before the addition of the assert in 5.2.


#8

I don’t understand how that’s happening:

In this scenario, during the method there is a time, when two lookAndFeel instances are present.
But there is never a time, when the Component has no LookAndFeel.
Handing over the ownership in lookAndFeel = newLookAndFeel.release(); is an atomic operation, and the old lookAndFeel is deleted afterwards…

If this is problematic, then I think the whole LookAndFeel mechanism should move on to a reference counted approach, otherwise this cannot work IMHO.