通过QThread进行进度控制
说明:
线程类 QSatelliteTrackThread
界面类 QSatelliteTreeWidget
在界面中通过【开始】【暂停】【继续】【停止】来控制线程的运行状态
线程的初始化与销毁是在界面中完成的
线程类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class QSatelliteTrackThread : public QThread
{
Q_OBJECT
public:
enum ThreadRunState
{
TRS_Begin ,
TRS_Run ,
TRS_Pause ,
TRS_Stop
};
QSatelliteTrackThread ();
virtual ~ QSatelliteTrackThread ();
void SetThreadRunState ( ThreadRunState s );
signals:
void featureCreated ( int fId , int t ); //传入动目标id,类型 [0:星下点 1:卫星]
void eventloopBreak (); //打破时间循环,以继续或终止
public slots :
void on_featureCreated ( int fId , int t );
void on_threadTimerWakeUp (); //执行处理逻辑
protected:
virtual void run ();
bool ContinueCtrl (); //进度控制
private:
QTimer * m_pThreadTimer ;
ThreadRunState m_cState ;
};
需要继承Qthread
需要支持外部设置状态,内部进行状态切换
能够在run函数里面进入具体的工作函数
构造函数
1
2
3
4
5
QSatelliteTrackThread :: QSatelliteTrackThread ()
{
m_cState = TRS_Begin ;
pThreadTimer = nullptr ;
}
run函数
1
2
3
4
5
6
7
8
9
10
11
void QSatelliteTrackThread :: run ()
{
m_pThreadTimer = new QTimer ;
m_pThreadTimer -> setSingleShot ( true );
connect ( m_pThreadTimer , & QTimer :: timeout , this , & QSatelliteTrackThread :: on_threadTimerWakeUp , Qt :: DirectConnection ); //保证子程创建工作
connect ( this , & QSatelliteTrackThread :: featureCreated , this , & QSatelliteTrackThread :: on_featureCreated , Qt :: QueuedConnection ); //保证主线程创建电磁特效
m_pThreadTimer -> start ();
exec ();
delete m_pThreadTimer ;
disconnect ( this , & QSatelliteTrackThread :: featureCreated , this , & QSatelliteTrackThread :: on_featureCreated );
}
将timer实例化,绑定信号,使其能够在线程中运行 [在线程中运行timer还需要线程启用事件循环]
启动timer,一旦超时,将会激活工作函数on_threadTimerWakeUp
启动事件循环
事件循环结束后,销毁timer并解除自身的绑定
过程控制函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <QEventLoop>
bool QSatelliteTrackThread :: ContinueCtrl ()
{
switch ( m_cState )
{
case QSatelliteTrackThread :: TRS_Begin :
return true ;
break ;
case QSatelliteTrackThread :: TRS_Run :
return true ;
break ;
case QSatelliteTrackThread :: TRS_Pause :
{
QEventLoop loop ;
connect ( this , & QSatelliteTrackThread :: eventloopBreak , & loop , & QEventLoop :: quit , Qt :: QueuedConnection );
loop . exec ();
return ! ( m_cState == TRS_Stop );
break ;
}
case QSatelliteTrackThread :: TRS_Stop :
return false ;
break ;
default:
break ;
}
return false ;
}
只有是pause状态的情况下,才需要使用eventloop阻塞线程的运行
相当于只要切换状态的时候,自己发一个信号,就能打破loop,使其继续运行
具体做事情的函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <QTimer>
void QSatelliteTrackThread :: on_threadTimerWakeUp ()
{
m_cState = TRS_Run ;
for ( qint64 t = m_dtStart ; t < m_dtEnd ; t += 1000 )
{
for ( int i = 0 ; i < m_vecSatellite . size (); i ++ )
{
if ( ! ContinueCtrl ()) break ;
//... do something
//Q_EMIT updateTrack(pSat);
msleep ( 10 );
}
if ( ! ContinueCtrl ()) break ;
}
}
在关键的位置,对状态进行检测,通常这种for循环中才需要
界面类
开始
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void QSatelliteTreeWidget :: on_pbPlay_clicked ( bool checked )
{
//调整状态
setPushbuttonEnableState ( ui . pbPlay , false );
setPushbuttonEnableState ( ui . pbPause , true );
setPushbuttonEnableState ( ui . pbStop , true );
ui . pbPause -> setText ( QString :: fromLocal8Bit ( "暂停" ));
if ( m_pSatTrackThread == nullptr )
{
m_pSatTrackThread = new QSatelliteTrackThread ();
}
m_pSatTrackThread -> start ();
}
设置按钮状态
实例化线程,线程对象是在主线程实例化的,出了他的run函数
其他的被外部调用时,也都是在主线程中的
暂停与继续
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void QSatelliteTreeWidget :: on_pbPause_clicked ( bool checked )
{
if ( ! m_pSatTrackThread ) return ;
QString text = ui . pbPause -> text ();
if ( text . compare ( QString :: fromLocal8Bit ( "暂停" )) == 0 )
{
m_pSatTrackThread -> SetThreadRunState ( QSatelliteTrackThread :: TRS_Pause );
ui . pbPause -> setText ( QString :: fromLocal8Bit ( "继续" ));
}
else
{
m_pSatTrackThread -> SetThreadRunState ( QSatelliteTrackThread :: TRS_Run );
ui . pbPause -> setText ( QString :: fromLocal8Bit ( "暂停" ));
}
}
结束
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void QSatelliteTreeWidget :: on_pbStop_clicked ( bool checked /*= false*/ )
{
if ( ! m_pSatTrackThread ) return ;
m_pSatTrackThread -> SetThreadRunState ( QSatelliteTrackThread :: TRS_Stop );
setPushbuttonEnableState ( ui . pbPlay , true );
setPushbuttonEnableState ( ui . pbPause , false );
setPushbuttonEnableState ( ui . pbStop , false );
ui . pbPause -> setText ( QString :: fromLocal8Bit ( "暂停" ));
m_pSatTrackThread -> quit ();
m_pSatTrackThread -> wait ();
delete m_pSatTrackThread ;
m_pSatTrackThread = nullptr ;
}
通过quit停止线程
通过wait等待线程finished
只有线程的run函数里面exec后,quit才会生效
销毁线程对象
QRunnable + QObject应该也是可以满足条件的。但是这种方式都是在循环存在的时候成立,在没有循环的情况下,并不能立刻冻结或暂停一个线程。
期望的状态是,通过一个函数能够在任何时间,直接对线程自身的运行施以操控。