QThread类的虚函数run在基类中的实现,就是调用exec函数处理事件循环。如果将某个对象移入该类所表示的子线程,且为该对象设置了信号——槽的连接,一旦信号触发,相应的槽函数将在子线程中被执行。
xxxxxxxxxx
11void QObject::moveToThread(QThread* targetThread); // 将工作对象移入子线程,工作对象中与特定信号相连接的槽函数将在子线程中被执行
调用工作对象的moveToThread方法,将其移入子线程,需要注意以下几点:
用于实例化工作对象的类,必须继承自QObject基类;
工作对象的父对象必须为空;
将targetThread参数指定为空指针,工作对象将不再与任何线程关联,其上的所有事件处理均会停止。
通过QObject类的moveToThread方法实现多线程编程的一般步骤如下:
从QObject类派生出表示工作对象的子类,并在其中定义期望在子线程中执行的槽函数;
实例化工作对象,并将某个信号与工作对象的槽函数建立连接;
实例化线程对象,通过工作对象的moveToThread方法,将其移入线程;
通过线程对象的start方法启动线程;
这时一旦信号触发,工作对象中与之相连的槽函数将在线程对象所表示的子线程中被执行。
通过QtCreator,在C:\Users\Minwei\Projects\Qt路径下,创建名为MoveTo的项目。
C:\Users\Minwei\Projects\Qt\MoveTo\movetodialog.ui:
xxxxxxxxxx
531
2<ui version="4.0">
3 <class>MoveToDialog</class>
4 <widget class="QDialog" name="MoveToDialog">
5 <property name="geometry">
6 <rect>
7 <x>0</x>
8 <y>0</y>
9 <width>93</width>
10 <height>70</height>
11 </rect>
12 </property>
13 <property name="windowTitle">
14 <string>线程</string>
15 </property>
16 <layout class="QVBoxLayout" name="m_layout">
17 <item>
18 <widget class="QPushButton" name="m_btnStart">
19 <property name="sizePolicy">
20 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
21 <horstretch>0</horstretch>
22 <verstretch>0</verstretch>
23 </sizepolicy>
24 </property>
25 <property name="text">
26 <string>启动</string>
27 </property>
28 <property name="default">
29 <bool>true</bool>
30 </property>
31 </widget>
32 </item>
33 <item>
34 <widget class="QPushButton" name="m_btnStop">
35 <property name="enabled">
36 <bool>false</bool>
37 </property>
38 <property name="sizePolicy">
39 <sizepolicy hsizetype="Preferred" vsizetype="Preferred">
40 <horstretch>0</horstretch>
41 <verstretch>0</verstretch>
42 </sizepolicy>
43 </property>
44 <property name="text">
45 <string>停止</string>
46 </property>
47 </widget>
48 </item>
49 </layout>
50 </widget>
51 <resources/>
52 <connections/>
53</ui>
C:\Users\Minwei\Projects\Qt\MoveTo\worker.h:
xxxxxxxxxx
241
2
3
4
5
6class Worker : public QObject
7{
8 Q_OBJECT
9
10public:
11 explicit Worker(unsigned long msecs, char ch, QObject* parent = nullptr);
12
13 void stop();
14
15public slots:
16 void run();
17
18private:
19 unsigned long m_msecs;
20 char m_ch;
21 bool m_stop;
22};
23
24// WORKER_H
C:\Users\Minwei\Projects\Qt\MoveTo\worker.cpp:
xxxxxxxxxx
301
2using namespace std;
3
4
5
6
7
8Worker::Worker(unsigned long msecs, char ch, QObject* parent)
9 : QObject(parent)
10 , m_msecs(msecs)
11 , m_ch(ch)
12 , m_stop(false)
13{
14}
15
16void Worker::stop()
17{
18 m_stop = true;
19}
20
21void Worker::run()
22{
23 while (!m_stop)
24 {
25 cout << m_ch << flush;
26 QThread::msleep(m_msecs);
27 }
28
29 m_stop = false;
30}
C:\Users\Minwei\Projects\Qt\MoveTo\movetodialog.h:
xxxxxxxxxx
321
2
3
4
5
6
7
8QT_BEGIN_NAMESPACE
9namespace Ui { class MoveToDialog; }
10QT_END_NAMESPACE
11
12class MoveToDialog : public QDialog
13{
14 Q_OBJECT
15
16public:
17 MoveToDialog(QWidget *parent = nullptr);
18 ~MoveToDialog();
19
20private slots:
21 void on_m_btnStart_clicked();
22 void on_m_btnStop_clicked();
23
24private:
25 Ui::MoveToDialog *ui;
26 Worker* m_worker1;
27 QThread* m_thread1;
28 Worker* m_worker2;
29 QThread* m_thread2;
30};
31
32// MOVETODIALOG_H
C:\Users\Minwei\Projects\Qt\MoveTo\movetodialog.cpp:
xxxxxxxxxx
491
2
3
4
5
6MoveToDialog::MoveToDialog(QWidget *parent)
7 : QDialog(parent)
8 , ui(new Ui::MoveToDialog)
9 , m_worker1(new Worker(500, '|'))
10 , m_thread1(new QThread(this))
11 , m_worker2(new Worker(100, '.'))
12 , m_thread2(new QThread(this))
13{
14 ui->setupUi(this);
15
16 connect(ui->m_btnStart, SIGNAL(clicked()), m_worker1, SLOT(run()));
17 m_worker1->moveToThread(m_thread1);
18 m_thread1->start();
19
20 connect(ui->m_btnStart, SIGNAL(clicked()), m_worker2, SLOT(run()));
21 m_worker2->moveToThread(m_thread2);
22 m_thread2->start();
23}
24
25MoveToDialog::~MoveToDialog()
26{
27 m_thread1->terminate();
28 m_thread1->wait();
29
30 m_thread2->terminate();
31 m_thread2->wait();
32
33 delete ui;
34}
35
36void MoveToDialog::on_m_btnStart_clicked()
37{
38 ui->m_btnStart->setEnabled(false);
39 ui->m_btnStop->setEnabled(true);
40}
41
42void MoveToDialog::on_m_btnStop_clicked()
43{
44 m_worker1->stop();
45 m_worker2->stop();
46
47 ui->m_btnStart->setEnabled(true);
48 ui->m_btnStop->setEnabled(false);
49}
运行效果如图所示: