QT练习--子类计数--主界面lcd显示数据,同时可以暂停、重新开启计数

自己写了一个关于QThread的小练习,实现子类计数,发送信号给主界面,主界面进行显示计数,同时还可以实现计数的暂停、重新结束,点击关闭按钮进行关闭。
在这里插入图片描述

QThread使用继承QObject的方法实现的。doWork有两种实现形式,一种定时器,一种sleep方式,都可以。

对应的头文件

#ifndef MTTHREAD_H
#define MTTHREAD_H


#include <QObject>
#include <QTimer>
#include <QMutex>
#include <QMutexLocker>
//思路:新类继承于QObject  ,开启一个定时器,初始变量m_nTimer 依次增加,并发送主界面中,实现lcd 的显示
class mtThread : public QObject
{
    Q_OBJECT
public:
    explicit mtThread(QObject *parent = nullptr);
    void setFlag(bool isstop);//标记位
    int m_nTimer;//计数
    QMutex m_mutex;//互斥事件
    void lockFun();//加锁函数,
    void unlockFun();//解锁
    bool bpause;//暂停---线程是否处于上锁状态




signals:
    void readyResults(int nRes);//m_nTimer 每增加一个数,就给主程序发一次信号


public slots:
    void doWork();//对应于主程序中的槽函数 开始
    void stop();//结束
private:
    volatile bool isStop;//是否要结束
    QTimer *timer;
    int nInterval;//定时器间隔时常


};


#endif // MTTHREAD_H

对应的源文件




#include "mtthread.h"
#include <QDebug>
static int ncount = 0;


#include <QDateTime>
#include <QElapsedTimer>
#pragma execution_character_set("utf-8")
mtThread::mtThread(QObject *parent) : QObject(parent)
{
    isStop = true;
    m_nTimer = 0;


    nInterval = 500;
    timer = new QTimer(this);
    timer->start(nInterval);
    bpause = false;


}


//【有问题】暂停后重新开始,定时器变快了,而且相隔1毫秒响应两次或者多次timeout
//解决:上锁后先关闭定时器,解锁后重新打开定时器
void mtThread::doWork()
{
    connect(timer,&QTimer::timeout,this,[=](){
        m_mutex.lock();//暂停时,就运行到此处的上方。
        if(!isStop)
        {
            ncount++;
            m_nTimer = ncount;
            emit readyResults(m_nTimer);
            qDebug()<<"object:---dowork3: "<<m_nTimer<<"       "<<QDateTime::currentDateTime().toString("hh:mm:ss.zzz");


        }
        m_mutex.unlock();
    });
    //尝试添加第五个参数 ,  Qt::UniqueConnection 还是不行
}




void Sleep(int msec)
{
    QElapsedTimer t;
    t.start();
    while(t.elapsed()<msec);
}


//使用sleep的方式//第二种方法
//void mtThread::doWork()
//{
//    while (1) {
//        if(isStop)
//        {
//            break;
//        }


//        m_mutex.lock();
//        if(!isStop)
//        {
//            ncount++;
//            m_nTimer = ncount;
//            Sleep(500);
//            emit readyResults(m_nTimer);
//            qDebug()<<"object:---dowork: "<<m_nTimer<<"       "<<QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
//        }
//        m_mutex.unlock();
//    }
//}




void mtThread::setFlag(bool isst)
{
    isStop = isst;
    qDebug()<<"object:---setflag: "<<m_nTimer<<isst;
}


//
void mtThread::lockFun()//上锁---关闭定时器
{
    if(bpause)//加过锁之后,不要再加了,一层保护
    {
        return;
    }
    timer->stop();//先关闭定时器,然后再重新开启,这样定时器就对啦
    m_mutex.lock();
    bpause = true;
    qDebug()<<"object:---lockFun: "<<"   bpause = " <<bpause;
}


void mtThread::unlockFun()//已经解锁了或者处于未曾枷锁的过程中//解锁--重新开启定时器
{
    if(bpause == false)
    {
        return;
    }
    m_mutex.unlock();//还是放前面吧
    timer = new QTimer(this);
    timer->start(nInterval);
    bpause = false;
    //m_mutex.unlock();//好像放哪里都可以呢
    qDebug()<<"object:---unlockFun: "<<"   bpause = " <<bpause;
}


void mtThread::stop()
{
    qDebug()<<"object:---stop: "<<m_nTimer<<"   bpause = " <<bpause;


    //m_mutex.unlock();//有时候状态不对,强制解锁会造成程序崩溃的.如果已经解锁了,在此解锁会崩溃的。
     isStop = true;
//    if(bpause == true)//在暂停状态下//必须在发送sendStop信号之前进行解锁。如果用此处的话,则可能运行不到就卡死了,因为新线程杀掉了,而此处的新类还没释放掉
//    {
//        m_mutex.unlock();
//        qDebug()<<"object:- ??????????";
//    }
    if(timer->isActive())
    timer->stop();//结束定时器




}

主界面中头文件

#ifndef WIDGET_H
#define WIDGET_H


#include <QWidget>
#include <QThread>
#include "mtthread.h"
//#include <QMutexLocker>
namespace Ui {
class Widget;
}


class Widget : public QWidget
{
    Q_OBJECT


public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();
    void dealResult();
   // void showEvent(QShowEvent *e);


signals:
    void sendStop();


private slots:
    void on_opem_btn_clicked();


