QThread创建多线程程序

Posted samp000

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QThread创建多线程程序相关的知识,希望对你有一定的参考价值。

最近在阅读Qt 5.9 C++开发指南,为了加深对书本上内容的理解,参照书上的讲解尝试写了一些demo,用于以后工作中查阅,如果涉及侵权请告知实例程序samp13_1

mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class MyThread : public QThread
{
    Q_OBJECT

private:
    int _times;
    int _value;

protected:
    void run();

public:
    MyThread();
    ~MyThread();

signals:
    void timesValueChanged(int times, int value);

};

#endif // MYTHREAD_H

mythread.cpp

#include "mythread.h"
#include <QRandomGenerator>

MyThread::MyThread()
{
    _times = 0;
    _value = 0;
}

MyThread::~MyThread()
{

}

// 这个是通过信号与槽与主窗口进行交互的,还有一种方法是通过函数
void MyThread::run()
{
    while(1)
    {
        _value = QRandomGenerator::global()->generate(); // 用这个类生成随机数
        _value = (_value % 6) + 1;

        // 这个类生成的数可能是负数,如果是负数就从新生成
        if(_value <= 0)
        {
            continue;
        }

        _times = _times + 1;
        emit timesValueChanged(_times, _value); // 发信号给主窗口,叫他显示

        msleep(500); // 先睡一会儿在生成数字
    }
}

mydialog.h

#ifndef MYDIALOG_H
#define MYDIALOG_H

#include <mythread.h>
#include <QDialog>
#include <QPushButton>
#include <QPlainTextEdit>
#include <QLabel>

class MyDialog : public QDialog
{
    Q_OBJECT

private:           
    QPushButton *_btnStart;
    QPushButton *_btnFinish;
    QPushButton *_btnClearInfo;
    QPlainTextEdit *_plainTextEdit;
    QLabel *_labStatus;
    QLabel *_labPicture;
    MyThread *_thread;

protected:
    void closeEvent(QCloseEvent *event);

public:
    MyDialog(QWidget *parent = nullptr);
    ~MyDialog();

    void iniUI();
    void iniSignalSlots();

private slots:
    void btnStartClicked();
    void btnFinishClicked();
    void btnClearInfoClicked();
    void timesValueChanged(int times, int value);

};

#endif // MYDIALOG_H

mydialog.cpp

#include "mydialog.h"
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QPixmap>
#include <QString>

MyDialog::MyDialog(QWidget *parent) : QDialog(parent)
{
    iniUI();

    //创建线程
    _thread = new MyThread();

    iniSignalSlots();
}

MyDialog::~MyDialog()
{

}

// 初始化界面
void MyDialog::iniUI()
{
    // 创建按钮
    _btnStart = new QPushButton("启动游戏");
    _btnFinish = new QPushButton("结束游戏");
    _btnFinish->setEnabled(false);
    _btnClearInfo = new QPushButton("清空文本");

    // 布局按钮
    QHBoxLayout *layout1 = new QHBoxLayout();
    layout1->addWidget(_btnStart);
    layout1->addWidget(_btnFinish);
    layout1->addWidget(_btnClearInfo);

    // 创建文本框和图片显示框
    _plainTextEdit = new QPlainTextEdit();
    _labPicture = new QLabel();
    QPixmap pixmap;
    pixmap.load(":/images/d0.jpg");
    _labPicture->setPixmap(pixmap);

    // 布局文本框和图片显示框
    QHBoxLayout *layout2 = new QHBoxLayout();
    layout2->addWidget(_plainTextEdit);
    layout2->addWidget(_labPicture);

    // 创建状态栏
    _labStatus = new QLabel("游戏状态:未开始");

    // 布局状态栏
    QHBoxLayout *layout3 = new  QHBoxLayout();
    layout3->addWidget(_labStatus);

    // 创建分组框的布局
    QVBoxLayout *layout4 = new QVBoxLayout();
    layout4->addLayout(layout1);
    layout4->addLayout(layout2);
    layout4->addLayout(layout3);

    // 创建一个分组框
    QGroupBox *groupBox = new QGroupBox("掷骰子");
    groupBox->setLayout(layout4);

    // 创建整体布局
    QHBoxLayout *layout5 = new QHBoxLayout();
    layout5->addWidget(groupBox);

    // 设置整体布局
    setLayout(layout5);
    resize(800, 600);
}

// 连接信号与槽
void MyDialog::iniSignalSlots()
{
    connect(_btnStart, SIGNAL(clicked()), this, SLOT(btnStartClicked()));
    connect(_btnFinish, SIGNAL(clicked()), this, SLOT(btnFinishClicked()));
    connect(_btnClearInfo, SIGNAL(clicked()), this, SLOT(btnClearInfoClicked()));
    connect(_thread, SIGNAL(timesValueChanged(int, int)), this, SLOT(timesValueChanged(int, int)));

}

void MyDialog::btnStartClicked()
{
    _labStatus->setText("游戏状态:进行中");
    _thread->start();
    _btnStart->setEnabled(false);
    _btnFinish->setEnabled(true);
}

void MyDialog::btnFinishClicked()
{
    _labStatus->setText("游戏状态:未开始");
    _thread->terminate();
    _thread->wait();
    _btnStart->setEnabled(true);
    _btnFinish->setEnabled(false);
}

void MyDialog::btnClearInfoClicked()
{
    _plainTextEdit->clear();
}

// 当用户点击开始游戏后,线程就启动了,当线程生成一个数字时,会发一个信号过来,这个槽函数接受信号做出响应
void MyDialog::timesValueChanged(int times, int value)
{
    QString text = QString::asprintf("第%d次掷骰子,点数为:%d", times, value);
    _plainTextEdit->appendPlainText(text);
    QString filename = QString::asprintf(":/images/d%d.jpg", value);
    QPixmap pixmap;
    pixmap.load(filename);
    _labPicture->setPixmap(pixmap); // 给一个label设置图片
}

void MyDialog::closeEvent(QCloseEvent *event)
{
    if(_thread->isRunning()) // 如果线程还在继续执行,那么强行终止
    {
        _thread->terminate();
        _thread->wait();
    }
    event->accept();
}

main.cpp

#include "mydialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyDialog w;
    w.show();

    return a.exec();
}

效果展示

技术图片

以上是关于QThread创建多线程程序的主要内容,如果未能解决你的问题,请参考以下文章

Python Qt GUI设计:多线程中信号与槽的使用(基础篇—9)

Qt多线程和GUI界面假死

QThread与多线程(比较清楚)

QtConcurrent 与多线程 QThread 的多线程性能

[ PyQt入门教程 ] PyQt5中多线程模块QThread使用方法

QT的多线程使用