Getting TabbedButtonBar to appear in TabbedComponent

I’m following the Widgets demo runner code and trying to get a tabbed component, but can’t get it to work. As per the example code, I’ve inherited from TabbedComponent, then added some tabs in the constructor, but no tab bar appears. I’m sure it’s something really basic that I’m missing, but I’ve been trying for hours and can’t work out what :frowning: Here’s my constructor:

class CellArrayComponent : public TabbedComponent
{
    CellArrayComponent() : TabbedComponent(TabbedButtonBar::TabsAtTop)
    {
        addTab("array", Colours::azure, new CellArrayElement(), true);
        addTab("array2", Colours::azure, new CellArrayElement(), true);
        addAndMakeVisible(getTabbedButtonBar()); // tried this, though it didn't make any difference
    } 
};

Can anyone suggest what I might be doing wrong? I wondered if I needed to override paint() or resize(), though I don’t see this being done in the demo code.

Have you done addAndMakeVisible for the TabbedComponent in your parent component, as well set set the bounds of the TabbedComponent?

Yes.

See here for a working (simple) example:
https://github.com/tomto66/Topiary-Beatz/blob/master/Topiary%20Beatz/Source/TopiaryBeatsTabbedComponent.cpp

2 Likes

Finally figured it out–the CellArrayComponent class which inherits TabbedComponent was overriding paint() and resize(). I knew it was something simple! Thanks for the example @tomto66, it helped point me in the right direction.

1 Like

You’re very welcome :slight_smile:

Sorry, just reading this now:
There are several classes in JCUE, that don’t lend itself to inheritance, especially

  • Viewport
  • TabbedComponent
  • Slider

Generally the API follows the principle “Prefer aggregation over inheritance”.
If you want to customise JUCE, that is done via the LookAndFeel classes most of the times.

As you learned, if paint() or resized() is overriden, this is a good indicator. Unfortunately I don’t know a hard rule, which ones are ok to inherit, and which ones aren’t.

TabbedComponent has virtual methods, so there’s some use for inheritance, though…(There’s no other way to get notified of the tab selection changing than to inherit.)

While you can do that, it is not necessary. The Components managed by the TabbedComponent react quite well bu being hidden and shown when appropriate.

I have a new problem with tabs, this time with renaming them. I want each tab to be able to automatically rename itself, according to the content of its component. It needs to be able to do this even if it is out of focus.

But the naming methods seem to be quite restrictive. To use setTabName(), you need to know the index position of the tab you want to rename, but the Component stored by my tab doesn’t currently know its index number. I can use getCurrentTabIndex() to find the currently selected tabs, but this won’t help for tabs that are out of focus.

The only way I can think of doing it is to feed each new Component it’s index number when it is created and then updating it when it moved. This seems like quite a lot of work for a simple task, and I am wondering if there is a simpler way.

Ideally, I would like to do something like this:

setTabName( getTabIndex(componentWhichIsOwnedByTab), "new name");

but getTabIndex() doesn’t exist.

Any suggestions?

I still haven’t solved this part of the puzzle. Is there any way of renaming a tab without having to refer to its index number? I’ll have no trouble proceeding like this, but I’m hoping that there is a more elegant way.

General advice for hierarchical architecture is, that the more specialised should have to know as little as possible of the structures around. So it would be bad, if the component would manage the tabbed component, that contains it.

Instead write a little update function, that is triggered via change listeners.

void changeListenerCallback (ChangeBroadcaster* sender)
{
    for (int i=0; i < tab.getNumTabs(); ++i)
    {
        auto* comp = tab.getTabContentComponent (i);
        tab.setTabName (i, comp->getComponentName());
    }
}

Now make all your tabs you add a ChangeBroadcaster, add yourself as listener to them, and send a sendChangedMessage() once the component changed it’s name.

This will update all names (no problem with that), but you can even check, if comp == sender

1 Like