說明:
- 線程類 QSatelliteTrackThread
- 界面類 QSatelliteTreeWidget
- 在界面中通過【開始】【暫停】【繼續(xù)】【停止】來控制線程的運行狀態(tài)
- 線程的初始化與銷毀是在界面中完成的
線程類
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:衛(wèi)星]
void eventloopBreak();//打破時間循環(huán),以繼續(xù)或終止
public slots:
void on_featureCreated(int fId, int t);
void on_threadTimerWakeUp(); //執(zhí)行處理邏輯
protected:
virtual void run();
bool ContinueCtrl();//進度控制
private:
QTimer* m_pThreadTimer;
ThreadRunState m_cState;
};
- 需要繼承Qthread
- 需要支持外部設置狀態(tài),內(nèi)部進行狀態(tài)切換
- 能夠在run函數(shù)里面進入具體的工作函數(shù)
構(gòu)造函數(shù)
QSatelliteTrackThread::QSatelliteTrackThread()
{
m_cState = TRS_Begin;
pThreadTimer = nullptr;
}
- 設置初始狀態(tài)
- 設置timer為空
run函數(shù)
void QSatelliteTrackThread::run()
{
m_pThreadTimer = new QTimer;
m_pThreadTimer->setSingleShot(true);
connect(m_pThreadTimer, &QTimer::timeout, this, &QSatelliteTrackThread::on_threadTimerWakeUp,Qt::DirectConnection); //保證子程創(chuàng)建工作
connect(this, &QSatelliteTrackThread::featureCreated, this, &QSatelliteTrackThread::on_featureCreated, Qt::QueuedConnection);//保證主線程創(chuàng)建電磁特效
m_pThreadTimer->start();
exec();
delete m_pThreadTimer;
disconnect(this, &QSatelliteTrackThread::featureCreated, this, &QSatelliteTrackThread::on_featureCreated);
}
- 將timer實例化,綁定信號,使其能夠在線程中運行 [在線程中運行timer還需要線程啟用事件循環(huán)]
- 啟動timer,一旦超時,將會激活工作函數(shù)on_threadTimerWakeUp
- 啟動事件循環(huán)
- 事件循環(huán)結(jié)束后,銷毀timer并解除自身的綁定
過程控制函數(shù)
#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狀態(tài)的情況下,才需要使用eventloop阻塞線程的運行
- 相當于只要切換狀態(tài)的時候,自己發(fā)一個信號,就能打破loop,使其繼續(xù)運行
具體做事情的函數(shù)
#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;
}
}
- 在關(guān)鍵的位置,對狀態(tài)進行檢測,通常這種for循環(huán)中才需要
界面類
開始
void QSatelliteTreeWidget::on_pbPlay_clicked(bool checked)
{
//調(diào)整狀態(tài)
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();
}
- 設置按鈕狀態(tài)
- 實例化線程,線程對象是在主線程實例化的,出了他的run函數(shù)
- 其他的被外部調(diào)用時,也都是在主線程中的
暫停與繼續(xù)
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("繼續(xù)"));
}
else
{
m_pSatTrackThread->SetThreadRunState(QSatelliteTrackThread::TRS_Run);
ui.pbPause->setText(QString::fromLocal8Bit("暫停"));
}
}
結(jié)束
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函數(shù)里面exec后,quit才會生效
- 銷毀線程對象
QRunnable + QObject應該也是可以滿足條件的。但是這種方式都是在循環(huán)存在的時候成立,在沒有循環(huán)的情況下,并不能立刻凍結(jié)或暫停一個線程。
期望的狀態(tài)是,通過一個函數(shù)能夠在任何時間,直接對線程自身的運行施以操控。