Slider attributes in getLookAndFeel() not set

Hi all,
I want to set the colours of the attributes of my sliders using getLookAndFeel(). I found out that some of the attributes are correctly set (namely thumbColourId and trackColourId) while others not (namely textBoxTextColourId, textBoxOutlineColourId, textBoxHighlightColourId).

Here my code in the PluginEditor.cpp

    void MySynthesizerAudioProcessorEditor::paint (Graphics& g)
{
    g.fillAll (getLookAndFeel().findColour (ResizableWindow::backgroundColourId));
    
    getLookAndFeel().setColour (Slider::thumbColourId, Colours::brown);
    getLookAndFeel().setColour (Slider::textBoxTextColourId, Colours::green);
    getLookAndFeel().setColour (Slider::textBoxHighlightColourId, Colours::yellow);
    getLookAndFeel().setColour (Slider::textBoxOutlineColourId, Colours::purple);
    getLookAndFeel().setColour (Slider::trackColourId, Colours::whitesmoke);
    
}

The only way I found to set the unset sliders’attributes is to set directly them where the sliders are created:

    FreqSlider.setColour (Slider::textBoxTextColourId, Colours::green);
    FreqSlider.setColour (Slider::textBoxHighlightColourId, Colours::yellow);
    FreqSlider.setColour (Slider::textBoxOutlineColourId, Colours::purple);
    
    
    FreqLabel.setText ("Freq", dontSendNotification);
    FreqLabel.attachToComponent (&FreqSlider, true);
    addAndMakeVisible (FreqLabel);
    FreqSlider.setTextValueSuffix (" Hz");
    addAndMakeVisible (FreqSlider);
    FreqAttachment.reset (new SliderAttachment (valueTreeState, "freq", FreqSlider));

Any idea about this strange behaviour?

The problem is, that the colour is used in a sub component of the slider, a Label named valueBox.
When you set the colour in the lookAndFeel, no update is triggered, but if you set it to the slider, it will trigger a colourChanged(), which triggers a lookAndFeelChanged().

If you call FreqSlider.lookAndFeelChanged() in your initial version, you should see the changes taking effect.

Btw, don’t set the colours in paint, just do it once in the constructor. Worst case such a change could trigger a repaint() leaving you in an infinite recursion…

Thanks a lot Daniel. So what am I supposed to do ultimately?
As I have various subcomponents of my GUI I would like to set the look and feel and let the other classes inherit it. As I said, for those attributes it works, for the ones related to valueBox not.
So how I can set globally the color of those attributes related to valueBox?

Thanks also for the tip of not using paint()

In your constructor you set the colours for your lookAndFeel, just as you did.
After that you can notify the component and all it’s children, that the lookAndFeel changed using sendLookAndFeelChange()

MySynthesizerAudioProcessorEditor::MySynthesizerAudioProcessorEditor (MySynthesizerAudioProcessor& proc) 
: /* ... */
{
    auto& lnf = getLookAndFeel();
    lnf.setColour (Slider::thumbColourId, Colours::brown);
    lnf.setColour (Slider::textBoxTextColourId, Colours::green);
    lnf.setColour (Slider::textBoxHighlightColourId, Colours::yellow);
    lnf.setColour (Slider::textBoxOutlineColourId, Colours::purple);
    lnf.setColour (Slider::trackColourId, Colours::whitesmoke);

    sendLookAndFeelChange();

    setSize (/* ... */);
}

EDIT @juce: shouldn’t the lookAndFeel changed be skipped for children, that use their own lookAndFeel?

shouldn’t it be something like:

const auto* myLookAndFeel = &getLookAndFeel();
for (int i = childComponentList.size(); --i >= 0;)
{
    auto* child = childComponentList.getUnchecked (i);
    if (&child->getLookAndFeel() == myLookAndFeel) 
        child->sendLookAndFeelChange();

Indeed the solution you proposed in the previous post does not work.

The one with sendLookAndFeelChanged() after the setColour calls?
It should actually, the addition was to remove the call from children, that don’t need it, because they have their own lookAndFeel…

Can you try to set a breakpoint in juce_Slider.cpp

void lookAndFeelChanged (LookAndFeel& lf)

and see if that is called? It is responsible for recreating your textBox, so that the colour settings are propagated…

I verified, yes it is called. Yet the texbox color is not changed, it gets the default color (white).

Did you ever find an answer to this? I’m having the same problem: I set all the colours in myLookAndFeel, call LookAndFeel::setDefaultLookAndFeel (&myLookAndFeel); in the editor constructor, and all the colours are set correctly except for textBoxOutlineColourId, which I have to force when adding my sliders, like so:

mySlider.setColour (Slider::textBoxOutlineColourId, findColour (Slider::textBoxOutlineColourId));

I don’t understand why this is necessary.

This is still a problem. However, another thing you can do is to call sendLookAndFeelChange() on the slider in your parent Component’s constructor after addAndMakeVisible(). Works for me…

i.e:

addAndMakeVisible(mySlider);
mySlider.sendLookAndFeelChange();
1 Like

Thanks stephenk. This also works for me if I call mySlider.sendLookAndFeelChange() after addAndMakeVisible(). Incidentally, I find there’s a similar problem with ShapeButton.

Thank you! I was banging my head against the wall about this unintuitive Slider behaviour. This sendLookAndFeelChange() kludge works.