如何让自定义QWidget接收所有按键事件,包括全局动作快捷键?
Qt自定义Widget捕获所有按键(含全局快捷键)问题
问题背景
在Qt 5环境下实现了自定义QWidget子类QMeow,按下任意按键可切换红/蓝背景色。同时在窗口中添加了QLineEdit和QMeow部件,并为窗口设置了快捷键为A的全局QAction。
自定义QMeow代码
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; };
窗口初始化代码
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();
异常现象
QLineEdit获焦时,可正常处理所有按键(包括A);QMeow获焦时,除A外的所有按键都能触发背景切换,A被全局QAction拦截。
需求:让QMeow的keyPressEvent()能捕获所有按键,与QLineEdit行为一致。
解决方案
方式一:关闭按键压缩属性
在QMeow的构造函数中添加属性设置,关闭Qt的按键压缩机制:
explicit QMeow() { this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); this->setFocusPolicy(Qt::StrongFocus); // 关闭按键压缩,让按键事件直接送达部件的keyPressEvent this->setAttribute(Qt::WA_KeyCompression, false); }
Qt::WA_KeyCompression属性默认开启,开启时Qt会优先将按键事件交给全局快捷键系统处理;关闭后,按键事件会直接发送给获焦部件的keyPressEvent(),与QLineEdit的默认行为一致。
方式二:重写event()方法优先处理按键事件
在QMeow类中重写event()方法,提前拦截并处理按键事件:
protected: bool event(QEvent *event) override { if (event->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event); keyPressEvent(keyEvent); // 标记事件已被处理,阻止后续传递给快捷键系统 event->accept(); return true; } return QWidget::event(event); }
此方法会在事件进入Qt的全局快捷键处理逻辑前,先将按键事件交给keyPressEvent()处理,随后标记事件已接受,避免被全局QAction拦截。
内容的提问来源于stack exchange,提问作者eepp
相关产品推荐
相关产品推荐

