Using QThread to try and set a clock that writes current time to a text edit box.
-
My ultimate goal is to read a temperature every so many milliseconds and display the temp with a time stamp. I do not have the thermistar yet but am trying to set up the clock. I had it displaying the times, but only after it had ran the loop that the time gather function was in, instead of every time it iterated through the loop like I was wanting it too. I am now trying to use a QThread to solve this problem, but can not get any output. Here is my code
QThread currentTimeThread.h
#ifndef CURRENTTIMETHREAD_H #define CURRENTTIMETHREAD_H #include <QThread> #include <QTime> class currentTimeThread : public QThread { Q_OBJECT public: explicit currentTimeThread(QObject *parent = 0); void run(); signals: void timeChanged(QString); public slots: }; #endif // CURRENTTIMETHREAD_H
here is my QThread cpp
#include "currenttimethread.h" #include <QtCore> #include <QTime> #include <QString> #include "noheatmode.h" currentTimeThread::currentTimeThread(QObject *parent) : QThread(parent) { } void currentTimeThread::run() { QTime time = QTime::currentTime(); QString currentTime = time.toString("hh:mm:ss:ms"); emit timeChanged(currentTime); }
here is noHeatMode.h (noHeatMode.cpp is where I want the results to display
#ifndef NOHEATMODE_H #define NOHEATMODE_H #include <QString> #include <QWidget> #include "qstring.h" #include "currenttimethread.h" namespace Ui { class noheatmode; } class noheatmode : public QWidget { Q_OBJECT public: explicit noheatmode(QWidget *parent = 0); ~noheatmode(); currentTimeThread *cTimeThread; private slots: void on_startButtonNoHeatMode_clicked(); void on_noHeatModeBack_clicked(); public slots: void setCurrentTime(); void onTimeChanged(QString); void displayCurrentTime(); private: Ui::noheatmode *ui; }; #endif // NOHEATMODE_H
And lastly noheatmode.cpp
#include "currenttimethread.h" #include <QTime> #include <QTextEdit> #include <QTimer> #include <QString> #include "currenttimethread.h" noheatmode::noheatmode(QWidget *parent) : QWidget(parent), ui(new Ui::noheatmode) { ui->setupUi(this); cTimeThread =new currentTimeThread(this); connect(cTimeThread,SIGNAL(timeChaged(QString)), this , SLOT (onTimeChanged(QString))); } noheatmode::~noheatmode() { delete ui; } void noheatmode::onTimeChanged(QString currentTime) { QString time = currentTime; ui->tempTimeNoHeatMode->setText(time); // ui->tempTimeNoHeatMode->setText(Time); } void noheatmode::on_startButtonNoHeatMode_clicked() { displayCurrentTime(); int flowTime, onTime, offTime, preHeat; int dutyCycle = 250; wiringPiSetup(); pinMode(0,OUTPUT); pinMode(2,OUTPUT); //Recieve Pre-Heat Time if(ui->preHeatBoxNoHeatMode->currentText()=="0 sec.") { preHeat = 0; } if(ui->preHeatBoxNoHeatMode->currentText()=="1 sec.") { preHeat = 1; } if(ui->preHeatBoxNoHeatMode->currentText()=="2 sec.") { preHeat = 2; } if(ui->preHeatBoxNoHeatMode->currentText()=="3 sec.") { preHeat = 3; } if(ui->preHeatBoxNoHeatMode->currentText()=="4 sec.") { preHeat = 4; } //Recieve and set flowTime if(ui->sizeBoxNoHeatMode->currentText()=="8 oz.") { flowTime = 10; } else if(ui->sizeBoxNoHeatMode->currentText()=="10 oz.") { flowTime = 20; } else if(ui->sizeBoxNoHeatMode->currentText()=="12 oz.") { flowTime = 25; } else if(ui->sizeBoxNoHeatMode->currentText()=="14 oz.") { flowTime = 35; } else if(ui->sizeBoxNoHeatMode->currentText()=="16 oz.") { flowTime = 40; } // Recieve duty cycle % and set variable dutyCycle if(ui->dutyCyclePercentageNoHeatMode->currentText()=="0%") { onTime = 0; offTime = 250; } if(ui->dutyCyclePercentageNoHeatMode->currentText()=="50%") { onTime = dutyCycle * 0.50; offTime = dutyCycle - onTime; } else if (ui->dutyCyclePercentageNoHeatMode->currentText()=="55%") { onTime = dutyCycle * 0.55; offTime = dutyCycle - onTime; } else if (ui->dutyCyclePercentageNoHeatMode->currentText()=="60%") { onTime = dutyCycle * 0.60; offTime = dutyCycle - onTime; } else if (ui->dutyCyclePercentageNoHeatMode->currentText()=="65%") { onTime = dutyCycle * 0.65; offTime = dutyCycle - onTime; } else if (ui->dutyCyclePercentageNoHeatMode->currentText()=="70%") { onTime = dutyCycle * 0.70; offTime = dutyCycle - onTime; } else if (ui->dutyCyclePercentageNoHeatMode->currentText()=="75%") { onTime = dutyCycle * 0.75; offTime = dutyCycle - onTime; } //Pre heat water digitalWrite(2,1); delay(preHeat * 1000); digitalWrite(2,0); // set zero pin LED to stay on for flowTime while(flowTime > 0) { cTimeThread->start(); digitalWrite(0,1); flowTime--; // set second pin LED to flash according to dutyCycle digitalWrite(2,1); delay(onTime); digitalWrite(2,0); delay(offTime); } digitalWrite(0,0); } void noheatmode::on_noHeatModeBack_clicked() { close(); }
Thanks
-
You should be able to do this with a QTimer as opposed to a QThread. This is probably unnecessary to go this extreme.
In your example the 'run' method from the thread exits immediately after reading the time.
void currentTimeThread::run() { QTime time = QTime::currentTime(); QString currentTime = time.toString("hh:mm:ss:ms"); emit timeChanged(currentTime); } // this version will run forever and send a signal every second with the current time. void currentTimeThread::run() { QTime time ; QString currentTime; do { time = QTime::currentTime(); currentTime = time.toString("hh:mm:ss:ms"); emit timeChanged(currentTime); this->msleep(1000); // sleep for 1 second }while (true); }
You should look into getting the time from your GUI thread when processing the data. Maybe using the tread for only reading the temperatures perhaps?
When working with a thread you should also connect the signals 'started()' and 'finished()' to monitor what it is doing. When you close the program you should also consider a way to shut down the thread if it is still running.
-
Thanks I will try that approach. I had used QTime before and it got all the times posted but would not do it in real time so tried QThread.
-
@Rondog Where do I connect the started() and finsihed() signals at? Looking in the documentation it says
void currentTimeThread::started()
but not where it goes, is it just in the .h file for the thread? -
Hi,
Currently, a thread looks like overkill for what you want to do. Using a QTimer (not QTime, QTimer) is enough. You should just write a class that does this. If you really need a thread then, use the worker object paradigm (described in QThread's documentation)
-
@SGaist I have also tried using QTimer and that will get the time in the text edit box, but only after the rest of the code has ran so it is not populating in real time. My code is.
void noheatmode::displayCurrentTime() { //Start timers to recursively get current time QTimer *timer = new QTimer(this); connect(timer, SIGNAL(timeout()), this, SLOT()); //delay set to space out time readings, can be adjusted timer->start(750); //Gets the time QTime time = QTime::currentTime(); //Converts to string with chosen format QString sTime = time.toString("hh:mm:ss:ms"); //displays current time in text edit box ui->tempTimeNoHeatMode->append(sTime); } //Set loop to run while flow time is not 0 while(flowTime > 0) { displayCurrentTime(); //set zero pin to be high while flowtime is more than 0 digitalWrite(0,1); flowTime--; // set second pin LED to flash according to dutyCycle digitalWrite(2,1); delay(onTime); digitalWrite(2,0); delay(offTime); } //turn zero pin low after flow time reaches 0 digitalWrite(0,0); }
-
Because you are still using a loop that is blocking the GUI thread
-
@cdbean04 said:
//Set loop to run while flow time is not 0 while(flowTime > 0) { ... }
Like @Sgaist said, you must not have a while loop that runs for a long time. This makes all of your GUI freeze.
When your GUI is frozen:
- Your displays will not update (that's why your time display doesn't update)
- You can't click on any buttons.
- You can't type any text.
-
Would you recommend I just use a different or shorter loop. What the loop is doing, in case I have not been clear, is turning on an led light that represents a valve opening to release a flow of water. A second led, which represents a pulse to a flow through heater, has to flash for a certain amount of milliseconds per second that the water flow led light is on. While all that is happening I also need to check the temperature of the water, and possible count pulses from a separate flow meter. To achieve all this should I can my logic and adjust my looping, or should I use Qthread? In your opinion of course.
-
You should rather take a look at the State Machine Framework. That will allow you to better handle your system.
-
@SGaist After looking through the State Machine Framework, it looks like I would have to do nested states to get everything to run independently, but at the same time. Is this correct or am thinking to complex?
-
It depends on what parts you want to model with the state machine.
-
My thoughts were to have flowTime (which is currently in the while loop, be a a state. And have the time stamp, temperature reading, and any other elements that need to run at the same time as nested state machines in the flowTime state.
Here is flowTime now// set zero pin LED to stay on for flowTime while(flowTime > 0) { digitalWrite(0,1); flowTime--; // set second pin LED to flash according to dutyCycle digitalWrite(2,1); delay(onTime); digitalWrite(2,0); delay(offTime); }
-
Aren't all these parts independent ?