    void on_close_btn_clicked();


    void on_pushButton_2_clicked();


    void on_pushButton_clicked();


private:
    Ui::Widget *ui;
    QThread mythread;//新线程对象
    mtThread *mt;//新类指针
    bool isFirstClicked;
};


#endif // WIDGET_H

主界面中源文件

#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QTimer>
#include <QDebug>
#include <QDateTime>
#pragma execution_character_set("utf-8")
//extern QMutex m_mutex;
//哟有一个问题:即使不暂停的话,界面显示 不正常,有时候会少显示一点点,但总数是对的
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);


    mt = new mtThread();
    mt->moveToThread(&mythread);


    connect(&mythread,&QThread::finished,mt,&QObject::deleteLater);//新线程与新类//这个容易出错 槽函数写不对
    connect(ui->opem_btn,&QPushButton::clicked,mt,&mtThread::doWork);//widget与新类 点击按钮 开始 进行处理
    //connect(ui->close_btn,&QPushButton::clicked,mt,&mtThread::stop);//widget与新类  点击按钮 结束
    connect(this,&Widget::sendStop,mt,&mtThread::stop);


//    connect(mt,&mtThread::readyResults,this,[=](){
//        ui->lcdNumber->display(QString("%1").arg(mt->m_nTimer));
//        //this->update();//增加一个刷新//4还是显示不出来
//        //qApp->processEvents();//也不管用
//    });//新类与widget 交互信息,进行显示   新类中数据处理完后,显示在界面上//有问题,显示不实时,有漏数


    //下面能够实时显示计数,而且不漏。
    //直接读的emit信号传过来的数据,这样就可以实时显示拉。而上面那个方法是读取的新类中的全局变量,在lcd显示时,会漏掉一些。
    void (mtThread:: *psignal)(int res) = &mtThread::readyResults;
    connect(mt,psignal,this,[=](int res){
        ui->lcdNumber->display(QString("%1").arg(res));
        qDebug()<<"getresult:--- "<<QDateTime::currentDateTime().toString("hh:mm:ss.zzz");
    });//新类与widget 交互信息,进行显示   新类中数据处理完后,显示在界面上




    connect(ui->pushButton_2,&QPushButton::clicked,mt,&mtThread::doWork);//重新开始
    isFirstClicked = false;


//    //写一个定时器测试//界面不会漏 显示
//    QTimer *timer1 = new QTimer();
//    timer1->start(500);
//    static int ir = 0;
//    connect(timer1,&QTimer::timeout,this,[=](){
//        ui->lcdNumber->display(QString("%1").arg(ir));
//        qDebug()<<" ir = "<<ir;
//        ir++;
//    });
}
//https://blog.csdn.net/jiedesheng/article/details/79481496?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
//重写//QT的刷新机制,有时会不刷新的bug解决办法//也不管用
//void Widget::showEvent(QShowEvent *e)
//{
//    this->setAttribute(Qt::WA_Mapped);
//    QWidget::showEvent(e);
//}


Widget::~Widget()
{
    delete ui;
}


void Widget::on_opem_btn_clicked()
{


    if(mythread.isRunning())
    {
        qDebug()<<"widget中线程正在运行";
        return;
    }
    if(isFirstClicked == true)//非第一次点击
    {
        mt->m_nTimer = 0;//重新计数
        mt = new mtThread();
        mt->moveToThread(&mythread);
        qDebug()<<"关闭后重新打开";
    }
    if(isFirstClicked == false)
    {
        isFirstClicked = true;
    }
    mt->setFlag(false);
    mythread.start();


}


void Widget::on_close_btn_clicked()
{
    qDebug()<<"关闭按钮";
    if(mythread.isRunning())
    {
        qDebug()<<"isrunning?????";
        if(mt->bpause)//如果处于暂停状态,关闭时,要先解锁。如果不解锁,则程序会崩溃的
        {
           mt->unlockFun();//第二种方法 ;
        }


        emit sendStop();//由于是多线程,如果是暂停状态,则一定要先解锁,再去操作其他的,所以,上面那句,如果是中断的话,一定要先解锁才可以。
        mt->setFlag(true);
        qDebug()<<"新线程结束1";
        mythread.quit();//析构时,将新线程释放内存 ; 如果新线程在初始化时 new this了就不用此处析构拉
        qDebug()<<"新线程结束2";//入股没有上面的解锁,则会运行到此就卡死了。新线程结束了,而新类还在响应。。。
        mythread.wait();
        qDebug()<<"新线程结束";


    }
}




void Widget::on_pushButton_2_clicked()//继续写
{
    //mt->m_mutex.unlock();
    //QMutexLocker m_lock(&m_mtex);//可以用这个方法
    mt->unlockFun();//第二种方法
    qDebug()<<"解锁--重新开始计数";
}


void Widget::on_pushButton_clicked()
{
   // mt->m_mutex.lock();
    mt->lockFun();
    qDebug()<<"暂停,上锁";
}

其中出现的问题
1.重新计数后,定时器频率变了,变为原来好几倍。
解决办法:上锁时定时器关掉,解锁时重新启动
2.主界面不能实时显示计数
解决办法a: 界面显示时,读取子类传递过来的信号参数,而不是直接读取子类中的全局值。

自己写的程序,如果有什么错误,希望大家能够指出来,谢谢!!!

具体代码链接
https://download.csdn.net/download/u012719076/12228826

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值