How to be informed if a tabComponent is changed?

Hello,
I have a few tabComponent and i would like to put a password on one of them. For this, how to be informed if a specific tab has been selected by the user?
Thanks,
Frédéric.

https://docs.juce.com/develop/classTabbedComponent.html#acb0ec8ee87c29825f9326aadb8302b72

Does this do it? It’s labelled virtual so I thinkthe idea is to inherit and override it.

Ho, thank you very much, i didn’t saw it.

Alternatively the TabbedButtonBar is a ChangeBroadcaster, so you could do:

getTabbedButtonBar().addChangeListener (listener);

Is there a function like “onClick()” and a way to use a lambda function that is called when the button is clicked? (like for Button?)

Not built in, but you could create a wrapper:

struct ChangeLambda : private juce::ChangeListener
{
    explicit ChangeLambda (juce::ChangeBroadcaster& senderToUse)
      : sender (senderToUse)
    {
        sender.addChangeListener (this);
    }
    ~ChangeLambda() override
    {
        sender.removeChangeListener (this);
    }
    void changeListenerCallback (juce::ChangeBroadcaster*) override
    {
        if (onChange) onChange();
    }

    std::function<void()> onChange;

private:
    ChangeBroadcaster& sender;
};

juce::TabbedComponent tabbedComponent;
ChangeLambda tabConnection { tabbedComponent.getTabbedButtonBar() };

// and setup:
tabConnection.onChange = [this] { doSomething(); };

You can use it with any ChangeBroadcaster

Thank you, it seems very interesting, but since i don’t understand very well the c++ code here, i tried and the compilator says:
error: class ‘ChangeLambda’ does not have any field named ‘sender’
| : sender (senderToUse)
Something is missing?

Sorry, that was my bad. I decided on a different name for the member variable, but didn’t change it everywhere. I edited the code above.

Basically we store the ChangeBroadcaster reference, that way we can deregister ourselves as listener when we are destroyed.

There is no more error in compilation, but i tried with:

 void doSomething()
 {
 	cout<<"Hello"<<endl;
 }

and i see no message when i clic. Is there something else missing?

I copied the code in a playground and it works for me.
Maybe test, if the cout works at all?

I used DBG to test:

MainComponent::MainComponent()
{
    addAndMakeVisible(tabs);

    tabConnection.onChange = [this]
    {
        DBG ("Changed");
    };
    
    tabs.addTab("First", juce::Colours::darkblue, new juce::Slider(), true);
    tabs.addTab("Second", juce::Colours::darkblue, new juce::Slider(), true);
    tabs.addTab("Third", juce::Colours::darkblue, new juce::Slider(), true);
    tabs.addTab("Fourth", juce::Colours::darkblue, new juce::Slider(), true);

    setSize (600, 400);
}

void MainComponent::resized()
{
    tabs.setBounds(getLocalBounds());
}

// and those members:
    // Your private member variables go here...
    juce::TabbedComponent tabs { juce::TabbedButtonBar::TabsAtTop };
    ChangeLambda tabConnection { tabs.getTabbedButtonBar() };

Sorry for my previous message. It works very well. In my case i use a pointer juce::TabbedComponent *tab; instead of an object, so i declared tabConnection as a pointer too.
Thank you very much!
(This is very useful, but i have to understand exactly what this code means.)

Thanks for the correction, Daniel. Say, would this be a good place to use the Component Safe Pointer/Weak Reference classes? You deregister your ChangeLambda in the destructor, but isn’t it possible that the ‘this’ in the lamdba gets deleted?

The this pointer is always a problem. Here it is safe, because the struct owning the lambda is owned by the same this.
If the lambda was executed asynchronously then a SafePointer or WeakReference would indeed be required.

Btw, wasn’t meant as correction. The virtual method is also a good solution.

1 Like