Qt-标准事件类和自定义事件

一 事件简介

1. 事件(event)是在程序运行时由系统或用户操作触发的、需要应用程序响应的动作。例如:鼠标事件、键盘事件、定时器事件等。
2. 每一个 Qt 应用程序都对应一个唯一的 QApplication 应用程序对象,当执行 QApplication 应用程序对象的 exec()函数时,Qt 应用程序就进入了事件循环来监测应用程序的事件。Qt 中,子线程、主线程、Qt 应用程序、窗口程序、非窗口程序等都可以拥有自己的事件循环(exec())。
3. 启用事件循环的对象不会轻易结束自己的生命周期,Qt 中依赖事件循环的功能有很多,例如:定时器、跨线程使用信号槽(队列连接,connect的第4个参数传入:Queued Connection)等

二 Qt中事件的处理步骤

1. 当事件产生之后, Qt 应用程序对象通过调用 QApplication::notify() 函数将事件发送到指定的窗口。
2. 事件在发送过程中可以通过向对象(窗口、按钮等)安装事件过滤器 QObject::eventFilter() 来对事件进行过滤。Qt 应用程序默认不对任何产生的事件进行过滤。
3. 当事件发送到指定窗口之后,窗口的事件分发器 QWidget::event() 会对收到的事件进行分类和分发。
4. 事件处理器会对接收到的事件进行处理,每个事件处理器函数都对应唯一的事件,我们可以重写事件处理器函数来修改事件的默认处理动作。

三 事件类

1. QEvent

1.1 常用API

1.让窗口接收并以默认方式处理传递过来的事件,事件在当前窗口处理,不会向上层窗口(父窗口)传递。
void QEvent::accept();

2. 让窗口忽略传递过来的事件,事件没有在当前窗口处理,被传递给父窗口处理(向上传递)。
void QEvent::ignore();

3. 获取事件是否在本窗口以默认方式处理
//返回值:true - 表示事件已被标记为在本窗口处理;false - 表示事件应当传递给其他对象处理或被忽略。
bool QEvent::isAccepted() const;

4. 设置事件是否在本窗口以默认方式处理
//参数:true - 表示将事件设置为在本窗口处理;false - 表示将事件设置为传递给其他对象处理或忽略。
void QEvent::setAccepted(bool accepted);

5. 获取传递到窗口的事件类型
    5.1 定时器事件类型:QEvent::Timer
    5.2 关闭窗口事件类型:QEvent::Close
QEvent::Type QEvent::type() const;

1.2 发送事件的API

1. postEvent:将事件放入事件队列中后,无论事件是否处理完成,函数就立即返回。
//参数1:接收自定义事件的对象指针
//参数2:自定义事件的对象指针
//参数3:事件处理的优先级,默认 事件处理的优先级,默认为 Qt::NormalEventPriority
void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority)
2. sendEvent:直接将事件发送给接收对象,等待事件处理完成后函数才返回。
//参数1:接收自定义事件的对象指针
//参数2:自定义事件的对象指针
//返回值:true - 事件处理成功   false - 事件未被处理或处理失败
bool QObject::sendEvent(QObject *receiver, QEvent *event)

发送事件的注意事项【重要】

1. postEvent 发送的事件要在堆区创建。如果在栈上创建事件对象,一旦发送事件的 postEvent 函数返回,局部变量生命周期结束,如果事件处理稍后才执行,这将导致未定义行为。
2. 事件在堆区创建,使用 sendEvent 发送的事件对象,如果该函数没有额外保留对事件对象的引用(即没有改变事件对象的生命周期),Qt 框架通常会负责回收事件对象的内存。
3. 事件在堆区创建,无论是使用 postEvent 还是 sendEvent 发送事件对象,最好在事件处理完成后手动释放事件内存。
4. 发送事件和接收事件的对象都不能是子线程对象(QTheard),可以是下面几种对象:

    4.1 qApp 对象:
