Bonjour à tous,
Je débute actuellement dans l'utilisation des threads avec Qt (et en général).
J'ai donc mis en place un petit projet de test en m'inspirant des divers recommandations de la doc Qt et des forums.
J'essaye d'utiliser la solution utilisant QObject::moveToThread() plutôt que d'hériter de QThread. Cette dernière solution ne permettant pas d'utiliser les signaux/slots .
J'ai donc implémenté une class "Worker" dont le rôle sera de traiter des données. J'ai ajouter deux slots cancel() et togglePause(), qui je connect directement au signal clicked() des mes boutons (ui->m_btStop et ui->m_btPause).
Le problème étant que ces deux slots ne sont jamais appelé, et je ne comprend pas pourquoi. Si quelqu'un peux m'éclairer, ca serait vraiment sympa.
Voici mon code :
worker.h
worker.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 #ifndef WORKER_H #define WORKER_H #include <QObject> #include <QMutex> #include <QWaitCondition> #include "data.h" class Worker : public QObject { Q_OBJECT public: explicit Worker(QObject *parent = 0); signals: void maxProgressRangeChanged(int maxRange); void progressValueChanged(int value); void progressTextChanged(const QString &text); void finished(); void resultReady(const Data &result); public slots: void cancel(); void togglePaused(); void startWork(const QStringList &list); public: bool isPaused(); bool isRunning(); private: QMutex m_sync; QWaitCondition m_pauseCond; QWaitCondition m_1secCond; volatile bool m_pause; volatile bool m_stop; bool m_isRunning; }; #endif // WORKER_H
MainWindow.h
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 #include <QStringList> #include <QTime> #include "worker.h" Worker::Worker(QObject *parent) : QObject(parent) { m_pause = false; m_stop = false; m_isRunning = false; } //Never called - Why ? void Worker::cancel() { m_sync.lock(); m_stop = true; m_sync.unlock(); } //Never called - Why ? void Worker::togglePaused() { m_sync.lock(); m_pause = !m_pause; if(!m_pause) m_pauseCond.wakeAll(); m_sync.unlock(); } void Worker::startWork(const QStringList &list) { m_sync.lock(); m_pause = false; m_stop = false; m_isRunning = true; m_sync.unlock(); int counter = 0; QStringList internalList = list; emit maxProgressRangeChanged(list.size()); emit progressValueChanged(0); emit progressTextChanged(tr("Starting....")); foreach(QString element, internalList){ //Check pause state //================= m_sync.lock(); if(m_pause) m_pauseCond.wait(&m_sync); // in this place, your thread will stop to execute until someone calls resume if(m_stop) { m_isRunning = false; m_sync.unlock(); emit finished(); break; } m_sync.unlock(); //Data process //================= emit progressValueChanged(++counter); emit progressTextChanged(tr("Processing \"%1\"").arg(element)); Data data(element.toUpper(), counter); //Wait 200 ms to make the process long (this is a test), //this can simulate a slow communication, waiting on a hardware, etc.. QTime t; t.start(); while(t.elapsed() < 200){} //send the data result emit resultReady(data); } m_sync.lock(); m_pause = false; m_stop = false; m_isRunning = false; m_sync.unlock(); emit finished(); } bool Worker::isPaused() { m_sync.lock(); bool res = m_pause; m_sync.unlock(); return res; } bool Worker::isRunning() { m_sync.lock(); bool res = m_isRunning; m_sync.unlock(); return res; }
MainWindow.cpp
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include "data.h" class Worker; class QThread; namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); public slots: void onBtStart(); void onBtPause(); void onBtStop(); void dataReady(const Data &data); void onProcessFinished(); void threadStarted(); void threadFinished(); signals: void startWork(const QStringList &list); void pause(); void stop(); private: Ui::MainWindow *ui; Worker *worker; QThread *thread; }; #endif // MAINWINDOW_H
Je n'ai pas ajouté l'image de la GUI, mais c'est très simple,
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109 #include <QThread> #include "mainwindow.h" #include "ui_mainwindow.h" #include "worker.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); qRegisterMetaType<Data>(); worker = new Worker; thread = new QThread(this); ui->progressBar->setVisible(false); ui->laProcess->setVisible(false); ui->btPause->setEnabled(false); ui->btStop->setEnabled(false); ui->btStart->setEnabled(true); connect(worker, SIGNAL(maxProgressRangeChanged(int)), ui->progressBar, SLOT(setMaximum(int))); connect(worker, SIGNAL(progressTextChanged(QString)), ui->laProcess, SLOT(setText(QString))); connect(worker, SIGNAL(progressValueChanged(int)), ui->progressBar, SLOT(setValue(int))); connect(worker, SIGNAL(resultReady(Data)), this, SLOT(dataReady(Data))); connect(worker, SIGNAL(finished()), this, SLOT(onProcessFinished())); connect(thread, SIGNAL(started()), this, SLOT(threadStarted())); connect(thread, SIGNAL(finished()), this, SLOT(threadFinished())); connect(ui->btPause, SIGNAL(clicked()), worker, SLOT(togglePaused()), Qt::QueuedConnection); connect(ui->btStop, SIGNAL(clicked()), worker, SLOT(cancel()), Qt::QueuedConnection); connect(ui->btStart, SIGNAL(clicked()), this, SLOT(onBtStart())); connect(this, SIGNAL(startWork(QStringList)), worker, SLOT(startWork(QStringList))); worker->moveToThread(thread); } MainWindow::~MainWindow() { emit stop(); thread->exit(); thread->wait(); delete thread; delete ui; } void MainWindow::onBtStart() { QStringList list; thread->start(); ui->progressBar->setVisible(true); ui->laProcess->setVisible(true); //Set random data list << "Nullam" << "libero" << "at" << "sapien" << "vestibulum"; //Start processing of the data emit startWork(list); ui->btPause->setEnabled(true); ui->btStop->setEnabled(true); ui->btStart->setEnabled(false); } void MainWindow::onBtPause() { emit pause(); } void MainWindow::onBtStop() { emit stop(); } void MainWindow::dataReady(const Data &data) { Data internalData(data); ui->edLog->append(QString("Data processed : %1 --> %2") .arg(internalData.value(), 8, 10, QChar('0')) .arg(internalData.name())); } void MainWindow::onProcessFinished() { ui->edLog->append("All data has been processed ! "); ui->progressBar->setVisible(false); ui->laProcess->setVisible(false); ui->btPause->setEnabled(false); ui->btStop->setEnabled(false); ui->btStart->setEnabled(true); } void MainWindow::threadStarted() { ui->edLog->append("Thread started ! "); } void MainWindow::threadFinished() { ui->edLog->append("Thread finished ! "); }
- 3 boutons start, pause, stop.
- 1 progressBar
- 1 label (traitement en cours)
- 1 TextEdit pour afficher le log de ce qui se passe.
Je sais qu'il existe pas mal de topic sur le sujet, mais je n'ai rien trouvé répondant à mon problème ( ou peut être n'ai-je pas compris tout simplement), de plus, ceci étant ma première utilisation des thread avec Qt, j'aimerais vraiment être sûre d'avoir bien compris le sujet pour partir sur de bonne bases.
Merci d'avance
Partager