设计界面原型用定时器模拟程序运行,处理数据的程序运行时间很长,并要实时显示进度,需要使用多线程技术。运行程序出现下面的警告:
1 |
QObject::startTimer: timers cannot be started from another thread |
警告无法再另一个进程中开始定时器。在QTimer的官方文档里,有下面一段话:
1 |
In multithreaded applications, you can use <a href="http://qt-project.org/doc/qt-4.8/qtimer.html">QTimer</a> in any thread that has an event loop. To start an event loop from a non-GUI thread, use <a href="http://qt-project.org/doc/qt-4.8/qthread.html#exec">QThread::exec</a>(). Qt uses the timer‘s <a href="http://qt-project.org/doc/qt-4.8/qobject.html#thread">thread affinity</a> to determine which thread will emit the <a href="http://qt-project.org/doc/qt-4.8/qtimer.html#timeout">timeout()</a> signal. Because of this, you must start and stop the timer in its thread; it is not possible to start a timer from another thread. |
指出必须在同一个线程里开始和停止定时器,也就是只有在创建定时器的线程里才能接受到timeout()信号。我的代码中使用QObject::moveToThread()方法实现多线程
1 2 3 4 5 6 7 8 |
work_thread = new QThread(); local_dir_data_importer_service = new LocalDirDataImporterService(); //TODO:? parent local_dir_data_importer_service->setImportDataModel(import_model); local_dir_data_importer_service->moveToThread(work_thread); work_thread->start(); connect(work_thread,SIGNAL(started()),local_dir_data_importer_service,SLOT(excuteImport())); |
在LocalDirDataImporterService构造函数中初始化定时器
1 2 3 4 5 6 7 |
LocalDirDataImporterService::LocalDirDataImporterService(QObject *parent) : //... { //... list_timer = new QTimer(); } //... |
在LocalDirDataImporterService::excuteImport()中开启定时器
1 2 3 4 5 6 7 8 |
void LocalDirDataImporterService::excuteImport() { list_timer->setInterval(1000); list_timer->start(); this->connect(list_timer,SIGNAL(timeout()),this,SLOT(testImportItem())); } |
如上,定时器在GUI进程中初始化,无法在子工作进程中开始定时器。需要在子工作进程中初始化定时器。
1 2 3 4 5 6 7 8 9 |
void LocalDirDataImporterService::excuteImport() { list_timer = new QTimer(); list_timer->setInterval(1000); list_timer->start(); this->connect(list_timer,SIGNAL(timeout()),this,SLOT(testImportItem())); } |
这样定时器就可以正常使用了。
Stackoverflow上看到另一种方法,将定时器和工作类都移到某个子进程:
http://stackoverflow.com/questions/15835267/qthread-and-qtimer
工作类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent = 0) : QObject(parent) {} signals: void doSomething(); public slots: void trigger() { emit doSomething(); } }; |
主程序
C++
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); MainThreadObject o; QThread *thread = new QThread; Worker w; QTimer timer; timer.setInterval(1000); timer.moveToThread(thread); w.moveToThread(thread); QObject::connect(thread, SIGNAL(started()), &timer, SLOT(start())); QObject::connect(&w, SIGNAL(doSomething()), &o, SLOT(doSomething())); QObject::connect(&timer, SIGNAL(timeout()), &w, SLOT(trigger())); thread->start(); return a.exec(); } |