2017-02-09 22 views
1

Я пытался использовать QTimer в разных QThread, но я не смог подключиться к слоту.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 никогда не вызывается в timeout @MrEricSir –

+0

@MrEricSir, попробуйте переместить 'connect (percentTimer ...)' before' percentTimer-> moveToThread (...); ' –

ответ

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 class documentation:

В многопоточных приложениях вы можете использовать QTimer в любом потоке, который имеет цикл событий. Чтобы запустить цикл событий из потока, отличного от GUI, используйте QThread :: exec(). Qt использует аффинность потока таймера, чтобы определить, какой поток будет выдавать сигнал таймаута(). Из-за этого, вы должны запустить и остановить таймер в своей нити; невозможно запустить таймер из другого потока.

В вашем случае percentTimer = new QTimer(); выполняется из основного потока, (даже если вы использовали moveToThread ранее, это по-прежнему основной поток его выполнения), в то время как ваши сигналы doWork и start вылетают из workerThread.

Вы можете, например, сделать ваш new QTimer из void 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())); 
}