首页 > 其他分享 >Qt事件循环及QEventLoop的使用

Qt事件循环及QEventLoop的使用

时间:2023-11-07 11:35:14浏览次数:31  
标签:调用 Qt exec QEventLoop 循环 事件

目录

一、 介绍

  Qt作为一个跨平台的UI框架,其事件循环实现原理就是把不同平台的事件循环进行了封装,并提供统一的抽象接口,和Qt做了类似工作的还有glfw、SDL等等很多开源库。

二、QCoreApplication 主事件循环

  一般的Qt程序,main 函数中都有一个 QCoreApplication/QGuiApplication/QApplication ,并在末尾调用 exec 。

int main(int argc, char *argv[]) {
    QCoreApplication app(argc, argv);		    // 或者QGuiApplication, 或者 QApplication
    // TODO ...
    return app.exec();
}

  Application类中,除去启动参数、版本等相关东西后,关键就是维护了一个QEventLoop,Application的 exec 就是 QEventLoop 的 exec 。Application 中的这个 EventLoop 称作主事件循环Main EventLoop。所有的事件分发、事件处理都从这里开始。Application 还提供了 sendEvent 和 poseEvent 两个发出事件的函数。sendEvent发出的事件会立即被处理,也就是“同步”执行。postEvent发送的事件会被加入事件队列,在下一轮事件循环时才处理,也就是“异步”执行。还有一个特殊的sendPostedEvents,是将已经加入队列中的准备异步执行的事件立即同步执行。

三、事件循环的开启

例一

  一般的事件循环都是由exec()来开启的,列如

QCoreApplicaton::exec();
QApplication::exec();
QDialog::exec();
QThread::exec();
QDrag::exec();
QMenu::exec();

  这些都开启了事件循环,事件循环首先是一个无限“循环”,程序在exec()里面无限循环,能让跟在exec()后面的代码得不到运行机会,直至程序从exec()跳出。从exec()跳出时,事件循环即被终止。QEventLoop::quit()能够终止事件循环。事件循环实际上类似于一个事件队列,对列入的事件依次的进行处理,当事件做完而事件循环仍然没有结束的时候,此时事件循环就类似于一个不占用CPU时间的的for(;;)循环。其本质实际上是以队列的方式来重新分配时间片。

例二

1 main()  
2 QApplication::exec()  
3 [...]  
4 QWidget::event(QEvent *)  
5 Button::mousePressEvent(QMouseEvent *)  
6 Button::clicked()  
7 [...]  
8 Worker::doWork()  

  在main()中通过调用QApplication::exec() (如上段代码第2行所示)开启了事件循环。视窗管理者发送了鼠标点击事件,该事件被Qt内核捕获,并转换成QMouseEvent ,随后通过QApplication::notify() (notify并没有在上述代码里显示)发送到我们的widget的event()方法中(第4行)。因为Button并没有重载event(),它的基类QWidget方法得以调用。 QWidget::event() 检测出传入的事件是一个鼠标点击,并调用其专有的事件处理器,即Button::mousePressEvent() (第5行)。我们重载了 mousePressEvent方法,并发射了Button::clicked()信号(第6行),该信号激活了我们worker对象中十分耗时的Worker::doWork()槽(第8行)。

四、父子事件传递

  如果子widget没有accept或ignore该事件,则该事件会被传递给其父窗口。那么:对于一个继承而来的类,只要我们重写实现了其各个事件处理函数,则对应的事件肯定无法传递给其父widget! 哪怕重写的该事件处理函数的函数体为空!如果是标准的控件对象,则其肯定没重写各个事件处理函数。那消息能不能传递到父widget中,则取决于中途有没有使用事件过滤器等将该信号拦截下来了。

  例如:

  在一个QWidget上建了一个QLabel。而后实现父QWidget的mousePressEvent(), 然后跟一下发现:当我click这个label时:居然能进入到父QWidget的mousePressEvent()中,但是如果把子改成QPushButton则进入不了。

  (1)对于QLabel: 如果不重写mouse处理函数,也没有设置事件过滤器等操作的话,则相当于:其对mouse这个事件一直没有进行处理,那没有进行处理的话,相当于上边所说的情况,此时该事件会被传递给其parent。

  (2)而对于QPushButton而言:当click它时:其会发射clicked()信号,其实这就相当于它对该事件的一个operator过程。所以:这里它accept该事件并进行了对应处理。从而:无法传递给其父窗口。

