设计界面原型用定时器模拟程序运行,处理数据的程序运行时间很长,并要实时显示进度,需要使用多线程技术。运行程序出现下面的警告:
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();
}
};
|
主程序
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();
}
|