Hi!
I am using an ApplicationCommandManager to get keyboard shortcuts for switching between tabs in a TabbedComponent, which works fine for JUCE components. However, when I use a basic component generated by the Projucer in a tab the shortcuts don’t work when that tab is active. Simplified code demonstrating the issue below. What am I doing wrong here?
#pragma once
#include <JuceHeader.h>
class TestComponent
: public Component
{
public:
TestComponent() {}
~TestComponent() {}
void paint(Graphics& g) override
{
g.fillAll(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));
g.setColour(Colours::white);
g.setFont(24.0f);
g.drawText("TestComponent", getLocalBounds(), Justification::centred, true);
}
private:
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(TestComponent)
};
class MainComponent
: public Component
, public ApplicationCommandTarget
{
public:
enum KeyPressCommandID
{
nextTab = 1,
previousTab,
};
MainComponent()
{
textButton1.setButtonText("I am on tab 1");
textButton2.setButtonText("I am on tab 2");
// Tabbed component
auto& buttonBar = tabbedComponent.getTabbedButtonBar();
buttonBar.setColour(TabbedButtonBar::ColourIds::tabTextColourId, Colours::lightgrey);
buttonBar.setColour(TabbedButtonBar::ColourIds::frontTextColourId, Colours::white);
tabbedComponent.addTab("Button 1", Colours::black, &textButton1, false);
tabbedComponent.addTab("Button 2", Colours::black, &textButton2, false);
tabbedComponent.addTab("Component", Colours::black, &testComponent, false);
addAndMakeVisible(tabbedComponent);
// Command manager
commandManager.registerAllCommandsForTarget(this);
commandManager.setFirstCommandTarget(this);
auto tlc = getTopLevelComponent();
tlc->addKeyListener(commandManager.getKeyMappings());
Timer::callAfterDelay(300, [tlc] { tlc->grabKeyboardFocus(); });
setSize(600, 400);
}
~MainComponent() {}
void paint(Graphics& g) override
{
g.fillAll(getLookAndFeel().findColour(ResizableWindow::backgroundColourId));
}
void resized() override
{
tabbedComponent.setBounds(getBounds());
}
ApplicationCommandTarget* getNextCommandTarget() override
{
return nullptr;
}
void getAllCommands(Array<CommandID>& commands) override
{
commands.addArray({
KeyPressCommandID::nextTab,
KeyPressCommandID::previousTab, });
}
void getCommandInfo(CommandID commandID, ApplicationCommandInfo& result) override
{
switch (commandID)
{
case KeyPressCommandID::nextTab:
result.setInfo("Next tab", "Next tab", "Keyboard shortcut", 0);
result.addDefaultKeypress(KeyPress::tabKey,
ModifierKeys::ctrlModifier);
break;
case KeyPressCommandID::previousTab:
result.setInfo("Previous tab", "Previous tab", "Keyboard shortcut", 0);
result.addDefaultKeypress(KeyPress::tabKey,
ModifierKeys::ctrlModifier | ModifierKeys::shiftModifier);
break;
default:
break;
};
}
bool perform(const InvocationInfo& info) override
{
const auto currentTabIndex{ tabbedComponent.getCurrentTabIndex() };
const auto numTabs{ tabbedComponent.getNumTabs() };
int newTabIndex{ tabbedComponent.getCurrentTabIndex() };
switch (info.commandID)
{
case KeyPressCommandID::nextTab:
newTabIndex++;
newTabIndex = (newTabIndex >= numTabs) ? 0 : newTabIndex;
tabbedComponent.setCurrentTabIndex(newTabIndex);
break;
case KeyPressCommandID::previousTab:
newTabIndex--;
newTabIndex = (newTabIndex < 0) ? numTabs - 1 : newTabIndex;
tabbedComponent.setCurrentTabIndex(newTabIndex);
break;
default:
return false;
break;
}
return true;
}
private:
ApplicationCommandManager commandManager;
TabbedComponent tabbedComponent{ TabbedButtonBar::Orientation::TabsAtTop };
TextButton textButton1;
TextButton textButton2;
TestComponent testComponent;
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(MainComponent)
};