五、processEvents

  我们的UI界面,要持续不断地刷新(对于QWidget就是触发paintEvent事件),以保证显示流畅、能及时响应用户输入。一般要有一个良好的帧率,比如每秒刷新60帧, 即经常说的FPS 60, 换算一下 1000 ms/ 60 ≈ 16 ms,也就是每隔16毫秒刷新一次。但有时候又需要做一些复杂的计算,这些计算的耗时远远超过了16毫秒。在没有计算完成之前,函数不会退出(相当于阻塞),事件循环得不到及时处理,就会发生UI卡住的现象。这种场景下,就可以使用Qt为我们提供的接口,立即处理一次事件循环,来保证UI的流畅。

// 耗时操作
doWork1();

// 适当的位置,插入一个processEvents,保证事件循环被处理
QCoreApplication::processEvents();

// 耗时操作
doWork2();

六、QEventLoop类

  QEventLoop即Qt中的事件循环类,主要接口如下:

int exec(QEventLoop::ProcessEventsFlags flags = AllEvents);
void exit(int returnCode = 0);
bool isRunning() const;
bool processEvents(QEventLoop::ProcessEventsFlags flags = AllEvents);
void processEvents(QEventLoop::ProcessEventsFlags flags, int maxTime);
void wakeUp();

其中exec是启动事件循环,调用exec以后,调用exec的函数就会被“阻塞”,直到EventLoop里面的while循环结束。

七、事件循环的嵌套及QEventLoop模拟同步调用

  事件循环是可以嵌套的,当在子事件循环中的时候,父事件循环中的事件实际上处于中断状态,当子循环跳出exec之后才可以执行父循环中的事件。当然,这不代表在执行子循环的时候,类似父循环中的界面响应会被中断,因为往往子循环中也会有父循环的大部分事件,执行QMessageBox::exec(),QEventLoop::exec()的时候,虽然这些exec()打断了main()中的QApplication::exec(),但是由于GUI界面的响应已经被包含到子循环中了,所以GUI界面依然能够得到响应。如果某个子事件循环仍然有效,但其父循环被强制跳出,此时父循环不会立即执行跳出,而是等待子事件循环跳出后,父循环才会跳出。

1、同步获取数据

  经常会有这种场景: “触发 ”了某项操作,必须等该操作完成后才能进行“ 下一步 ”。比如:数据获取,向服务器发起登录请求后,必须等收到服务器返回的数据,才决定下一步如何执行。这种场景,如果设计成异步调用,直接用Qt的信号/槽即可,如果要设计成同步调用,就可以使用本地QEventLoop。

void A::onFinish(bool r, const QString &info) {
    m_result = r;
    qDebug() << info;
    // 槽中退出事件循环 
    loop.quit(); 
};
 
bool A::get(const QString &userName, const QString &passwdHash, const QString &dataName) { 
    // 声明本地EventLoop QEventLoop loop;
    m_result = false; 
    // 先连接好信号 
    connect(&network, SIGNAL(finished(bool,const QString &)),this,SLOT(onFinish(bool,const QString &)));
    // 发起登录请求 
    getData(userName, passwdHash, dataName); 
    // 启动事件循环。阻塞当前函数调用,但是事件循环还能运行。 
    // 这里不会再往下运行,直到前面的槽中,调用loop.quit之后,才会继续往下走
    loop.exec();
    // 返回result。loop退出之前,m_result中的值已经被更新了。
    return m_result;
}

2、主线程等待

  比如想要将主线程等待100ms,总不能使用sleep吧,那样会导致GUI界面停止响应的,但是用事件循环就可以避免这一点:

QEventLoop loop;
QTimer::singleShot(100, &loop, SLOT(quit()));
loop.exec();

