Qt | 定时器实现动画效果时卡住了
环境: VS2017+Qt5.14
实现功能: 一个 QWidget 窗口,初始状态是隐藏的,在这个 QWidget 中有一个 QLabel, 在 QWidget 显示的同时,打开定时器,定时器时间间隔为 42ms,在定时器响应函数中执行 QLabel 上图片的定时切换,从而达到动画的效果。
具体实现: QWidget 执行 show()之后,立马打开定时器,在定时器的 timeout()中执行 ui.label->setPixmap(m_Pixmap[i]);
遇到的问题: show()函数执行完毕,定时器 start()执行完毕,但是定时器的响应函数迟迟不响应。有时可能等一两秒就可以反应过来,有时可能需要八九秒才可以反应过来,反应过来后,定时器正常运行,动画正常显示。或者在定时器不响应的时候,用鼠标在窗口上移动一下,定时器的响应函数就可以正常响应了。但是响应之前就像界面卡住了一样。
于是开始查找原因及解决办法,把所有相关代码注释掉后一点点放开,发现造成这种现象的原因就是因为调用 show()函数引起的。这就有点鸡肋了,如果是因为 show()函数引起的,说明是主线程在走 UI 的一些东西卡住了,这怎么解决?!
在网上查了很多种解释和方法,show()和 hide()函数确实会引起界面刷新,从而导致主线程卡住,如果是静态页面,一般不会有什么问题,但是如果是动态页面,就会出现程序卡住的现象。
解决办法: 一种方法是使用 stackWidget,调用 stackWidget 的 setCurrentIndex()实现页面的切换,避免使用 show()、hide()函数。我试过这种方法,但是因为我们的窗口样式和父子继承关系很复杂,所以 stackWidget 加入进来后,显示效果并不能达到我们的需求,所以放弃这种方法。
另一种方法是一个比较有局限性的方法,就是调用 Qt 的事件轮循机制。
在需要退出事件轮循的地方将 m_bExit = true;
调用事件轮循后,界面就不会出现卡死的现象了,因为在处理主进程的同时可以去处理其他的消息、事件。这样就实现了同时处理主进程和其他线程的事件,达到在线程中刷新界面的效果。
注:
因为我的这部分代码属于在 show()的同时操作界面,所以即使开线程,也需要在线程中发信号出来,执行相应操作,所以如果用线程+信号槽机制还是会卡死。
目前上面这种方法是我试过的效果最好的方法,但是他会有一个问题,就是如果在这个 while()循环执行期间退出程序,程序是退不掉的,需要手动调用 m_bExit = true,或者销毁资源的函数,先退出 while 循环,然后再执行程序的 close()才可以。
版权声明: 本文为 InfoQ 作者【YOLO.】的原创文章。
原文链接:【http://xie.infoq.cn/article/680331adff1c540f15f5be844】。未经作者许可,禁止转载。
评论