美文网首页
通过QThread进行进度控制

通过QThread进行进度控制

作者: 雯饰太一 | 来源:发表于2023-07-17 12:40 被阅读0次

    说明:

    • 线程类 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应该也是可以满足条件的。但是这种方式都是在循环存在的时候成立,在没有循环的情况下,并不能立刻冻结或暂停一个线程。

    期望的状态是,通过一个函数能够在任何时间,直接对线程自身的运行施以操控。

    相关文章

      网友评论

          本文标题:通过QThread进行进度控制

          本文链接:https://www.haomeiwen.com/subject/zpfiydtx.html