浮生愿,不曾解,我还有一些念,向桃花的尽头追~|

园龄:粉丝:关注:

QT 界面阻塞相关事项

Q1 界面阻塞与资源初始化

问题描述:在启动一个界面时,需要执行一个耗时的初始化的操作,如果像下面这种写法,则会导致主线程被阻塞。

int main(int argc, char* argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
w.InitData();//一个耗时的操作
return a.exec();
}

方法一、延迟执行InitData

使用

QTimer::singleShot(10, &w, SLOT(InitData()));

或者

QMetaObject::invokeMethod(&w, "InitData", Qt::QueuedConnection);

方法二、在操作过程中使用qApp->processEvents();

//InitData
for (size_t i = 0; i <= 100; i++) {
qApp->processEvents();
for (size_t j = 0; j < 100000000; j++) { }//delay <==> QThread::msleep(123);
}

上述方法的弊端在于,不管是使用哪种方式,InitData这个操作都是在UI线程中完成的,qApp->processEvents();可以让Qt在这个操作进行的过程中去处理事件,但是处理事件的效率受到这个delay的限制。如下图可以明显感受到进度条满了之后时间的刷新速度变快了。

考虑如下场景:

  • 界面中设置了一个label,并通过一个timer以10ms一次的间隔设置其文本为当前时间。
  • 界面中添加了一个进度条,并由InitData操作逐次修改进度值,其中InitData中的delay设置为1000ms。

经过测试,会出现如下情况:

  • InitData进行前,label每10ms刷新一次

  • InitData进行时,label刷新频率明显变慢

  • InitData结束后,label每10ms刷新一次

如何使得InitData的阻塞操作不影响UI线程,即label始终每10ms刷新一次?

方案三、使用线程来执行耗时操作

  • 将InitData操作放到线程中执行,通过信号的方式与主线程进行交互,需要注意的,这种情况下不可以在线程中初始化MainWindow的线程独占成员如socket、串口设备等。
void MainWindow::InitData(){
for (size_t i = 0; i <= 100; i++) {
emit setValue(i);
QThread::msleep(1000);
}
}
int main(int argc, char* argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
std::thread t(std::bind(&MainWindow::InitData, &w));//建议使用QT推荐的QThread写法
return a.exec();
}

当MainWindow的一部分资源初始化耗时较大时,在线程中处理对UI线程的影响较小,这种情况下,使用线程来修改MainWindow的成员是避免不了的一件事,最为稳妥的办法就是,在线程中计算出变量的最终值,然后触发信号来通知MainWindow进行变量的更新,否则就需要使用锁机制。

引申场景

异步请求

  • 考虑将请求过程放到线程空间,通过信号来控制发起请求和收到响应处理

本文作者:料峭春风吹酒醒

本文链接:https://www.cnblogs.com/pengpengda/p/17576389.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   料峭春风吹酒醒  阅读(345)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起