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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步