Reputation: 783
I have a Qt gui as QMainWindow
which has a QThread
that starts a infinite loop of the object of another class.
Here is the brief code:
Calculations.h
Class Calculations : public QObject
{
public:
//many functions!
void run();
signals:
void signalResultAvailable();
void signalECUQueryTimePassed();
private:
//many things!
}
and Calculations.cpp
void Calculations::run()
{
while (1)
{
unsigned long loopStart = millis();
//Heavy calculations per second!
unsigned long loopEnd = millis();
if ((loopEnd - loopStart) <= 1000)
{
delay(1000 - (loopEnd - LoopStart));
emit signalResultAvailable;
}
}
}
MainWindow.h
is as follows:
Class MainWindow : public QMainWindow
{
private slots:
on_button_Pause_clicked();
private:
Calculations cal;
}
MainWindow.cpp
:
MainWindow::MainWIndow() : ui(new Ui::MainWindow), cal()
{
//all the initializations...
QThread *thread_1 = new Qthread;
cal.moveToThread(thread_1);
connect(thread_1, SIGNAL(started()), &cal, SLOT(run()));
thread_1->start();
}
void MainWindow::on_buttonPause_clicked()
{
// I want to put the Thread pause HERE!
}
I want to have a Pause button on the GUI, so when the user clicks it pauses the qthread (absolutely GUI must not freeze!) and when a user clicks the Resume button it continues the calculations. I've read this topic as well but it didnt help since it uses the QThread subclass as I understood.
Can anybody please help me?
Upvotes: 3
Views: 1600
Reputation: 48196
You can instead of doing a loop make the Qthread do the looping for you using a timer:
Calculations::Calculations(QObject *parent) :QObject(parent)
{
timerId = startTimer(0);
}
Calculations::pauze(){
killTimer(timerId);
timerId = 0;
}
Calculations.restart(){
timerId = startTimer(0);
}
Calculations::timerEvent(QTimerEvent *event){
//Heavy calculations per second!
emit signalResultAvailable;
}
Both pauze
and restart
are slots connected to the clicked
signal of their respective buttons.
If you want it to run only once per second then you can pass 1000 instead of 0 to startTimer
.
Upvotes: 3
Reputation: 858
Use paused
flag with QMutex
and QWaitCondition
.
// in header
QMutex mutex;
QWaitCondition waitCondition;
// don't forget to false it in constructor
bool paused;
public slots:
// connect this slot to GUI button toggled(bool) signal
void setPaused(enable);
...
// in source
void setPaused(bool enable)
{
mutex.lock();
paused=enable;
if (!paused)
waitCondition.wakeAll();
mutex.unlock();
}
void Calculations::run()
{
while (1)
{
mutex.lock();
if (paused)
{
waitCondition.wait(&mutex);
}
mutex.unlock();
unsigned long loopStart = millis();
//Heavy calculations per second!
unsigned long loopEnd = millis();
if ((loopEnd - loopStart) <= 1000)
{
delay(1000 - (loopEnd - LoopStart));
emit signalResultAvailable;
}
}
}
UPDATE
Note, that in your implementation you can use signalResultAvailable() only in slots directly connected to the signal with Qt::DirectConnection. If you want to get it back to the main GUI thread with Qt::QueuedConnection you will never get it there. And be aware that all that you connect with Qt::DirectConnection is invoked in the caller thread, so you can not update GUI in that slot.
UPDATE 2
Well, there is something more. Look at this construct:
QThread *thread_1 = new Qthread;
cal.moveToThread(thread_1);
connect(thread_1, SIGNAL(started()), &cal, SLOT(run()));
thread_1->start();
I guess, you want the cal.run()
method to be invoked in your thread_1
. Sorry, it will be invoked in your current GUI thread. It would be invoked via Qt::AutoConnection
in the separate thread if you had declared the void run()
as public slot (maybe, it is just hidden behind the //many functions!
).
And note again. As I've mentioned, your signal emitted in the custom infinite loop in run()
will never go to other thread. Moreover, in your implementation now there is no way to leave your thread: QThread::stop()
will not help, because it stops only Qt event loop (which you'll never reach, btw, after you enter your loop) but it does not break the execution in your custom infinite loop.
Upvotes: 1