3、对话框弹出

void A::Show() {
    QDialog dlg;
    dlg.show();
    QEventLoop loop;
    connect(&dlg, SIGNAL(finished(int)), &loop, SLOT(quit()));
    loop.exec(QEventLoop::ExcludeUserInputEvents);
}

原文:https://blog.csdn.net/kupepoem/article/details/121844578

标签:调用,Qt,exec,QEventLoop,循环,事件
From: https://www.cnblogs.com/hhddd-1024/p/17814636.html

相关文章

  • bat里循环1万次测试时间
    bat里循环1万次测试时间  @echooff@echostart:%time%set/ai=0:LoopStartset/ai+=1if%i%leq10000gotoLoopStart@echoend:%time% 自己的电脑,循环1万次要7,8秒    公司服务器的电脑,循环一万次要5秒  买的华为云服务器1核心2G内......
  • QT代码实现将图片镜像翻转效果
    QT代码实现将图片镜像翻转效果将图片原图和镜像图合并输出,实现图片镜像功能快速显示效果在UI拖入一个QPushButton,一个QLabel用于缩放显示效果voidWidget::on_pushButton_clicked(){QStringpath=QDir::currentPath();//ui->m_fileEdit->setText(path);//打......
  • pyqt5-QScrollBar
    1、介绍这是一个进度条组件,两侧点击可以加减。 setMinimum(self,a0:int)设置最小值,可以是负值setMaximum(self,a0:int)设置最大值,可以是超过100设置浮点数时,保留其整数部分value(self)->int返回进度条的数值,int类型。默认时最小为0,最大为99。两侧点击,加减的......
  • qt 登录
    Qt设计精美的登录注册界面(包含SQLite数据库应用)_c++_桃豆豆-腾讯云开发者社区(csdn.net)......
  • 关于嵌入式QT QML 竖屏屏幕显示为横屏
    硬件平台:全志的A40I-H(从淘宝一家广州卖家买的开发板)软件平台:Linux内核版本3.10.65QT版本:5.9.0当时遇到的问题,在PC上运行一个qml的demo,是正常的横屏显示的。但是交叉编译过后,烧录到开发板子上面,发现是旋转了90度显示大致如下图所示: 当时非常的头大,如果按照文档上面,使用QT......
  • (八)C#编程基础复习——for循环
    在某些情况下,我们可能需要重复执行某些代码,这时就需要用到C#中的循环语句,C#中支持for循环、foreach循环、while循环和dowhile循环等循环语句,使用for循环可以重复一部分代码,而且重复的次数是可以设定的,流程如下:代码示例:for(inti=1;i<=9;i++){Console.Write......
  • 大二算法实验一用循环链表解决约瑟夫环
    题目约瑟夫(Joeph)问题的一种描述是:编号为1,2,…,n的n个人按顺时针方向围坐一圈,每人持有一个密码(正整数)。一开始任选一个正整数作为报数上限值m,从第一个人开始按顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的密码作为新的m值,从他在顺时针方向上的......
  • 实验二 C语言分支与循环基础应用
    1.实验11#include<stdio.h>2#include<stdlib.h>3#include<time.h>45#defineN56#defineN13747#defineN246589intmain()10{11intnumber;12inti;1314srand(time(0));1516for(i=......
  • QT 应用程序打包
    一、简述在Windows环境将应用程序打包成一个exe应用,以便给没有Qt环境的用户使用。打包工具:Windows使用windeployqt,Ubuntu使用linuxdeployqt(linuxdeployqtxxx可执行文件-appimage)。步骤:使用windeployqt将exe所依赖的库文件找出来,然后使用EnigmaVirtualBox将......
  • QtCreator 格式化代码
    目录Beautifier插件介绍配置Beautifier步骤1、使用ArtisiticStyle2、使用Clang-format3、使用uncrustify参考Beautifier插件介绍QtCreator本身默认支持代码格式化,具体格式化快捷键为:Ctrl+i。可以选择部分或全部选择后执行Ctrl+i操作完成代码格式化。但只限于缩进......