前言
目的是在主線程中,使用信號和槽來執行一個子線程中的處理函數。
- 當點擊start按鈕時,子線程每秒鐘發射一個信號(mySignal) 並在控制檯打印線程地址,主線程接收此信號執行數字累加。
- 當點擊stop按鈕時,停止子線程,並釋放內存。
- 當點擊關閉窗口按鈕時,可能子線程還在運行,此時就要觸發stop按鈕的信號執行停止子線程。
步驟
- 創建自定義類Thread繼承QObject,並在槽函數中寫相應的處理代碼。
- 在主線程中創建一個Thread的對象myT,和QThread(子線程)的對象thread。
- 將myT加入到子線程中。
- 啓動子線程thread(此時並沒有執行myT中的處理函數myTimerout())。
- 通過主線程的信號startThread()喚醒子線程的函數myTimerout()。
- 子線程中myTimerout()發射信號mySignal(),主線程接收執行dealSignal()。
代碼:
自定義類Thread:
thread.h
#include<QObject>
#include<QDebug>
#include<QThread>
class Thread : public QObject
{
Q_OBJECT
public:
Thread() ;
void set_flag(bool x) ;
signals:
void mySignal() ;
public slots:
void myTimerout();
private:
bool flag;
};
thread.cpp
#include"thread.h"
#include "QThread"
Thread::Thread()
{
flag = false ;
}
void Thread::set_flag(bool x)
{
this->flag = x ;
}
void Thread::myTimerout()
{
while(!flag)
{
for(long long i = 0; i < 500000000; i++) ;
emit mySignal() ;
qDebug() << QThread::currentThread() ;
}
}
classwindow.h
#ifndef CLASSWINDOW_H
#define CLASSWINDOW_H
#include <QtGui/QMainWindow>
#include <QDebug>
#include <QThread>
#include "ui_classwindow.h"
#include "thread.h"
class ClassWindow : public QMainWindow
{
Q_OBJECT
public:
ClassWindow(QWidget *parent = 0, Qt::WFlags flags = 0);
~ClassWindow();
private:
Ui::ClassWindowClass ui;
Thread *myT;
QThread *thread ;
signals:
void startThread() ;
public slots:
void startButton_licked() ;
void stopButton_clicked() ;
//處理子線程發射的信號的函數
void dealSignal() ;
};
#endif // CLASSWINDOW_H
classwindow.cpp
#include "classwindow.h"
ClassWindow::ClassWindow(QWidget *parent, Qt::WFlags flags)
: QMainWindow(parent, flags)
{
ui.setupUi(this);
//創建自定義線程類,動態分配空間,不能指定父對象
myT = new Thread ;
//創建子線程
thread = new QThread(this) ;
//把自定義線程加入到子線程中
myT->moveToThread(thread) ;
qDebug() << QThread::currentThread() ;
//主線程發射信號,子線程接收開始執行函數myTimout()
QObject::connect(this, SIGNAL(startThread()), myT, SLOT(myTimerout())) ;
//子線程中的myTimout()每秒發射一個信號,主線程執行dealSignal
QObject::connect(myT, SIGNAL(mySignal()), this, SLOT(dealSignal()));
//關閉按鈕觸發stop按鈕來停止子線程
QObject::connect(this, SIGNAL(destroyed()), this, SLOT(stopButton_clicked())) ;
//線程處理函數不能操作圖形用戶界面
}
ClassWindow::~ClassWindow()
{
}
void ClassWindow::startButton_licked()
{
if(thread->isRunning())
return ;
myT->set_flag(false) ;
thread->start() ;
emit startThread() ;
}
void ClassWindow::stopButton_clicked()
{
if(thread->isFinished())
return ;
myT->set_flag(true) ;
thread->quit() ;
thread->wait() ;
delete myT ;
}
void ClassWindow::dealSignal()
{
static int i = 0;
i++;
ui.lcdNumber->display(i) ;
}
運行時可以看到,控制檯上顯示的主線程和子線程不是一個地址。