Qt多线程之继承QObject(moveToThread方式)

Qt多线程有两两种方式,第一种继承QThread,复写run()函数,但是run()和main()类似,run()函数才是子线程的入口函数,所以在设计到类的操作时,必须把对象或者指针放在run函数里面,否则就不在一个线程里面了,会出现错误。

第二种方式,继承QObject,通过moveToThread()将自定义的线程添加到子线程QThread里,然后信号槽的方式实现,shix实现主线程和子线程的交互。

本文只为给自己学习QT多线程做个笔记。本文使用第二种方式,Qt官方主推的方式。

注意:

继承QObject,调用moveToThread方法用的时候要强调的几个重点:
自定义的MyThread线程类的对象在创建时不能指定父对象!
启动子线程后,并没有启动子线程处理函数;
启动子线程处理函数必须用signal-slot方式!!!
在线程处理函数内部,绝对不允许操作ui图形界面(比如跳个弹窗等等),线程内部通常是纯数据处理!

 

 

线程退出:

线程在使用时,需要判断线程的状态。isRunning()。

thread->quit();//退出线程,会等待线程执行完毕。

thread->wait();//回收资源

子线程是while(1)一般使用设置标志位来实现线程的退出。

myThread->setFlag(true);

 

 

代码如下:

1.pro文件

#-------------------------------------------------
#
# Project created by QtCreator 2019-10-29T14:52:07
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = ThreadUI2
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

CONFIG += c++11

SOURCES += \
        main.cpp \
        widget.cpp \
    mythread.cpp

HEADERS += \
        widget.h \
    mythread.h

FORMS += \
        widget.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

2.mythread.h文件

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>

class MyThread : public QObject
{
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);
    ~MyThread();
    //线程处理函数
    void MyTimeout();
    void setFlag(bool flag = true);

signals:
    void mySignal();//定义一个信号,在该子线程中每秒发射一次该信号

private:
    bool isStop;
public slots:
};

#endif // MYTHREAD_H

3.mythread.h文件

#include "mythread.h"
#include<QThread>
#include<QtDebug>
MyThread::MyThread(QObject *parent) : QObject(parent)
{
    isStop=false;
}

MyThread::~MyThread()
{

}

void MyThread::MyTimeout()
{
    while(isStop==false)
    {
        QThread::sleep(1);
        emit mySignal();
        qDebug()<<"sub thread :"<<QThread::currentThread();
        if(true==isStop)
        {
            break;
        }
    }
}

void MyThread::setFlag(bool flag)
{
    isStop=flag;
}

4.widget.h文件

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include"mythread.h"
#include<QThread>

namespace Ui {
class Widget;
}

class Widget : public QWidget
{
    Q_OBJECT

public:
    explicit Widget(QWidget *parent = nullptr);
    ~Widget();

signals:
    void startThread();//启动子线程的信号


private slots:
    void on_pushButtonStart_clicked();

    void on_pushButtonStop_clicked();
    void dealSignal();
    void dealClose();

private:
    Ui::Widget *ui;
    MyThread *myT;
    QThread *thread;
};

#endif // WIDGET_H

5.widget.cpp文件

#include "widget.h"
#include "ui_widget.h"
#include<QtDebug>
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    myT=new MyThread;//不能指定父对象
    thread=new QThread(this);//创建子线程
    myT->moveToThread(thread);//把自定义的线程加入到子线程中

    connect(myT,&MyThread::mySignal,this,&Widget::dealSignal);
    qDebug()<<"main thread: "<<QThread::currentThread();
    connect(this,&Widget::startThread,myT,&MyThread::MyTimeout);
    connect(this,&Widget::destroyed,this,&Widget::dealClose);//右上角X 关了 窗口线程还在运行

}

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

void Widget::dealSignal()
{
    static int i=0;
    i++;
    ui->lcdNumber->display(i);
}

void Widget::dealClose()
{
    on_pushButtonStop_clicked();//停止线程
    delete myT; //释放线程空间
}
//start按钮
void Widget::on_pushButtonStart_clicked()
{
    if(thread->isRunning()==true)
    {
        return;
    }
    //启动线程 但是满意启动线程处理函数
    thread->start();
    myT->setFlag(false);
    //不能直接调用线程处理函数,直接调用导致线程处理函数和主线程在同一个线程
    // myT->myTimeout();/

    //只能通过signal - slot方式
    emit startThread();

}

//stop按钮
void Widget::on_pushButtonStop_clicked()
{
    if(thread->isRunning()==false)
    {
        return;
    }
    myT->setFlag(true);
    thread->quit();
    thread->wait();

}

6.widget.ui文件

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>Widget</class>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>418</width>
    <height>276</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>Widget</string>
  </property>
  <layout class="QVBoxLayout" name="verticalLayout" stretch="2,0">
   <item>
    <widget class="QLCDNumber" name="lcdNumber"/>
   </item>
   <item>
    <layout class="QHBoxLayout" name="horizontalLayout">
     <item>
      <widget class="QPushButton" name="pushButtonStart">
       <property name="text">
        <string>Start</string>
       </property>
      </widget>
     </item>
     <item>
      <widget class="QPushButton" name="pushButtonStop">
       <property name="text">
        <string>Stop</string>
       </property>
      </widget>
     </item>
    </layout>
   </item>
  </layout>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>

7.UI界面

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fyzy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值