2012-12-29 88 views
1

我正在使用Qt5,我通過moveToThread()將QObject worker傳遞給QThread實例來實現線程。我的實現看起來是這樣的..Qt:QObject移動到不同線程後信號/插槽不工作

Worker.h

class worker : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit worker(QObject *parent = 0); 
    bool IsWorkRunning(); 
    void MoveObjectToThread(); 

signal: 
    void SignalToObj_mainThreadGUI(); 

public slots: 
    void do_Work(); 
    void StopWork(); 
    void StartWork(); 

private: 
    void Sleep(); 
    QThread *workerthread;  
    volatile bool running,stopped; 
}; 

Worker.cpp

worker::worker(QObject *parent) : 
    QObject(parent),stopped(false),running(false) 
{ 
} 

void worker::do_Work() 
{ 
    running = true; 
    while(!stopped) 
    { 
     if(running) 
     { 
     emit SignalToObj_mainThreadGUI(); 
     workerthread->msleep(20); 
     } 
    } 
} 

void worker::StopWork() 
{ 
    running = false; 
} 

void worker::StartWork() 
{ 
    running = true; 
} 

bool worker::IsWorkRunning() 
{ 
    return running; 
} 

void MoveObjectToThread() 
{ 
    workerthread = new QThread; 
    QObject::connect(workerthread,SIGNAL(started()),this,SLOT(do_Work())); 

    this->moveToThread(workerthread); 

    workerthread->start(); 
} 

MainWindow.h

namespace Ui { 
class MainWindow; 
} 

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    explicit MainWindow(QWidget *parent = 0); 
    ~MainWindow(); 

signals: 
    void Startwork_mainwindow(); 
    void Stopwork_mainwindow(); 

public slots: 

private slots: 
    void on_pushButton_push_to_start_clicked(); 

    void on_pushButton_push_to_stop_clicked(); 

private: 

    Ui::MainWindow *ui; 
    worker myWorker; 
    bool work_started; 

}; 

MainWindow.cpp

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent),work_started(false), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 

    QObject::connect(this,SIGNAL(Startwork_mainwindow()),&myWorker,SLOT(StartWork())); 
    QObject::connect(this,SIGNAL(Stopwork_mainwindow()),&myWorker,SLOT(StopWork())); 
} 

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

void MainWindow::on_pushButton_push_to_start_clicked() 
{ 
    if(!work_started) 
    { 
     myWorker.MoveObjectToThread(); 
     work_started = true; 
    } 

    if(!myWorker.IsWorkRunning()) 
     emit this->Startwork_mainwindow(); 
} 

void MainWindow::on_pushButton_push_to_stop_clicked() 
{ 
    if(myWorker.IsWorkRunning()) 
     emit this->Stopwork_mainwindow(); 
} 

不知道爲什麼,下面的兩個信號/槽對似乎沒有工作

QObject::connect(this,SIGNAL(Startwork_mainwindow()),&myWorker,SLOT(StartWork())); 
QObject::connect(this,SIGNAL(Stopwork_mainwindow()),&myWorker,SLOT(StopWork())); 

因此,我不能啓動或停止線程一旦do_Work()槽被觸發通過started() QThread對象的信號。僅供參考這個帖子我的是我以前的帖子的延續here described。任何見解將是有益的...謝謝

+0

您是否嘗試過在執行任何信號連接之前移動到線程。就像你做完之後?當你的線程沒有運行的時候,你的線程並不是在你的線程中瘋狂地旋轉嗎?也許它也需要睡眠以幫助調度程序。 – jdi

+0

而不是使用'moveToThread',我會重新實現'QThread'。跟蹤更容易,我認爲不太容易出錯。當使用'QObject :: connect'從主線程到另一個線程時,請不要使用'AutoConnect'連接到另一個線程,請使用['QueuedConnection'](http://qt-project.org/doc/qt- 4.8/qt.html#ConnectionType-enum)。 – phyatt

+0

如果我使用Qt :: Directconnection,該怎麼辦?有些地方在我讀過的論壇中對QThread進行子類分類並不是一個好習慣......而Qt5已經使許多靜態私有函數公開了,因爲這種使用範例 –

回答

2

在你MainWindow類的定義,請嘗試更改worker myWorkerworker * myWorker。另外,我會照其他人的建議去做,並將課程移到worker課外。該MainWindow構造變得像這樣:

MainWindow::MainWindow(QWidget *parent) 
    : QMainWindow(parent) 
    , work_started(false) 
    , ui(new Ui::MainWindow) 
    , myWorker(new worker()) 
{ 
    // NOTE: myWorker is created without a parent on purpose. 
    // Qt won't change the thread affinity of an obj with a parent 

    ui->setupUi(this); 

    connect(this, SIGNAL(Startwork_mainwindow()), myWorker, SLOT(StartWork())); 
    connect(this, SIGNAL(Stopwork_mainwindow()), myWorker, SLOT(StopWork())); 

    QThread * thread = new QThread(); 
    // delete the worker obj whenever this obj is destroyed 
    connect(this, SIGNAL(destroyed()), myWorker, SLOT(deleteLater())); 
    // stop the thread whenever the worker is destroyed 
    connect(myWorker, SIGNAL(destroyed()), thread, SLOT(quit())); 
    // clean up the thread 
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
    myWorker->moveToThread(thread); 
    thread->start(); 
} 

當然,你不需要worker::MoveObjectToThread()方法了。另外,方法worker::IsWorkRunning()MainWindow調用並不安全。你可能不會遇到這個具體例子的麻煩,但是當事情變得更加複雜時,它肯定會給你帶來痛苦。相反,請添加workFinished()信號或類似信息,並在MainWindow類中進行收聽。

Startwork_mainwindow()信號將開始工作。由於您在connect的調用中不提供連接類型,因此當您更改線程關聯(moveToThread)時,Qt將使用QueuedConnection。基本上,myWorker是在它自己的事件循環線程中。使用Qt::QueuedConnection調用一個插槽將事件發送到該事件循環,然後將插槽方法排隊。它會在事件循環接近它時運行。