2012-05-08 64 views
12

Próbuję uruchomić QTimer w określonym wątku. Jednak zegar nie wydaje się wykonywać i nic nie jest drukowane. Czy to ma coś wspólnego z zegarem, szczeliną lub wątkiem?Uruchamianie QTimer w QThread

main.cpp

#include "MyThread.h" 
    #include <iostream> 
    using namespace std; 

    int main(int argc, char *argv[]) { 
     MyThread t; 
     t.start(); 
     while(1); 
    } 

MyThread.h

#ifndef MYTHREAD_H 
    #define MYTHREAD_H 

    #include <QTimer> 
    #include <QThread> 
    #include <iostream> 

    class MyThread : public QThread { 
     Q_OBJECT 
    public: 
     MyThread(); 
    public slots: 
     void doIt(); 
    protected: 
     void run(); 
    }; 

    #endif /* MYTHREAD_H */ 

MyThread.cpp

#include "MyThread.h" 

    using namespace std; 

    MyThread::MyThread() { 
     moveToThread(this); 
    } 

    void MyThread::run() { 
     QTimer* timer = new QTimer(this); 
     timer->setInterval(1); 
     timer->connect(timer, SIGNAL(timeout()), this, SLOT(doIt())); 
     timer->start(); 
    } 

    void MyThread::doIt(){ 
     cout << "it works"; 
    } 
+2

To nie jest tak, jak powinno się już robić. [przeczytaj ten post] (http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/) – UmNyobe

+0

dlaczego nie tworzysz QApplication? – Kunal

+2

Link został zmieniony na: http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/ – donturner

Odpowiedz

20

Jak skomentował (dalsze informacje w linku) robisz to źle:

  1. jesteś mieszanie obiekt trzyma dane wątek z innego przedmiotu (odpowiedzialny doIt()). Powinny być rozdzielone.
  2. W twojej sprawie nie ma potrzeby podklasy QThread. Co gorsza, zastępujesz metodę run, nie zastanawiając się nad tym, co robił.

Ta część kodu powinna być wystarczająco

QThread* somethread = new QThread(this); 
QTimer* timer = new QTimer(0); //parent must be null 
timer->setInterval(1); 
timer->moveToThread(somethread); 
//connect what you want 
somethread->start(); 

Teraz (Qt w wersji> = 4.7) domyślnie QThread rozpoczyna pętlę wydarzeniem w jego metodzie run(). Aby uruchomić wewnątrz wątku, wystarczy przenieść obiekt. Read the doc...

+0

Jak uruchomić ten timer poza somethread (w bieżącym wątku)? Czy muszę używać usługi QueuedConnection? – jichi

+1

podłączyć sygnał do gniazda timera 'start()' i wywołać sygnał – UmNyobe

+1

Mianowicie 'connect (somethread, SIGNAL (start()), timer, SLOT (start()))' – rbaleksandar

8

QTimer działa tylko w wątku, która ma pętlę zdarzeń.

http://qt-project.org/doc/qt-4.8/QTimer.html

W aplikacjach wielowątkowych, można użyć QTimer w każdym wątku, który posiada pętlę zdarzeń. Aby uruchomić pętlę zdarzeń z wątku innego niż GUI, użyj QThread :: exec(). Qt używa powinowactwa wątku licznika czasu do określenia, który wątek będzie emitował sygnał timeout(). Z tego powodu musisz uruchomić i zatrzymać timer w swoim wątku; nie można uruchomić stopera z innego wątku.

+0

Próbowałem dodać exec() w metodzie run, ale otrzymuję QEventLoop: Nie można go używać bez QApplication. –

+0

Utwórz QApplication, a następnie utwórz swój wątek. –

10
m_thread = new QThread(this); 
QTimer* timer = new QTimer(0); // _not_ this! 
timer->setInterval(1); 
timer->moveToThread(m_thread); 
// Use a direct connection to whoever does the work in order 
// to make sure that doIt() is called from m_thread. 
worker->connect(timer, SIGNAL(timeout()), SLOT(doIt()), Qt::DirectConnection); 
// Make sure the timer gets started from m_thread. 
timer->connect(m_thread, SIGNAL(started()), SLOT(start())); 
m_thread->start(); 
+0

Nie jest dla mnie jasne, czym jest "robotnik". – Stormenet

+2

@Stormenet Jakiś obiekt z slotem 'doIt()', który powinien wykonywać pracę (w stworzonym wątku) za każdym razem, gdy timer się uruchomi. –

0

Można użyć sygnału emitują i uruchomić stoper wewnątrz emitowanego funkcję gniazda

main.cpp

#include "MyThread.h" 
#include <iostream> 
using namespace std; 

int main(int argc, char *argv[]) { 
    MyThread t; 
    t.start(); 
    while(1); 
} 

MyThread.h

#ifndef MYTHREAD_H 
#define MYTHREAD_H 

#include <QTimer> 
#include <QThread> 
#include <iostream> 

class MyThread : public QThread { 
    Q_OBJECT 
public: 
    MyThread(); 
    QTimer *mTimer; 
signals: 
    start_timer(); 
public slots: 
    void doIt(); 
    void slot_timer_start(); 
protected: 
    void run(); 
}; 

#endif /* MYTHREAD_H */ 

MyThread.cpp

#include "MyThread.h" 

using namespace std; 

MyThread::MyThread() { 
    mTimer = new QTimer(this); 
    connect(this,SIGNAL(start_timer()),this, SLOT(slot_timer_start())); 
    connect(mTimer,SIGNAL(timeout()),this,SLOT(doIt())); 

} 

void MyThread::run() { 
    emit(start_timer()); 
    exec(); 
} 

void MyThread::doIt(){ 
    cout << "it works"; 
} 
void MyThread::slot_timer_start(){ 
    mTimer->start(1000); 
} 
0

Potrzebujesz pętli zdarzeń, aby mieć liczniki czasu.Oto jak rozwiązać ten sam problem z moim kodu:

MyThread::MyThread() { 
} 

void MyThread::run() { 
    QTimer* timer = new QTimer(this); 
    timer->setInterval(1); 
    timer->connect(timer, SIGNAL(timeout()), this, SLOT(doIt())); 
    timer->start(); 

    /* Here: */ 
    exec();    // Starts Qt event loop and stays there 
    // Which means you can't have a while(true) loop inside doIt() 
    // which instead will get called every 1 ms by your init code above. 
} 

void MyThread::doIt(){ 
    cout << "it works"; 
} 

Oto odnośny fragment dokumentacji, że żaden z innych plakatów wymienić:

int QCoreApplication :: exec()

Powoduje wejście w główną pętlę zdarzeń i oczekuje na wywołanie metody exit(). Zwraca wartość, która została ustawiona na exit() (która wynosi 0, jeśli exit() jest wywoływana przez quit()). Tę funkcję należy wywołać, aby rozpocząć obsługę zdarzenia . Główna pętla zdarzeń odbiera zdarzenia z systemu okienkowego i wysyła je do widżetów aplikacji. Aby aplikacja wykonała przetwarzanie w trybie bezczynności (tj. Wykonując specjalną funkcję , gdy nie ma żadnych oczekujących zdarzeń), użyj QTimer z czasem oczekiwania 0. Bardziej zaawansowane schematy przetwarzania w trybie bezczynności można uzyskać za pomocą processEvents().