一、界面线程与工作线程
GUI程序的主线程:
GUI的用户输入主要来自鼠标、键盘,称为事件。
处理事件的主循环,称为 事件循环。 这个用于处理各种界面的线程,称为 界面线程
GUI界面卡死
所有的事件处理函数(slots)都应该迅速返回,否则主界面会卡死
例如:鼠标点击一个按钮后,这个处理函数要尽快的返回。在它处理期间,界面是卡死的。(因为此函数处于事件循环中)
解决:把长时间的任务放到另一个线程(工作线程)中来完成,保持界面处于活动的状态。
二、定时器(Timer)
定时器用于实现定时操作,如:
每3秒钟自动保存一次
每500毫秒闪烁一次
每1秒刷新显示一次界面
使用方法:
1:重写virtual void timerEvent( QTimerEvent* event );
2:启动定时器,指定时间间隔(毫秒)
m_timerld = startTimer(500);
小练习:
实现一个文字时钟,显示系统当前时间
class Test8_1a_12_8 : public QMainWindow { Q_OBJECT public: Test8_1a_12_8(QWidget *parent = Q_NULLPTR); virtual void timerEvent(QTimerEvent* event); //重写该函数(继承自QObject) private: Ui::Test8_1a_12_8Class ui; int m_timerId; //每个Timer有一个id }; Test8_1a_12_8::Test8_1a_12_8(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); m_timerId = startTimer(500); } void Test8_1a_12_8::timerEvent(QTimerEvent* event) { //可以有多个定时器,每个定时器有不同的处理 if ( event->timerId() == m_timerId ) { QTime now = QTime::currentTime(); QString text = now.toString("HH:mm:ss"); ui.lineEditTime->setText(text); } }
效果:
关于定时器,要注意以下:
1、定时器并不是线程:定时器时间和普通鼠标、键盘事件一样,进入事件循环进行处理,因此,定时器的处理函数需要尽快完成,不然也会把界面卡死;
2、定时器不是精确的,因为它需要放在事件循环中处理,因此如果其他事件占用了较多的事件,会导致定时器不够精确
三、创建线程
在Qt里,线程相关的类:
QThread:线程
QMutex:互斥锁
QSemaphore:信号量
创建线程的方法:
1、派生一个线程类,继承自QThread,然后重写入口函数run()方法
启动:start()
回收:wait()
2、添加一些成员函数,用于查询任务的状态和进度
状态: int GetStatus(); 返回值: 1(已完成) 2(正在进行) 3(发生错误,已终止)
进度:int GetProgress(); 返回值: 0 ~ 100
创建工作线程:
工作线程就是一个普通的线程,区别于“界面线程”
当一个事件处理可能需要较长的时间,就创建一个线程来完成它,以免线程卡死。
步骤:
1、创建,并启动一个工作线程
2、显示一个进度条或等待对话框
3、启动一个定时器,定时查询工作线程的进度和状态,在其完成之后,填满进度条,结束等待
小练习:
模拟传送一个文件,显示任务进度
代码:
github:
https://github.com/HonestFox/Qt/tree/master/12_8FileTransferStatu