事件传递机制
eventfilter(事件过滤器也可以自己观察自己)
// 无论是true 或者 false 事件处理函数都需要手动调用,否则不进
B->installeventfilter(A); // A控制B
// 事件过滤器的参数类中需要实现eventfilter函数,A->eventfilter();
bool eventfilter(QObject*, QEvent*)
{
return true; // 不继续向父组件传递
return false; // 继续向父组件传递
return FU::eventfilter(..., ...); //使用父类的处理方式
}
多次进事件过滤的情况
// 会进三次第二层if
bool tabHistogram::eventFilter(QObject *watched, QEvent *event)
{
if(watched == ui->lineEdit_left || watched == ui->lineEdit_right ||
watched == ui->lineEdit_decomposel || watched == ui->lineEdit_decomposer) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
if(watched == ui->lineEdit_left) {
on_lineEdit_left_editingFinished();
} else if(watched == ui->lineEdit_right) {
on_lineEdit_right_editingFinished();
}else if(watched == ui->lineEdit_decomposel) {
on_lineEdit_decomposel_editingFinished();
} else if(watched == ui->lineEdit_decomposer) {
on_lineEdit_decomposer_editingFinished();
}
return true;
}
return QWidget::eventFilter(watched, event);
}
✅ 回车键会触发的几个常见事件(一次回车 ≠ 一个事件) 当你按一下回车(Enter)键时,Qt 会依次生成如下事件序列: | 事件类型 | 含义 | | ————————– | ——————— | | QEvent::KeyPress | 键盘按下(你监听的事件) | | QEvent::ShortcutOverride | 如果系统中定义了快捷键,先让它们有机会处理 | | QEvent::KeyRelease | 键盘释放 |
| 你看到的现象 | 原因说明 |
|---|---|
| 回车触发三次事件 | Qt 会发出多种事件(Press、Release) |
| eventFilter 进三次 | 是所有事件都经过 eventFilter |
| 判断条件只命中一次 | 只有 KeyPress 分支会触发处理逻辑 |
bool tabHistogram::eventFilter(QObject *watched, QEvent *event)
{
if(watched == ui->lineEdit_left || watched == ui->lineEdit_right ||
watched == ui->lineEdit_decomposel || watched == ui->lineEdit_decomposer) {
if (event->type() == QEvent::KeyPress) {
QKeyEvent* keyEvent = static_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter) {
if(watched == ui->lineEdit_left) {
on_lineEdit_left_editingFinished();
} else if(watched == ui->lineEdit_right) {
on_lineEdit_right_editingFinished();
}else if(watched == ui->lineEdit_decomposel) {
on_lineEdit_decomposel_editingFinished();
} else if(watched == ui->lineEdit_decomposer) {
on_lineEdit_decomposer_editingFinished();
}
return true;
}
}
}
return QWidget::eventFilter(watched, event);
}
专门的事件过滤类
class MyFilter : public QObject
{
Q_OBJECT
protected:
bool eventFilter(QObject* obj, QEvent* event) override
{
if (event->type() == QEvent::MouseButtonPress)
{
qDebug() << "Mouse press intercepted on object:" << obj;
return true; // 阻止事件继续传递
}
return QObject::eventFilter(obj, event); // 不拦截,继续传递
}
};
// 使用
MyFilter* filter = new MyFilter();
targetWidget->installEventFilter(filter);
事件循环机制
事件的传递顺序是 事件过滤器 ——> 事件分发 ——> 事件处理函数
事件过滤器中如果返回值是false,表示传递给对应的对象处理。如果返回的是true,表示不继续传递给其它事件过滤器,并且终止。最后调用父类的事件过滤函数。实际测试事件过滤器中也支持ignore和accept方法
事件分发 中需要调用事件处理函数才会走处理函数, 如果返回的是false, 表示继续传递给父组件, 如果返回的是true, 表示就此终止,函数末尾需要再调用父类的event方法。
事件处理函数是事件的最后一步。accept——不再继续向父组件发送;ignore——继续向父组件发送;事件处理函数默认是accept,QWidget的方法则默认是ignore.
QEvent中return的返回值是和notify()通信,而accept和ignore是和具体的事件函数通信。
QEvent的返回值是true表示用户自己处理这个事件。并且如果是event->ignore(),就算调用true,也会向父控件传递消息。如果是accept,就算是false,也会向父控件传递消息。其实ignore和accept最好只在事件处理函数中出现。
test:
控件A包含控件B,B包含控件C,C包含button D。A/B/C中有事件过滤器,事件分发器,都返回false。D中有event,返回false。点击D,分别打印,C事件过滤器,D事件分发器,B事件过滤器,C事件分发器,A事件过滤器,B事件分发器。
加入NativeEvent
┌──────────────┐
│ Win32事件(如WM_MOUSEMOVE) │
└──────────────┘
↓
┌──────────────┐
│ nativeEvent()│ ← 只有顶层窗口才会收到
└──────────────┘
↓
┌──────────────────────────┐
│ Qt 内部生成 QEvent 对象 │ ← 例如 QMouseEvent
└──────────────────────────┘
↓
┌──────────────┐
│ eventFilter()│ ← 安装者优先收到,能阻断传递
└──────────────┘
↓
┌────────────┐
│ event() │ ← 主处理函数
└────────────┘
↓
┌─────────────────────┐
│ mousePressEvent() 等 │ ← 特化处理函数
└─────────────────────┘