在 Qt 5 中,假设有以下自定义小部件:
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;
};
按下任意键时,此小部件的实例会在红色和蓝色之间更改其背景颜色。
现在,让我们创建一个窗口并添加一个
QLineEdit
以及一个QMeow
,同时使用快捷键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();
如果你尝试这个,你会注意到:
QLineEdit
小部件获得焦点时,它会处理所有键,包括小写字母 A,并将其添加到渲染的文本中。QMeow
小部件获得焦点时,它会处理所有键 除了小写 A 之外,表明操作会处理它。
QMeow::keyPressEvent()
)
QLineEdit
?我尝试了
QWidget::grabKeyboard()
,不同的重点政策,并查看
qlineedit.cpp
但没有成功。
只要聚焦的小部件可能触发对当前上下文有效的快捷方式,它总是会收到特殊的
ShortcutOverride
事件(QKeyEvent)。参见相关文档:
子级中的按键,用于覆盖快捷键处理(同样,QKeyEvent)。当快捷方式即将触发时,
ShortcutOverride
会发送到活动窗口。这允许客户端(例如小部件)通过接受事件来发出信号,表明它们将自行处理快捷方式。如果接受快捷方式覆盖,则事件将作为正常按键传递到焦点小部件。否则,它会触发快捷操作(如果存在)。
QKeyEvent文档的相关部分:
对于 QEvent::ShortcutOverride 接收者需要显式接受事件才能触发覆盖。对按键事件调用ignore()会将其传播到父窗口小部件。该事件沿着父窗口小部件链向上传播,直到窗口小部件接受它或事件过滤器消耗它。这正是文本输入小部件所做的:它们覆盖
event()
并将
ShortcutOverride
事件发送到内部文本控制对象,其中包含以下内容:
...
} else if (ke->modifiers() == Qt::NoModifier || ke->modifiers() == Qt::ShiftModifier
|| ke->modifiers() == Qt::KeypadModifier) {
if (ke->key() < Qt::Key_Escape) {
if (!isReadOnly())
ke->accept();
由于标准字母数字键低于 Qt::Key_Escape
(
0x01000000
),这意味着如果这些键没有修饰符、使用Shift 或在数字键盘内按下,则始终接受使用此类键的快捷键。结果是它们接受快捷方式,防止传播到父级,然后父级将被“转换”为标准
KeyPress
并最终发送到
keyPressEvent()
处理程序。解决方案是覆盖
event()
,检查
ShortcutOverride
事件并接受它(假设您do想要接受此类按键)。