Qt学习记录—多线程的两种使用

只有一个线程去处理,会导致界面卡顿,无法处理用户的相关操作。使用多线程,可以提高效率。

线程可以分为两类:
1、创建一个线程类的子类,让其继承QT中的线程类 QThread,重写父类的 run() 方法,在该函数内部编写子线程要处理的具体的业务流程

//   .h
class MyThread_delay : public QThread
{
    Q_OBJECT

public:
    explicit MyThread_delay(QObject* parent = nullptr)
        :QThread(parent){
        


    };
    ~MyThread_delay() override{
        if (m_timer->isActive()) {
            m_timer->stop();
        }
        delete m_timer;
        if (check_timer->isActive()) {
            check_timer->stop();
        }
        delete check_timer;
        if (setzero_timer->isActive()) {
            setzero_timer->stop();
        }
        delete setzero_timer;
    };
    QTimer* m_timer; // Qt Timer
    QTimer* check_timer; // Qt Timer
    QTimer* setzero_timer; // Qt Timer

protected:
    void run() override{

        m_timer = new QTimer(this);
        m_timer->setSingleShot(false);
        connect(m_timer, &QTimer::timeout, this, &MyThread_delay::onTimerTimeout);
        m_timer->start(1000); // 以1秒为间隔触发定时器
        check_timer = new QTimer(this);
        check_timer->setSingleShot(false);
        connect(check_timer, &QTimer::timeout, this, &MyThread_delay::check_ue);
        check_timer->start(5000); // 以1秒为间隔触发定时器
        setzero_timer = new QTimer(this);
        setzero_timer->setSingleShot(false);
        connect(setzero_timer, &QTimer::timeout, this, &MyThread_delay::set_zero);
        setzero_timer->start(1500); // 以1秒为间隔触发定时器


        exec(); // 启动Qt事件循环,保持线程运行
    };
    void onTimerTimeout(){
        //实现功能
        // 定时器超时时,发送信号更新折线图
        emit updateGraph(list_id,delay_list,list_name); // 传递适当的值,作为折线图的数据
    }

    void check_ue(){
        //实现功能

    }
    void set_zero(){
               //实现功能

    }
signals:
    void updateGraph(QList<QString> ,QList<float>,QList<QString>); // 自定义信号,用于更新折线图

private:

    const int numRows =6;
    const int numColumns = 2;
    QSqlDatabase db; //数据库对象
    int id;
    QList<QString> list_id;
    QList<float>delay_list;
    QList<QString> list_name;
    QList<QString>list_real_id={"1","2","21","22","41","42"};
    QList<int> list_num={0,0,0,0,0,0};
    QList<QList<float>> list2_passvalue;
    QList<QList<int>> list2_count;

    int Max_slice_num=6;
};
// .cpp  主线程中


    m_thread_delay = new MyThread_delay;
//将当在线程中实现功能时   与通过信号槽的方式与主线程进行交互
    connect(m_thread_delay, SIGNAL(updateGraph(QList<QString>, QList<float>, QList<QString>)), this, SLOT(show_delay(QList<QString>, QList<float>, QList<QString>)));

    m_thread_delay->start();

缺点:当处理多个任务时,都需要写到run()函数中,这样该函数中的逻辑就会变得非常混乱,不容易维护

2、这种方式更加灵活,但是写起来会相对复杂一些
以下是一个接受视频数据流并显示在label里面的一个示例代码:
属于 QObject

