《QT5.9 c++ 开发指南》第13章 QThread功能简介

先看一下QThread 类功能简单介绍

         将应用程序的线程称为主线程,额外创建的线程称为工作线程 。 一般在主线程里创建工作线程,井调用 start()开始执行工作线程的任务 。 start()会在 内 部调用 run()函数,进入工作线程的事件循环,在 run()函数里调用 exit()或 quit()可以结束线程的事件循环,或在主线程里调用 terminate() 强制结束线程。
         公共函数部分:


 那我们开始写一个小工程吧。

 

   

 

先看下运行的图吧:

页面布局如下:

这获取图片资源:

链接:图片资源      提取码:74g3 

提取后记得要加载在项目中。

好的,我们先需要写一个类 QDiceThread 继承与 QThread 如下面:

#ifndef QDICETHREAD_H
#define QDICETHREAD_H

#include    <QThread>

class QDiceThread :public QThread
{
     Q_OBJECT
private:
    int     m_seq=0;//掷骰子次数序号
    int     m_diceValue;//骰子点数
    bool    m_Paused = true; //掷一次骰子
    bool    m_stop=false; //停止线程
protected:
    void run() Q_DECL_OVERRIDE;   //线程任务,重载run函数
public:
    QDiceThread();
    void diceBegin();  //掷一次骰子
    void dicePause(); //暂停
    void stopThread();  //结束线程
signals:
    void newValue(int seg,int diceValue); //产生新点数的信号  由主线程的槽函数响应
};

#endif // QDICETHREAD_H

对应的cpp:

#include "qdicethread.h"
#include<QTime>

QDiceThread::QDiceThread()
{

}
void QDiceThread::run()
{
    //线程任务
    m_stop = false; //启动线程 m_stop=false
    m_seq = 0; //掷骰子次数
    qsrand(uint(QTime::currentTime().msec())); //随机数初始化,qsrand是线程安全的
    while (!m_stop) {
        if(!m_Paused)
        {
            m_diceValue = qrand(); //获取随机数
            m_diceValue = (m_diceValue % 6) +1;
            m_seq++;
            emit newValue(m_seq,m_diceValue); //发送信号
        }
        msleep(500); //线程休眠500ms
    }

    //  在  m_stop==true时结束线程任务
    quit(); //相当于  exit(0),退出线程的事件循环
}



void QDiceThread::diceBegin()
{
    //开始掷骰子
    m_Paused = false;
}

void QDiceThread::dicePause()
{
    //暂停掷骰子
    m_Paused = true;
}

void QDiceThread::stopThread()
{
    //停止线程
    m_stop = true;
}
 

如果你编译过程中出现下面错误,可能是你在创建这个类的时候,没有选择继承 Q_OBJECT:

 

解决方案:

解决方案与错误分析

如果没有我们继续:

这个是dialog.h 文件:

#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include "qdicethread.h"

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT
private:
    QDiceThread  threadA;
protected:
    void closeEvent(QCloseEvent *event);

public:
    explicit Dialog(QWidget *parent = nullptr);
    ~Dialog();
private slots:
    //自定义槽函数
    void    onthreadA_started();
    void    onthreadA_finished();
    void    onthreadA_newValue(int seq, int diceValue);

    void on_btnStartThread_clicked();

    void on_btnDiceBegin_clicked();

    void on_btnDiceEnd_clicked();

    void on_btnStopThread_clicked();

    void on_btnClear_clicked();

private:
    Ui::Dialog *ui;
};

#endif // DIALOG_H

这个是dialog.cpp 文件:

#include "dialog.h"
#include "ui_dialog.h"

void Dialog::closeEvent(QCloseEvent *event)
{
    //关闭窗口 并退出程序
    if(threadA.isRunning())
    {
        threadA.stopThread();
        threadA.wait();
    }
    event->accept();
}

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    //构造函数
    connect(&threadA,SIGNAL(started()),this,SLOT(onthreadA_started()));
    connect(&threadA,SIGNAL(finished()),this,SLOT(onthreadA_finished()));
    connect(&threadA,SIGNAL(newValue(int,int)),this,SLOT(onthreadA_newValue(int,int)));

}

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

void Dialog::onthreadA_started()
{
   //线程started()信号的响应槽函数
    ui->LabA->setText("Thread 状态: thread started");
}

void Dialog::onthreadA_finished()
{
    //线程的 finished()信号的响应槽函数
    ui->LabA->setText("Thread状态:thread finished");
}

