Displaying the modified value of Label associated to a slider when the GUI loads

Hi all,
I am using the function textFromValueFunction to modify the text of a label associated to a slider. I can indeed change that text but only when the slider is actually moved, whereas I would like to have it changed already when the GUI is created. I am using this code:

class PanelFilter 
{
public:
    
    PanelFilter (AudioProcessorValueTreeState& valueTreeState)
    {
        filterSystemDecayLabel.setText ("System Decay", dontSendNotification);
        filterSystemDecayLabel.attachToComponent (&filterSystemDecaySlider, true);
        addAndMakeVisible (filterSystemDecayLabel);
        addAndMakeVisible (filterSystemDecaySlider);
        filterSystemDecayAttachment.reset (new SliderAttachment (valueTreeState, "system_decay_panel_filter", filterSystemDecaySlider));
        
		filterSystemDecaySlider.textFromValueFunction = [](float value)
        {
            float systemDecay = value / PluginConstants::scaleFactor;
            return juce::String(systemDecay);
        };
        
        filterSystemDecaySlider.valueFromTextFunction = [](const String &text)
        {
            float systemDecay = text.getFloatValue();
            return systemDecay * PluginConstants::scaleFactor;
        };
		
		
	}	

Note that the value that is displayed at the start of the GUI is the one I set here

AudioProcessorValueTreeState::ParameterLayout FilterSynthesizerAudioProcessor::createParameterLayoutPanelFilter1()
{

	auto SystemDecayFilter1Param = std::make_unique<AudioParameterFloat> ("system_decay_panel_filter1",// parameterID
                                                                  	"System Decay Filter1",             // parameter name
                                                                  	0.0f * PluginConstants::scaleFactor,       // minimum value
                                                                  	0.99999f * PluginConstants::scaleFactor,   // maximum value
                                                                  	0.9965f * PluginConstants::scaleFactor);   // default value
    
	

that is called in

FilterSynthesizerAudioProcessor::FilterSynthesizerAudioProcessor()
     : AudioProcessor (BusesProperties().withOutput ("Output", AudioChannelSet::stereo(), true)),
       parametersPanelFilter1 (*this, nullptr, Identifier ("ParametersPanelFilter1"), createParameterLayoutPanelFilter1())
{

    systemDecayParameterPanelFilter1 = parametersPanelFilter1.getRawParameterValue ("system_decay_panel_filter1");
}
	

Don’t set the textToValue and valueToText lambdas on the Slider. They are automatically set by the SliderAttachment from the parameter.
Use the approach I just answered here.

And maybe stay within one thread, if you have follow-up questions. It makes it hard to answer in the right thread and people have to read multiple threads…

I’ve been running into this problem and I was completely stumped why slider.textFromValueFunction apparently has bugs when using parameters and attachments.

The workaround @daniel provided to setup these number ↔ string lambas when you create the AudioParameter fixed the problem for me. :+1:

I have a suggestion: It would be really helpful if the docs for slider.textFromValueFunction and slider.valueFromTextFunction informed people to not use these lambdas if you are using parameters and attachments, and point them to the correct way to handle this situation.


That said, I also tried removing the attachment completely, and it appears slider.textFromValueFunction is never called initially, so if you aren’t using attachments in a standalone app, it still seems buggy when the GUI first loads. Is there a way to force it to apply the textFromValueFunction on the initial render when not using attachments? Or is it actually a bug?

For reference, when I was testing without attachments, I was doing stuff like this:

const juce::String OffText {"OFF"}; 

class TextFromValueBugEditor : public juce::AudioProcessorEditor
{
public:
    TextFromValueBugEditor(juce::AudioProcessor& p) : AudioProcessorEditor(&p)
    {
        slider.setRange(0, 100);
        slider.textFromValueFunction = [&](double value) { return value < 0.5 ? OffText : juce::String(value); };
        slider.valueFromTextFunction = [&](const juce::String& text) { return text == OffText ? 0.0 : text.getIntValue(); };
        addAndMakeVisible(slider);
        slider.setValue(0); // I thought this might help, but it doesn't
        setSize(400, 300);
    }
    
    ~TextFromValueBugEditor() override {}
    
    void resized() override {
        slider.setBounds(20, 20, getWidth() - 40, 100);
    }
    
    void paint(juce::Graphics& g) override
    { 
        g.fillAll(getLookAndFeel().findColour(juce::ResizableWindow::backgroundColourId));
    }
    
private:
    juce::Slider slider;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TextFromValueBugEditor)
};

By adding a DBG() to textFromValueFunction, I can see it is never called until I interact with the slider.

It probably would if it wasn’t the default value, because:

Try if setValue(1.0) fixes it, or any other value.

But even better is to call slider.updateText();

Thanks! Both of these fix that issue.

IIRC I tried slider.updateText() when I was using a SliderAttachment and I don’t think that was working (because my issue was I needed to set the lambdas on the Parameters). I forget to try it again with the non-attachment scenario.