Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Manage widget focus



  • I'm working on a C++ GUI. I use two QDial objects to control linear and angular velocity of a robot. Now I want to change the one Dial with up- and down-key, the other one with left- and right-key. How can I achieve that without having to use tab or mouseclicks to change the focus? I've tried to work with this function

    void MainWindow::keyPressEvent(QKeyEvent *event)
    {
        if(event->key() == Qt::Key_Up)
        {
            dial1->setFocus();
        }
        else if(event->key() == Qt::Key_Down)
        {
            dial1->setFocus();
        }
        else if(event->key() == Qt::Key_Left)
        {
             dial2->setFocus();
        }
        else if(event->key() == Qt::Key_Right)
        {
             dial2->setFocus();
        }
    }
    

    The Problem is, that the focus stays on the first widget focused. Do I have to set the focus back to the MainWindow after the keyboard input?
    Can someone suggest a clever way to solve this issue?

    Thanks a lot in advance!


  • Moderators

    @Agricola
    The following code increases/decreases the dial values no matter where the current focus is (as long as the mainwindow of course is active). The events are consumed for up/down/left/right keys and thus are not delivered to the target widget.
    Is this behavior what you want to achieve?

    qApp->installEventFilter( myFilter );
    ...
    bool MyFilter::eventFilter( QObject* watched, QEvent* event )
    {
        switch( event->type() )
        {
            case QEvent::KeyPress:
            {
                   QKeyEvent* ke = static_cast<QKeyEvent*>(event);
                   switch( ke->key() )
                   {
                          case Qt::Key_Up:
                                 dial1->triggerAction( QAbstractSlider::SliderSingleStepAdd );
                                 return true;
                          case Qt::Key_Down:
                                 dial1->triggerAction( QAbstractSlider::SliderSingleStepSub );
                                 return true;
                          case Qt::Key_Right:
                                 dial2->triggerAction( QAbstractSlider::SliderSingleStepAdd );
                                 return true;
                          case Qt::Key_Left:
                                 dial2->triggerAction( QAbstractSlider::SliderSingleStepSub );
                                 return true;
                   }
            }
        }
        return ParentClass::eventFilter( watched, event );
    }
    

    (untested)



  • @raven-worx
    Thanks a lot for the suggestion! I used your input to do some research in the docs as well but I somehow have problems making it work. Maybe you can have a look on what I've done so far?!

    I have added a new Class to my project that is derived from QObject and overrides the eventFilter()-Funktion.
    keypressfilter.cpp:

    #include "keypressfilter.h"
    
    KeyPressFilter::KeyPressFilter(QObject *parent) : QObject(parent)
    {
    
    }
    
    bool KeyPressFilter::eventFilter(QObject *obj, QEvent *event)
    {
        switch(event->type())
        {
            case QEvent::KeyPress:
            {
                QKeyEvent* ke = static_cast<QKeyEvent*>(event);
                switch(ke->key())
                {
                    case Qt::Key_Enter:
                        emit enterKeySig();
                        return true;
                    case Qt::Key_Up:
                        emit upKeySig();
                        return true;
                    case Qt::Key_Down:
                        emit downKeySig();
                        return true;
                    case Qt::Key_Left:
                        emit leftKeySig();
                        return true;
                    case Qt::Key_Right:
                        emit rightKeySig();
                        return true;
                }
            }
        }
        return QObject::eventFilter(obj, event);
    }
    

    I'm using Signals to make the changes to the dials in the MainWindow:
    mainwindow.cpp (excerpt):

    filter = new KeyPressFilter(this);
        connect(filter, SIGNAL(enterKeySig()), this, SLOT(enterKey()));
        connect(filter, SIGNAL(upKeySig()), this, SLOT(upKey()));
        connect(filter, SIGNAL(downKeySig()), this, SLOT(downKey()));
        connect(filter, SIGNAL(leftKeySig()), this, SLOT(leftKey()));
        connect(filter, SIGNAL(rightKeySig()), this, SLOT(rightKey()));
    

    The Slots to trigger the Dial:

    void MainWindow::upKey()
    {
        Dial->triggerAction(QAbstractSlider::SliderSingleStepAdd);
    }
    

    This way it doesn't seem to work; the Signals are not emitted.
    I've seen that it is possible to install the the filter in the App (that's what you did in your example as well right?), however I don't know how to convincingly call the Dials that way!?


  • Moderators

    @Agricola
    are you calling qApp->installEventFilter()?
    Also you are using the old connection style, which might fail at runtime - check the console output for errors.



  • @raven-worx
    Sorry if I wasn't specific enough. I solved the problem now; all I had to do was instantiating the filter and setting up the signal-slot-connections in the mainwindow.cpp and additionally (that's what I didn't grasp at first) calling

    app.installEventFilter(win->filter);
    

    in the main.cpp (win being the mainwindow object).

    Thanks a lot for your help!


Log in to reply