Qt 事件传递流程-事件处理器|事件分发器|事件过滤器
(总体传递流程图见文章末尾)
自定义控件结构
自定义继承于QLabel的控件类 PropagateLabel.h
自定义窗口 PropagateWidget
在PropagateWidget中添加一个PropagateLabel标签
1 PropagateWidget::PropagateWidget(QWidget *parent) : 2 QWidget(parent) 3 { 4 QVBoxLayout* verticalLayout=new QVBoxLayout(this); 5 verticalLayout->setSpacing(0); 6 verticalLayout->setContentsMargins(0,0,0,0); 7 8 // 添加自定义标签PropagateLabel 9 lbl=new PropagateLabel(this); 10 // lbl->setText(QString::fromUtf8("Qt事件-总结")); 11 lbl->setFrameShape(QFrame::Box); 12 lbl->setFixedHeight(50); 13 lbl->setAlignment(Qt::AlignCenter); 14 lbl->setStyleSheet("background-color:blue;color:white;font-size:25px"); 15 16 verticalLayout->addWidget(lbl); 17 }
事件处理器-指定控件的指定事件
在自定义控件PropagateLabel中重写鼠标点击事件 mousePressEvent
1 void PropagateLabel::mousePressEvent(QMouseEvent *ev) 2 { 3 qDebug()<<"PropagateLabel::mousePressEvent"; 4 }
鼠标点击控件,检测到事件输出相应信息
在窗口PropagateWidget中重写 mousePressEvent
1 void PropagateWidget::mousePressEvent(QMouseEvent *event) 2 { 3 qDebug()<<"PropagateWidget::mousePressEvent"; 4 }
如果窗口检测到鼠标点击事件将会有相应输出
在自定义控件中设置事件接收状态为accept,则控件检测到事件之后不会传递给父控件(PropagateWidget),此时点击标签只有自定义控件的输出,即父控件检测不到事件
在自定义控件中设置事件接收状态为ignore,则控件检测到事件之后会传递给父控件(PropagateWidget),由输出可以看出,自定义控件先检测事件,然后传递给父控件,此时父控件能检测到事件
如果没有显式指定事件接收状态,则默认为accep,即省略ev->accept/ev->ignore,默认父控件检测不到事件
事件分发器-event
事件分发器在事件处理器之前获取事件
在自定义控件PropagateLabel中重写event
1 bool PropagateLabel::event(QEvent *e) 2 { 3 if (e->type()==QEvent::MouseButtonPress) // 指定需要检测的事件 4 { 5 qDebug()<<"PropagateLabel::event"; 6 } 7 return QLabel::event(e); // 返回 把事件传递下去 8 }
由输出顺序可知,event先检测到事件,然后传递给默认事件处理器
如果在if分支中return true,则只有event能检测到事件
如果return false,则事件不会再被控件的默认事件处理器检测到,直接传递给父控件
事件过滤器-eventFilter
在事件到达控件之前拦截事件
在窗口PropagateWidget中重写事件过滤器
1 bool PropagateWidget::eventFilter(QObject *watched, QEvent *event) 2 { 3 if (watched==lbl && event->type()==QEvent::MouseButtonPress) 4 { 5 qDebug()<<"PropagateWidget::eventFilter"; 6 } 7 return QWidget::eventFilter(watched,event); 8 }
在构造函数里为控件安装事件过滤器
lbl->installEventFilter(this);
输出顺序可以看到事件过滤器最早获取事件
最后一句 QWidget::eventFilter ,Qt里的定义为直接return false,即最后一句等价于直接写return false,事件会继续传递下去
在if分支里return true,则事件过滤器会拦截事件,不再传递下去
事件过滤器原理上是阻止某个控件截取事件,而不是令某个控件对事件做出反应
例如,控件A中有一个子控件B,我们希望控件A对事件X做出反应,但是在运行过程中发现事件X会被控件B截取,导致控件A获取不到事件,这时就可以给控件B安装事件过滤器,在事件X到达控件B之前截取,然后越过控件B传递给控件A
(总结)事件传递流程图