Automatic keyboard focus on label editors


#1

Been researching this for a couple of days, still haven't found a solution - it's probably just an oversight. I realize many people have problems with keyboard focus, maybe because it's not really clear what components are supposed to have keyboard focus and what not?

 

Anyway, I have a component which contains a Label. This component is spawned by user input, the idea being that you click on some element and a box pops up where you enter a value with the keyboard. To get the workflow smooth, I want it such that this component, after construction and being viewable, automatically gives keyboard focus to the label editor. That is, user clicks -> box pops up instantly -> user enters value and hits enter -> box disappers, and value is set.

However, when the component is spawned, the editor doesn't grab the keyboard focus before you actually click on it (then it works as it should). In it's current state, it requires the user first to click on an item, then the label's textbox, and then do the editing.

Here's example code:

class LabelSpawner : public juce::Component
{
public:

    LabelSpawner(juce::String text = "example...")
    {
        setSize(100, 50);
        label.setText(text, NotificationType::sendNotification);
        label.setEditable(true);
        label.setBounds(0, 0, 100, 50);
        addAndMakeVisible(label);
    }

    void visibilityChanged() override
    {
        if(isVisible())
           label.showEditor(); // should show editor and grab keyboard focus
    }

private:
    juce::Label label;
};

According to the code of label.showEditor() it does attempt to grab keyboardfocus several times, adding manual calls to grabKeyboardFocus() doesn't help. Also, the grabbing of focus is done after the component is visible (as Jules suggests). I've tried so many variations, different places to add setWantsKeyboardFocus() and grabFocus().. nothing changes.

 

What is the general method / pitfalls for making this stuff work? To make matters worse, it should work in an audio plugin as well.


#2

I think you could change to another way:

just use TextEditor instead, and use setExplicitFocusOrder to grab the focus when the popupbox shows up (i guess the parent component of the label is a popup window?), and once user presses keys esc or enter then handle what you want eg hide the texteditor and show a label...

 


#3

test case here


class testWin : public TopLevelWindow, private ButtonListener
{
public:
    testWin()
        : TopLevelWindow("test", true)
    {
        setOpaque(true);
        centreWithSize(800, 600);
        
        setVisible(true);
        btn.setButtonText("abc");
        btn.setBounds(100, 100, 100, 90);
        btn.addListener(this);
        addAndMakeVisible(btn);
        
    }
    void paint(Graphics& g) override {
        g.fillAll(Colours::grey);
    }
private:
    class abc : public Component, private juce::KeyListener {
    public:
        abc()
        {
            setSize(200, 94);
            aaa = new TextEditor();
            aaa->setBounds(0, 0, 200, 94);
            aaa->setText("............aa");
            aaa->setExplicitFocusOrder(1);
            addAndMakeVisible(aaa);
            aaa->addKeyListener(this);
        }
        ScopedPointer<TextEditor> aaa;
        bool keyPressed(const KeyPress& key,
            Component* originatingComponent) override
        {
            if (key == VK_RETURN)
            {
                setVisible(false);
                return true;
            }
            return false;
        }
    };
    ScopedPointer<abc> txt;
    TextButton btn;
    void buttonClicked(Button*) override
    {
        txt = new abc;
        addAndMakeVisible(txt);
        txt->grabKeyboardFocus();
    }
};