In Qt 5, assume the following custom widget:
class QMeow final :
public QWidget
{
public:
explicit QMeow()
{
this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
this->setFocusPolicy(Qt::StrongFocus);
}
protected:
void keyPressEvent(QKeyEvent * const event) override
{
_s = !_s;
this->update();
QWidget::keyPressEvent(event);
}
void paintEvent(QPaintEvent *) override
{
QPainter painter {this};
painter.fillRect(this->rect(), QColor {_s ? "red" : "blue"});
}
private:
bool _s = false;
};
An instance of this widget changes its background color between red and blue when any key is pressed.
Now, let's make a window and add a QLineEdit as well as a QMeow, also setting an action with the shortcut key A:
QApplication app {argc, argv};
QWidget window;
QVBoxLayout layout {&window};
layout.addWidget(new QLineEdit);
layout.addWidget(new QMeow);
QAction action {"hello"};
action.setShortcut(Qt::Key_A);
window.addAction(&action);
window.show();
app.exec();
If you try this, you'll notice that:
- When the
QLineEditwidget has the focus, it handles all the keys, including lowercase A, adding it to its rendered text. - When the
QMeowwidget has the focus, it handles all the keys except lowercase A, suggesting that the action handles it instead.
How can QMeow::keyPressEvent() get called for any key, including action shortcuts, like QLineEdit?
I tried QWidget::grabKeyboard(), different focus policies, and looking at qlineedit.cpp without success.
Text input widgets in Qt normally use an internal "text control" which is used as a "proxy" for any text-related aspect, including keyboard input.
A focused widget always receives a special
ShortcutOverrideevent (a QKeyEvent) whenever it may trigger a shortcut valid for the current context.See the relevant documentation about
QEvent::ShortcutOverride:Similarly, the related section of the QKeyEvent docs:
This is exactly what text input widgets do: they override
event()(QLineEdit::event()) and sendShortcutOverrideevents to the internal text control object (QWidgetLineControl::processShortcutOverrideEvent()), which contains the following:Since standard alphanumeric keys are below
Qt::Key_Escape(0x01000000, and theQt::Keyenum mostly uses the standard ASCII numeration for them, with upper case for letters) this means that shortcuts using such keys are always accepted if they don't have modifiers, use Shift or are pressed within the numeric pad. The result is that they accept the shortcut, preventing propagation to parents, which will then be "converted" to a standardKeyPressand eventually sent to thekeyPressEvent()handler.The solution is then to override
event(), check forShortcutOverrideevents, and accept it (assuming you do want to accept such key press).