qApp->sendEvent(work, &CustEvent);

    4.2 QCoreApplication 对象静态成员函数:
    QCloseEvent cuEvent;
    QCoreApplication::sendEvent(this, &cuEvent);

    4.3 直接继承于 QObject 且移动到子线程对象中的子类对象。

    4.4 窗口对象。

    4.5 有事件循环且派生于 QObject 类的对象。

 1.3 代码示例

//重写键盘按下事件处理函数
void Widget::keyPressEvent(QKeyEvent *event)
{
    qDebug() << "键盘按下了按键:" << QChar(event->key()) << Qt::endl;
}

void Widget::on_pushButton_clicked()
{
    //键盘按下Q按键事件
    QKeyEvent pressEvent(QEvent::KeyPress, Qt::Key_Q, Qt::NoModifier);

    //设置焦点到控件上
    ui->textEdit->setFocus();

    //向窗口控件发送键盘Q按下事件
    //注意:窗口控件没有显示键盘按键的值
    qApp->sendEvent(ui->textEdit, &pressEvent);
}

2. 事件的子类

2.1 鼠标事件:QMouseEvent

2.2 键盘事件:QKeyEvent

2.3 窗口事件:QResizeEvent、QMoveEvent、QCloseEvent

2.4 绘制事件:QPaintEvent
        补充:手动触发绘图事件的方法
        2.4.1 执行 update(); 说明:调用该函数后,不会立即重绘,而是将重绘请求添加到事件队列中,在适当的时机调用 paintEvent() 函数进行重绘操作。多次连续调用 update() 可能只会导致一次 paintEvent() 调用,因为 Qt 会自动合并相邻的更新请求。
        2.4.2 repaint(); 说明:调用该函数后会立即调用 paintEvent() 函数进行重绘操作。

2.5 定时器事件:QTimerEvent

2.6 拖放事件:
 2.6.1 QDragEnterEvent:当一个拖放操作进入一个可以接收拖放事件的窗口小部件时触发
 2.6.2 QDragMoveEvent:当一个拖放操作在可接收拖放事件的窗口小部件内移动时触发
 2.6.3 QDragLeaveEvent:当一个拖放操作离开一个可接收拖放事件的窗口小部件时触发
 2.6.4 QDropEvent【重要】:当一个拖放操作最终在窗口小部件上释放鼠标按钮时触发,代表拖放操作完成

2.7 焦点事件:QFocusEvent

 四 自定义事件

1. 使用步骤

第一步 注册自定义事件ID
    1.1 方式1:取 QEvent::User 和 QEvent::MaxUser 之间的自定义值,例如:static QEvent::Type MyEvent = static_cast<QEvent::Type>(QEvent::User + 1);
    1.2 方式2:使用 QEvent::registerEventType()。例如:static QEvent::Type MyEvent = static_cast<QEvent::Type>(QEvent::registerEventType());

建议使用方式1,因为方式1 registerEventType()每执行一次,Id 就会+1,所以 registerEventType() 不能放到头文件中,因为头文件被引用多次,registerEventType()就会被执行多次。
 

第二步 创建派生于 QEvent 的自定义事件类,在自定义事件类中创建一个成员变量保存注册的自定义事件ID


第三步 发送自定义事件

    方式1:postEvent:将事件放入事件队列中后,无论事件是否处理完成,函数就立即返回。
    方式2:sendEvent:直接将事件发送给接收对象,等待事件处理完成后函数才返回。

第四步 接收自定义事件并进行处理
    方式1 可以给接收对象安装事件过滤器和重写事件过滤器函数来处理自定义事件。
    方式2 可以重写事件分发器函数来处理自定义事件。
    方式3 可以重写自定义事件处理函数 void QObject::customEvent(QEvent *event) 来处理自定义事件。

2. 举例:通过发送自定义事件实现线程通信

完整代码在绑定的资源中,审核通过后大家可以免费下载。


 

  • 10
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值