说明:
- 线程类 QSatelliteTrackThread
- 界面类 QSatelliteTreeWidget
- 在界面中通过【开始】【暂停】【继续】【停止】来控制线程的运行状态
- 线程的初始化与销毁是在界面中完成的
线程类
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函数里面进入具体的工作函数
构造函数
QSatelliteTrackThread::QSatelliteTrackThread()
{
m_cState = TRS_Begin;
pThreadTimer = nullptr;
}
- 设置初始状态
- 设置timer为空
run函数
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并解除自身的绑定
过程控制函数
#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,使其继续运行
具体做事情的函数
#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循环中才需要
界面类
开始
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函数
- 其他的被外部调用时,也都是在主线程中的
暂停与继续
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("暂停"));
}
}
结束
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应该也是可以满足条件的。但是这种方式都是在循环存在的时候成立,在没有循环的情况下,并不能立刻冻结或暂停一个线程。
期望的状态是,通过一个函数能够在任何时间,直接对线程自身的运行施以操控。
网友评论