事件传递模式
Qt 的事件传递遵循一定的模式,特别是在使用继承和父子对象体系时。主要有两种事件传递方式:
1直接事件传递:事件直接发送到目标对象。
2事件链传递(Event Chain):事件从目标对象传递到其父对象,直到被处理或达到顶层对象。
1 直接事件传递
直接事件传递是指事件被发送到指定的目标对象,并由该对象直接处理。例如,点击按钮时,事件直接发送到按钮对象。
发送事件的方式:
●同步发送:使用 QCoreApplication::sendEvent(QObject *receiver, QEvent *event)。事件被立即发送并处理,调用方等待处理完成。
●异步发送:使用 QCoreApplication::postEvent(QObject *receiver, QEvent *event)。事件被放入接收者的事件队列,等待事件循环处理。
这个稍后我们自定义事件的时候可以用一下,目前做个了解。
2 事件链传递
事件链传递是指事件在目标对象、其父对象及进一步的父对象中逐级传递,直到被处理或到达事件链的顶端。
事件链的传递顺序如下:
1事件过滤器:在事件传递到目标对象之前,事件可以被安装在目标对象或其父对象上的事件过滤器拦截和处理,事件过滤器之后讲解
2目标对象:首先尝试由目标对象处理事件。
3父对象:如果目标对象未处理事件,事件将被传递到其父对象,依此类推,直到顶层对象(通常是 QApplication)。
4默认处理:如果事件链上的所有对象都未处理事件,则事件最终会被系统的默认事件处理程序处理。
注意
要想让事件传递链生效,需要在目标对象的event处理函数里返回false,表示未处理完全,这样其父节点依次处理。
3 示例:事件链传递
我们定义一个ChildWidget继承自QLabel,重写paintEvent绘制区域,和event事件处理点击事件。
再定义一个ParentWiget,继承自QWidget,重写event事件处理点击事件
然后让ChildWidget成为ParentWidget的子部件
cpp
class ParentWidget : public QWidget
{
Q_OBJECT
public:
explicit ParentWidget(QWidget *parent = nullptr);
bool event(QEvent *event) override
{
if (event->type() == QEvent::MouseButtonPress) {
QMessageBox::information(this, "Parent Event", "Parent received mouse press event.");
//返回true不向上传递
return true;
}
//其他事件类型调用基类默认处理
return QWidget::event(event);
}
signals:
public slots:
};
class ChildWidget : public QLabel
{
public:
ChildWidget(const QString &text, QWidget *parent = nullptr) : QLabel(text, parent)
{
setAlignment(Qt::AlignCenter);
}
protected:
void paintEvent(QPaintEvent * event) override{
// 自定义绘图逻辑
QPainter painter(this);
// 设置背景颜色
//设置画笔
painter.setPen(QPen(Qt::red,2));
// 绘制与控件相同大小的矩形
painter.drawRect(rect());
// 调用基类的 paintEvent
QLabel::paintEvent(event);
}
bool event(QEvent *event) override
{
if (event->type() == QEvent::MouseButtonPress) {
QMessageBox::information(this, "Child Event", "Child received mouse press event.");
// 返回 false 以允许事件继续传递到父对象
return false;
}
return QLabel::event(event);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
ParentWidget parent;
parent.resize(300, 200);
ChildWidget *child = new ChildWidget("Click Me", &parent);
child->setGeometry(50, 50, 200, 100);
parent.show();
return a.exec();
}
在这个示例中,当用户点击标签(ChildWidget)时:
- 事件首先被发送到
ChildWidget。 ChildWidget的event方法处理事件,并弹出一个消息框。- 返回
false,表示事件未被完全处理,事件继续传递到其父对象ParentWidget。 ParentWidget的event方法接收同一个事件,并弹出另一个消息框。
如果将 ChildWidget::event 返回 true,事件将不会传递到 ParentWidget。
cpp
bool event(QEvent *event) override
{
if (event->type() == QEvent::MouseButtonPress) {
QMessageBox::information(this, "Child Event", "Child received mouse press event.");
// 返回 true 不允许事件继续传递到父对象
return true;
}
return QLabel::event(event);
}