在 QThread 中启动 QTimer
Posted
技术标签:
【中文标题】在 QThread 中启动 QTimer【英文标题】:Starting QTimer In A QThread 【发布时间】:2012-05-16 13:47:36 【问题描述】:我正在尝试在特定线程中启动 QTimer。但是,计时器似乎没有执行,也没有打印出来。是和定时器、槽还是线程有关?
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";
【问题讨论】:
这不是事情应该做的事情了。 read this post 你为什么不创建 QApplication ? 链接已更改为:blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong 链接又变了:blog.qt.io/blog/2010/06/17/youre-doing-it-wrong 【参考方案1】:正如我所评论的(链接中的更多信息)你做错了:
-
您正在将持有线程数据的对象与另一个对象(由
doIt()
负责)混合。它们应该分开。
在你的情况下不需要子类QThread
。更糟糕的是,您正在覆盖 run
方法,而没有考虑它在做什么。
这部分代码应该够用了
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();
现在(Qt 版本>= 4.7)默认QThread
在他的run()
方法中启动一个事件循环。为了在线程内运行,您只需要移动对象。 Read the doc...
【讨论】:
如何在某个线程之外(在当前线程中)启动这个计时器?我必须使用 QueuedConnection 吗? 连接一个信号到定时器槽start()
并触发信号
即connect(somethread, SIGNAL(started()), timer, SLOT(start()))
如果我想停止线程和计时器是否可以安全地调用 thread.quit() 和之后的 thread.wait()? “somethread”是否为 QTimer 对象释放内存?
@rbaleksandar 函数指针语法需要强制转换才能正确编译:connect(somethread, &QThread::started, timer, static_cast<void (QTimer::*)()>(&QTimer::start));
【参考方案2】:
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();
【讨论】:
@Stormenet 带有插槽doIt()
的某个对象应该在计时器触发时执行工作(在创建的线程中)。【参考方案3】:
QTimer
仅适用于具有事件循环的线程。
http://qt-project.org/doc/qt-4.8/QTimer.html
在多线程应用程序中,您可以在任何具有事件循环的线程中使用 QTimer。要从非 GUI 线程启动事件循环,请使用 QThread::exec()。 Qt 使用计时器的线程亲和性来确定哪个线程将发出 timeout() 信号。因此,您必须在其线程中启动和停止计时器;无法从另一个线程启动计时器。
【讨论】:
我尝试在 run 方法中添加 exec() 但我得到 QEventLoop: Cannot be used without QApplication.【参考方案4】:您可以使用发射信号并在发射槽函数中启动计时器
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);
【讨论】:
【参考方案5】:你需要一个事件循环来拥有计时器。以下是我使用代码解决相同问题的方法:
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";
以下是其他张贴者均未提及的相关文档:
int QCoreApplication::exec()
进入主事件循环并等待直到 exit() 被调用。退货 设置为 exit() 的值(如果通过调用 exit(),则为 0 放弃())。需要调用这个函数来启动事件 处理。主事件循环从窗口系统接收事件 并将这些分发到应用程序小部件。让你的 应用程序执行空闲处理(即执行特殊功能 每当没有未决事件时),使用具有 0 超时的 QTimer。 可以使用更高级的空闲处理方案来实现 处理事件()。
【讨论】:
【参考方案6】:我创建了一个在 lambda 函数中调用计时器的示例:
#include <QCoreApplication>
#include <QObject>
#include <QTimer>
#include <QThread>
#include <QDebug>
#include <memory>
int main(int argc, char** argv)
QCoreApplication app(argc, argv);
QThread* thread = new QThread(&app);
QObject::connect(thread, &QThread::started, [=]()
qInfo() << "Thread started";
QTimer* timer1 = new QTimer(thread);
timer1->setInterval(100);
QObject::connect(timer1, &QTimer::timeout, [=]()
qInfo() << "Timer1 " << QThread::currentThreadId();
);
timer1->start();
);
thread->start();
QTimer timer2(&app);
QObject::connect(&timer2, &QTimer::timeout, [=]()
qInfo() << "Timer2 " << QThread::currentThreadId();
);
timer2.setInterval(100);
timer2.start();
return app.exec();
【讨论】:
以上是关于在 QThread 中启动 QTimer的主要内容,如果未能解决你的问题,请参考以下文章
在 Windows 错误中使用 QProcess 启动进程:“计时器只能用于以 QThread 启动的线程”