//   .h文件
class DataReceiverThread : public QObject
{
    Q_OBJECT
public:
    explicit DataReceiverThread(int PORT, QObject *parent = nullptr)
        : QObject(parent), m_PORT(PORT)
    {
    }

public:
    void work()
    {

        m_clientSocket = new QTcpSocket(this);
        QObject::connect(m_clientSocket, &QTcpSocket::stateChanged, [=](QAbstractSocket::SocketState socketState) {

            if (socketState == QAbstractSocket::ConnectedState) {
                isConnect=true;

                qDebug() << "Connected to the server.";
            } else if (socketState == QAbstractSocket::UnconnectedState) {

                isConnect=false;
                m_clientSocket->abort(); // 中断当前连接
                if (m_clientSocket->state() == QAbstractSocket::ConnectedState) {
                    m_clientSocket->waitForDisconnected(); // 等待连接关闭完成
                }
                qDebug() <<"disConnected to the server.";
                QMetaObject::invokeMethod(this, [this]() {
                           m_clientSocket->connectToHost("192.168.31.XX", m_PORT); // 重新发起连接
                       }, Qt::QueuedConnection);
                m_clientSocket->connectToHost("192.168.31.XX", m_PORT); // 重新发起连接
                //当连接不上时发射信号  让主线程执行对应动作
                emit no_connect();

                // 重新启动接收数据的线程
            }
        });
        m_clientSocket->connectToHost("192.168.31.XX", m_PORT);
   QObject::connect(m_clientSocket, &QTcpSocket::readyRead, [=]() {

       if(isConnect){

        if (m_expectedSize == 0) {
            // 判断是否接收到了期望的帧大小数据
            if (m_clientSocket->bytesAvailable() < sizeof(quint32)) {
                return;
            }

            // 读取四个字节的帧大小数据
            QByteArray sizeData = m_clientSocket->read(sizeof(quint32));

            // 将网络字节顺序(大端序)的数据转换为主机字节顺序
            QDataStream sizeStream(sizeData);
            sizeStream.setByteOrder(QDataStream::BigEndian);
            sizeStream >> m_expectedSize;

            // 清空已接收的数据
            m_receivedData.clear();
            m_receivedData.reserve(m_expectedSize); // 预分配接收数据的大小
        }

        // 继续接收剩余数据
        m_receivedData.append(m_clientSocket->readAll());

        // 检查是否已接收到完整的一帧数据
        if (m_receivedData.size() >= m_expectedSize) {

            emit dataReceived(m_receivedData);
        }}}
   );
    }

public slots:
    void clearData(){
        m_receivedData.clear();
        m_expectedSize = 0;
        m_clientSocket->write("received");

    }
    void stopThread() {
            // 停止线程的运行
            m_stopThread = true;
            // 关闭套接字连接
            m_clientSocket->disconnectFromHost();
            qDebug()<<"destruction";
            // 将线程从事件循环中退出
            QCoreApplication::postEvent(this, new QEvent(QEvent::Quit));
       }
    void deleteObject() {
            delete this;
        }
signals:
    void dataReceived(const QByteArray& data);
    void no_connect();
private:
    QTcpSocket* m_clientSocket;
    int m_PORT;
    quint32 m_expectedSize=0;
    QByteArray m_receivedData;
    bool isConnect;
    bool m_stopThread;
    void stopConnection()
      {
          m_stopThread = true;
          m_clientSocket->disconnectFromHost();
          m_clientSocket->deleteLater();
          m_clientSocket = nullptr;
      }
};
//  .cpp文件
                DataReceiverThread* DreceiverThread = new DataReceiverThread(12101);
                QThread* receiverThread= new QThread();
//将工作的类对象移动到创建的子线程对象中
                DreceiverThread->moveToThread(receiverThread);
                QObject::connect(this, &Video_Status::stopThread, DreceiverThread, &DataReceiverThread::stopThread);
//线程中接完一帧数据后  发出信号dataReceived 后然后运行该匿名函数  显示在label中
                QObject::connect(DreceiverThread, &DataReceiverThread::dataReceived,this,[=](const QByteArray& data) {


                        QImage image;
                        image.loadFromData(data, "JPG");
                        // 在此处进行图像处理或显示
                        label_image[i][0]->setPixmap(QPixmap::fromImage(image));

                        emit over;
                });
//显示在label中后   发射信号over  与线程中的clearData连接 清除历史数据
                QObject::connect(this, &Video_Status::over, DreceiverThread, &DataReceiverThread::clearData);
//当没有数据是该类发射信号  然后主线程中显示无视频信号
                QObject::connect(DreceiverThread, &DataReceiverThread::no_connect, this,[=]() {
                    label_image[i][0]->setPalette(pe);
                    label_image[i][0]->setText("无视频信号");
                });
//将线程开始与定义的类的函数连接在一起  当线程开始时就运行该类中的work函数
                QObject::connect(receiverThread_, &QThread::started, DreceiverThread, &DataReceiverThread::work);
//开启线程
                receiverThread->start();

我这只是一个学习记录,具体的用法学习可以参考:Qt中多线程的使用 | 爱编程的大丙 (subingwen.cn)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值