2017-02-09 212 views
1

我試圖在QThread不同的QThread內使用QTimer,但我無法連接到QTimertimeout()插槽。QTimer不呼叫超時插槽

我在做什麼錯?

這裏是我的代碼:

extern MainWindow *mainClass; 

class myObj : public QObject 
{ 
    Q_OBJECT 
public: 
    explicit myObj(QObject *parent = 0); 
    ~myObj(); 
    QThread workerThread; 

    int percent; 
    QTimer *percentTimer; 

public slots: 
    void doWork(); 
    void percentUpdate(); 
    void startFunction(); 

signals: 
    void start(); 
    void UpdateResult(); 
}; 

myObj::myObj(QObject *parent) : QObject(parent) 
{ 
    moveToThread(&workerThread); 

    connect(&workerThread, SIGNAL(finished()), this, SLOT(deleteLater())); 
    connect(this, SIGNAL(UpdateResult()), mainClass, SLOT(on_UpdateResult())); 
    connect(&workerThread, SIGNAL(started()), this, SLOT(doWork())); 
    connect(this, SIGNAL(start()), this, SLOT(startFunction())); 

    percent++; 
    percentTimer = new QTimer(); 
    percentTimer->moveToThread(&workerThread); 
    percentTimer->setInterval(1000); 
    connect(percentTimer, SIGNAL(timeout()), this,SLOT(percentUpdate())); 

} 

myObj::~myObj() { 
    workerThread.quit(); 
    workerThread.wait(); 
    if (percentTimer) percentTimer->deleteLater(); 
} 

void myObj::doWork() 
{ 
    emit start(); 
    workerThread.exec();  
} 

void myObj::startFunction() 
{ 
    percentTimer->start(); 
    QThread::sleep(60); 
    percentTimer->stop();  
} 

void myObj::percentUpdate() 
{ 
    qDebug() << "In Timer" << percent++; 
    emit UpdateResult(); 

} 
+0

當您在調試器中完成此操作時會發生什麼?首先在每種方法中添加一個斷點。哪些被調用,以什麼順序? – MrEricSir

+0

一切工作正常,除了插槽percentUpdate永遠不會在超時時調用@MrEricSir –

+0

@MrEricSir,嘗試在'percentTimer-> moveToThread(...)之前移動'connect(percentTimer ...)'' –

回答

1

首先,你應該SHART workerThread讓在其上下文myObj工作(創建所需的連接後啓動因爲插槽連接到start信號可能不會否則執行)。 而不是使用QThread::sleepFor的你應該使用這樣的事情:

QEventLoop loop; 
QTimer::singleShot(60000, &loop, SLOT(exit())); 
loop.exec(); 

創建延遲,因爲QThread::sleepFor凍結整體線程執行。所以你的任何事件都不會被綁定到這個線程。

workerThread.exec()這裏沒用。

+0

感謝作品(y)@RealFresh –

4

這是因爲您試圖從不同於創建QTimer的線程啓動QTimer。當使用QTimer和線程時,您應該非常小心地在將控制它的線程中創建您的QTimer。

QTimer class documentation

在多線程應用程序,你可以在有事件循環任何線程使用QTimer。要從非GUI線程啓動事件循環,請使用QThread :: exec()。 Qt使用計時器的線程關聯來確定哪個線程將發出timeout()信號。因此,您必須在其線程中啓動和停止計時器;不可能從另一個線程啓動一個定時器。

在你的情況percentTimer = new QTimer();從主線程(即使你使用moveToThread之前,這仍然是執行它的主線程)執行,而你doWorkstart信號從發射workerThread

例如你可以做你的new QTimervoid init()插槽從workerThread調用,而不是在構造函數中,以確保QTimer創建並通過適當的線程所擁有。

myObj::myObj(QObject *parent) : QObject(parent), percentTimer(nullptr) 
{ 
    moveToThread(&workerThread); 

    connect(&workerThread, SIGNAL(finished()), this, SLOT(deleteLater())); 
    connect(this, SIGNAL(UpdateResult()), mainClass, SLOT(on_UpdateResult())); 
    connect(&workerThread, SIGNAL(started()), this, SLOT(init())); 
    connect(&workerThread, SIGNAL(started()), this, SLOT(doWork())); 
    connect(this, SIGNAL(start()), this, SLOT(startFunction())); 

    percent++; 
} 

void myObj::init() { 
    percentTimer = new QTimer(); 
    percentTimer->setInterval(1000); 
    connect(percentTimer, SIGNAL(timeout()), this, SLOT(percentUpdate())); 
}