qt多线程编程|Qt多线程功能简化方案

qt多线程编程|Qt多线程功能简化方案) 序

UI程序中经常有一些耗时的操作要处理,如果直接在UI线程中执行,整个界面都会卡住,出现无响应状态。
如果每次操作都生成一个线程类,而且相关数据都要传递过去,可能处理起来会比较麻烦!
因此本篇文章的初衷就是想简化这种情况。

qt多线程编程(Qt多线程功能简化方案

仿照MFC方式解决

最开始我想到的就是按照MFC创建线程的方式进行解决。
通过类的 static 成员函数作为函数指针,通过QThread的run函数进行回调。
思路如下:

UI 部分大致逻辑如下
class Form : public QWidget{    Q_OBJECTpublic:     Form(QWidget *parent=0) : QWidget(parent)    {        ...        m_thread.setCallBack(run, this);        m_thread.start();    }...private:    void static run(QObject* obj)    {        Form*frm = (Form*) obj;        frm->todo();    }    void todo()    {         // 添加需要做的事情    }...private:    CThread m_thread;}
CThread实现方式如下
#ifndef CTHREAD_H#define CTHREAD_H#include <QThread>// 函数指针定义,用于回调的;QObject *即为传递过来的 Form 的 this 对象指针typedef void (*pFuncPointer)(QObject *);   class CThread : public QThread{public:    CThread(QObject *obj=0):QThread(obj) {m_obj = obj;}    CThread(pFuncPointer func, QObject *obj):QThread(obj) {m_func = func; m_obj = obj;}    void setCallBack(pFuncPointer func, QObject *obj) {m_func = func; m_obj = obj;}    void setObj(QObject *obj) {m_obj = obj;}    void setFun(pFuncPointer func) {m_func = func;}private:    void run(){m_func(m_obj);}  // 回调函数,将 this 传递回去private:    pFuncPointer m_func;    QObject *m_obj;};#endif // CTHREAD_H
更进一步

由于我实在太懒了,觉得定义按照MFC那样的方式定义 static 成员函数 实在太麻烦了;
想直接一步到位,如果这样可以通过传递类的函数指针,这样就可以简化成下面这样!
思路如下:

UI 部分大致逻辑如下
class Form : public QWidget{    Q_OBJECTpublic:     Form(QWidget *parent=0) : QWidget(parent)    {        ...        m_thread.setCallBack(&MainForm::todo, this);  // 成员函数指针        m_thread.start();    }...private:    void todo()    {         // 添加需要做的事情    }...private:    CThread<Form> m_thread;}
CThread实现方式如下
#ifndef CTHREAD_H#define CTHREAD_H#include <QThread>template <typename T>                    // 模板class CThread : public QThread{public:    typedef void (T::*pFuncPointer)();   // 模板函数指针    CThread(T *obj=0):QThread(obj) {m_obj = obj;}    CThread(pFuncPointer func, T *obj):QThread(obj) {m_func = func; m_obj = obj;}    void setCallBack(pFuncPointer func, T *obj) {m_func = func; m_obj = obj;}    void setObj(T *obj) {m_obj = obj;}    void setFun(pFuncPointer func) {m_func = func;}private:    void run(){(m_obj->*m_func)();}  // 回调,这里的写法需要注意private:    pFuncPointer m_func;    T *m_obj;};#endif // CTHREAD_H
需要注意的地方

由于 todo 函数虽然是 Form 的成员函数,但是它是被另一个线程所调用的,所以它不属于UI线程。
在更新界面相关,或者需要更新界面信息时,可以在 Form 里面定义信号和对应的槽;
而且连接的时候,最好明确指明最后一个参数为Qt::QueuedConnection。

总结

我的砖就抛到这里,希望对你们有用。
接下来的路就请各位小伙伴们自己走了!

推荐阅读