提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
目录
前言
事件循环本质上就是一个无限循环,不停地去获取下一个事件,然后做出处理;直到 quit 事件发生,循环结束。
一、QEventLoop
其中exec是启动事件循环,调用exec以后,调用exec的函数就会被“阻塞”,直到EventLoop里面的while循环结束。
QEventLoop 即 Qt 中的事件循环类,其中 exec 是启动事件循环,调用 exec 以后,调用 exec 的函数就会被“阻塞”,直到 EventLoop 里面的while循环结束。
一般当主线程需要等待某个条件成立才能继续执行,如果不想卡主界面,就可以使用 QEventLoop 实现。
二、使用步骤
QEventLoop loop;//定义一个事件循环
QTimer::singleShot(2000, &loop, SLOT(quit()));//创建单次定时器,槽函数为事件循环的退出函数
loop.exec();//事件循环开始执行,程序会卡在这里,直到定时时间到,本循环被退出
三、 事件循环的嵌套及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);
}