void Dialog::onthreadA_newValue(int seq, int diceValue)
{
   //QDiceThread的newValue()信号的响应槽函数,显示骰子次数和点数
    QString str = QString::asprintf("第 %d 次掷骰子,点数为:%d",seq,diceValue);
    ui->plainTextEdit->appendPlainText(str);
    QPixmap pic;//图片显示
    QString filename = QString::asprintf(":/dice/images/d%d.jpg",diceValue);
    pic.load(filename);
    ui->LabPic->setPixmap(pic);

}

void Dialog::on_btnStartThread_clicked()
{
   //开始线程
    threadA.start(); //开始线程,会执行重载的run 函数
    ui->btnStartThread->setEnabled(false);
    ui->btnStopThread->setEnabled(true);

    ui->btnDiceBegin->setEnabled(true);
    ui->btnDiceEnd->setEnabled(false);
}

void Dialog::on_btnDiceBegin_clicked()
{
    //开始 掷骰子按钮
    threadA.diceBegin();
    ui->btnDiceBegin->setEnabled(false);
    ui->btnDiceEnd->setEnabled(true);
}

void Dialog::on_btnDiceEnd_clicked()
{
    //暂停 掷骰子按钮
    threadA.dicePause();
    ui->btnDiceBegin->setEnabled(true);
    ui->btnDiceEnd->setEnabled(false);
}

void Dialog::on_btnStopThread_clicked()
{
    //结束线程
    threadA.stopThread();
    threadA.wait();

    ui->btnStartThread->setEnabled(true);
    ui->btnStopThread->setEnabled(false);

    ui->btnDiceBegin->setEnabled(false);
    ui->btnDiceEnd->setEnabled(false);
}



void Dialog::on_btnClear_clicked()
{
    //清空文本 按钮
    ui->plainTextEdit->clear();
}

大部分功能都有中文解释了,请慢慢理解,可以看这本书,对比来。

希望大家多多学习进步。

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
当然可以!以下是一个使用Qt 5.9、C++和OpenCV 4.6的示例程序,演示了如何在多线程环境下使用OpenCV: ```cpp #include <QApplication> #include <QMainWindow> #include <QPushButton> #include <QHBoxLayout> #include <QThread> #include <QDebug> #include <QLabel> #include <opencv2/opencv.hpp> // 子线程类 class WorkerThread : public QThread { Q_OBJECT public: void run() override { // 加载图片并在子线程中处理 cv::Mat image = cv::imread("path_to_image.jpg"); cv::cvtColor(image, image, cv::COLOR_BGR2GRAY); // 发送信号以将图像传递给主线程 emit imageProcessed(image); } signals: void imageProcessed(const cv::Mat& image); }; class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = nullptr) : QMainWindow(parent) { // 创建按钮和标签 QPushButton *button = new QPushButton("处理图片"); connect(button, &QPushButton::clicked, this, &MainWindow::processImage); label = new QLabel; label->setAlignment(Qt::AlignCenter); // 创建布局并将按钮和标签添加到其中 QHBoxLayout *layout = new QHBoxLayout; layout->addWidget(button); layout->addWidget(label); // 创建主窗口并将布局设置为中心部件 QWidget *centralWidget = new QWidget; centralWidget->setLayout(layout); setCentralWidget(centralWidget); } public slots: void displayImage(const cv::Mat& image) { // 转换图像格式以便在Qt中显示 cv::Mat rgbImage; cv::cvtColor(image, rgbImage, cv::COLOR_GRAY2RGB); // 创建图像显示 QImage qimage(rgbImage.data, rgbImage.cols, rgbImage.rows, rgbImage.step, QImage::Format_RGB888); // 在标签上显示图像 label->setPixmap(QPixmap::fromImage(qimage).scaled(label->size(), Qt::KeepAspectRatio)); } void processImage() { // 创建子线程并连接信号和槽函数 WorkerThread *workerThread = new WorkerThread; connect(workerThread, &WorkerThread::imageProcessed, this, &MainWindow::displayImage); // 启动子线程 workerThread->start(); } private: QLabel *label; }; int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } #include "main.moc" ``` 请确保将示例中的 `path_to_image.jpg` 替换为你要处理的图像的实际路径。这个示例中,我们创建了一个主窗口,其中包含一个用于处理图片的按钮。当按下按钮时,会创建一个子线程并在子线程中加载图像、将其转换为灰度图像,然后将处理后的图像传递给主线程进行显示。 请注意,这个示例假设你已经正确安装和配置了Qt 5.9和OpenCV 4.6,并将其正确链接到项目中。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值