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!
-
@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!? -
@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) callingapp.installEventFilter(win->filter);
in the main.cpp (win being the mainwindow object).
Thanks a lot for your help!