I'm reading and plotting data from a serial port using Qt, I'm tryng to crate a timeout with QTimer class, who send in the function "lettura()", it works one time and after create a loop inside the that, there is some way to get out from that loop? I'm a beginner and i don't now how to use thread and qtimer.
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include<QSerialPort>
#include<QtDebug>
#include<QTimer>
#include <thread>
#include<QSharedPointer>
#include"qcustomplot.h"
QSerialPort *serial;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
//Timer start
timer.start();
//Set up form
ui->setupUi(this);
//Set up poerta seriale
serial= new QSerialPort(this);
serial->setPortName("COM3");
serial->setBaudRate(QSerialPort::Baud115200);
serial->setDataBits(QSerialPort::Data8);
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
serial->open(QIODevice::ReadOnly);
//Set up grafici
//Set up del grafico dell'umidità
ui->plotH->addGraph();
ui->plotH->graph(0)->setScatterStyle((QCPScatterStyle::ssCircle));
ui->plotH->graph(0)->setLineStyle(QCPGraph::lsLine);
ui->plotH->xAxis->setRange(0,8);
ui->plotH->yAxis->setRange(0,100);
ui->plotH->xAxis->setLabel("t[h]");
ui->plotH->yAxis->setLabel("H[RH%]");
//Set up del grafico della temperatura
ui->plotT->addGraph();
ui->plotT->graph(0)->setScatterStyle((QCPScatterStyle::ssCircle));
ui->plotT->graph(0)->setLineStyle(QCPGraph::lsLine);
ui->plotT->xAxis->setRange(0,8);
ui->plotT->yAxis->setRange(-20,50);
ui->plotT->xAxis->setLabel("t[h]");
ui->plotT->yAxis->setLabel("T[°C]");
//Connessione con la funzione principale
connect(serial, &QSerialPort::readyRead, this, &MainWindow::Reader);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::Reader()
{
QTimer *timer3 = new QTimer(this);
connect(timer3, &QTimer::timeout, this, QOverload<>::of(&MainWindow::lettura));
timer3->start(10000);
}
void MainWindow::PLOTTER_H()
{
ui->plotH->graph(0)->setData(vec_t, vec_H);
ui->plotH->replot();
ui->plotH->update();
}
void MainWindow::PLOTTER_T()
{
ui->plotT->graph(0)->setData(vec_t, vec_T);
ui->plotT->replot();
ui->plotT->update();
}
void MainWindow::addPoints(double HUM, double TEMP,double t)
{
vec_t.append(t);
vec_H.append(HUM);
vec_T.append(TEMP);
}
void MainWindow::Clear()
{
vec_t.clear();
vec_T.clear();
vec_H.clear();
}
void MainWindow::on_Clear_clicked()
{
Clear();
PLOTTER_H();
PLOTTER_T();
}
void MainWindow::lettura()
{
//Letura dei dati
serial->waitForReadyRead();
m_readData=serial->QSerialPort::readAll();
//Sgrossatura dei dati
inter=QString(m_readData);
QStringList firstlist2= inter.split("$");
m_readData2=firstlist2.takeFirst();
inter2=QString(m_readData2);
QStringList firstlist3= inter2.split(" ");
m_readData3=firstlist3.takeFirst();
H=m_readData3.toDouble();
QStringList firstlist4=inter2.split(" ");
m_readData4=firstlist4.takeLast();
T=m_readData4.toDouble();
//Ottenere dal timer la variabile tempo
milli=timer.elapsed();
double sec=milli/1000;
min=sec/60;
double ore=min/60;
//Creazione dei punti
addPoints(H,T,min);
//Aggiunta dei punti ai grafici
PLOTTER_H();
PLOTTER_T();
//Programma in stand-by per 5 minuti
//Sleep(10000);
// QThread::sleep(10); //300
}
First issue is:
void MainWindow::Reader()
{
QTimer *timer3 = new QTimer(this); <--- The timer is created here
connect(timer3, &QTimer::timeout, this, QOverload<>::of(&MainWindow::lettura));
timer3->start(10000);
} <-- and destroyed here.
You need to create the timer3 pointer as a member variable new it in the constructor setup the connect in the constructor, set it to singleshot most likely if you are going to use it this way. and then just call timer3->start(10000)
The other issue is what is
timer.start();
Do you already have a timer? If you do us it instead of the timer3 one
There are other issues with starting the timer on the ReadyRead call from a serial port since it will trigger every time a byte is ready and the timer->start() call will reset the timer each time. But that is a threading question.
Related
i'm quite starting OOP so i can make incredible stupid things.
Anyway.
I've got 2 cameras (or 4) witch own their tcp server for providing MJPEG video stream.
on one base computer i need to handle 2 (or 4) tcp client connections to these units.
if i just have one instance, or one camera to handle, it works. but with multiple, it fail in bad tcp connections, I my mind, the issue should be with the instanciation of 2 QTcpsocket objects.
I tried with thread, with slots, still the same, when i instanciate more than one object of my client class, the connection read nothing or auto close. I have different TCP port for different units before you tell that.
have a look on my main code sirs:
MAIN.CPP
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QDebug>
#include <QImage>
#include "streamerclient.h"
#include "camimageprovider.h"
#include "streamerthread.h"
#include "streamerthread2.h"
#include<unistd.h>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
StreamerThread clientSat1(1238,"SAT1-SNTL");clientSat1.start();
CamImageProvider *camImageProviderSat1(new CamImageProvider());
CamImageProvider *camImageProviderSat2(new CamImageProvider());
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("camImageProviderSat1",camImageProviderSat1);
engine.addImageProvider("camSat1", camImageProviderSat1);
engine.rootContext()->setContextProperty("camImageProviderSat2",camImageProviderSat2);
engine.addImageProvider("camSat2", camImageProviderSat2);
const QUrl url(u"qrc:/baseApp001/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
engine.load(url);//const QImage &)) ,Qt::DirectConnection
QObject::connect(&clientSat1, SIGNAL(newImage(QImage)),camImageProviderSat1, SLOT(updateImage(QImage)));
QObject::connect(&clientSat1, SIGNAL(newImage(QImage)),camImageProviderSat2, SLOT(updateImage(QImage)));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
CLIENT OBJECT DECLARATION
#ifndef STREAMERTHREAD_H
#define STREAMERTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include<QDebug>
#include <QObject>
#include <QTimer>
#include <QVector>
#include <QVariant>
#include <QImage>
#include <QFuture>
class StreamerThread : public QThread
{
Q_OBJECT
Q_PROPERTY(NOTIFY newImage)
public:
StreamerThread(int port,char *satName,QObject *parent=0);
qint64 newTcpDataRead();
void run();
QImage img(){return m_Image;}
private:
QTcpSocket *socket;
int socketDescriptor;
QImage m_Image;
QByteArray m_baImage; // Variable contenant l'image reçue.
bool m_quit; // Variable permettant de savoir que l'application est en cours de fermeture.
char m_satName[16];
private slots:
void slotQuit(); // Slot appelé lors de la fermeture de l'application.
signals:
void newImage(const QImage &);
};
#endif // STREAMERTHREAD_H
CLIENT OBJECT DESCRIPTION
#include "streamerthread.h"
#include<iostream>
#include<QImage>
#include<QDebug>
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/highgui.hpp>
#include<opencv2/imgproc.hpp>
char datout=0;
int m_port=0;
StreamerThread::StreamerThread(int port,char *satName,QObject *parent)
{
m_quit = 0;
m_port=port;
strcpy(m_satName,satName);
this->socketDescriptor=port;
//m_Image = QImage(640,480, QImage::Format_RGB888);//RGB32);
m_Image = QImage(1280,720, QImage::Format_RGB888);//RGB32);
}
void StreamerThread::run()
{
qInfo()<<this<<" construit pour "<<m_satName <<"d: "<<this->socketDescriptor;
//socket = new QTcpSocket();
socket = new QTcpSocket();
socket->setSocketDescriptor(this->socketDescriptor);
// socket->connectToHost("127.0.0.1", 1234);
socket->connectToHost(m_satName, m_port);
if(!socket->waitForConnected(4000))
{
qDebug()<<"error "<<socket->errorString();
}
// socket->write(new char[4]{1,2,3,4});
// QByteArray buffer;
socket->flush();
std::cout<<"HostOk"<<std::endl;
m_quit=0;
while(m_quit == 0)
{
/* if(socket->state()==QTcpSocket::UnconnectedState)
{
qDebug()<<"deconnecte";
socket->close();
//delete socket;
socket->deleteLater();
sleep(2);
delete socket;
qDebug()<<"essai de reconnecter";
socket = new QTcpSocket();
socket->connectToHost(m_satName, m_port);
// socket->connectToHost("192.168.0.20", 1234);
if(!socket->waitForConnected(3000))
{
qDebug()<<"error "<<socket->errorString();
}
// socket->write(new char[4]{1,2,3,4});
//QByteArray buffer;
socket->flush();
std::cout<<"Host-Ok"<<std::endl;
}
*/
this->newTcpDataRead();
}
}
QImage Mat2QImage(cv::Mat const& src)
{
cv::Mat temp; //make the same cv::Mat
cvtColor(src, temp,cv::COLOR_BGR2RGB); //cvtColor Makes a copt, that what i need
QImage dest((const uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
dest.bits(); //enforce deep copy, see documentation
return dest;
}
cv::Mat QImage2Mat(QImage const& src)
{
cv::Mat tmp(src.height(),src.width(),CV_8UC3,(uchar*)src.bits(),src.bytesPerLine());
cv::Mat result; //deep copy just in case (my lack of knowledge with open cv)
cvtColor(tmp, result,cv::COLOR_BGR2RGB);
return result;
}
qint64 StreamerThread::newTcpDataRead()
{
QDataStream in(socket);
in.setVersion(QDataStream::Qt_5_11);
// initialize data
QImage image;
QByteArray data;
static qint64 imageSize = 0;
QString currentSatName="";
QByteArray currentSatData;
socket->waitForReadyRead();
usleep(1000);
//le client envoie un QByteArrayavec la taille du jpeg en premier puis les datas
if ( 0 == imageSize ) {
if ( socket->bytesAvailable() < (int)sizeof(qint64) )
{
std::cout<<"error "<<std::endl;
return-1;
}
in >> imageSize;
in>>currentSatName;
in>>currentSatData;
// qInfo() << imageSize;
//std::cout<<currentSatName.toStdString()<<std::endl;
}
//le client envoie un QByteArrayavec les datas, une chaine jpeg a recoder avec cv::decode
if (socket->bytesAvailable() < imageSize ) {;}//return -2;
else
{
in>>data;
//Vers cv::Mat:
std::vector<uchar> vData(data.begin(), data.end());
cv::Mat matImg;
if(imageSize!=-1&&imageSize!=0&&data.size()>0)
{
matImg = cv::imdecode(cv::Mat(1,
imageSize,//vData.size(),
CV_8UC1,
&vData[0]), cv:: IMREAD_COLOR);
QImage image= Mat2QImage(matImg);
emit newImage(image);
}
else
{
qDebug()<<"matrice a -1";
qInfo()<<this<< " :erreur decodage tcp";
QImage image = QImage(640,480, QImage::Format_RGB888);
image.fill(QColor("red"));
socket->flush();
}
imageSize = 0;
//DATA OUT
QByteArray block;
QByteArray satData;
if(datout>=10)
{
QString satName="RATS";
satData.reserve(8);
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_11);
// initialize data
// serialize
out << qint64(0) <<satName<<satData;
out.device()->seek(0);
out << (qint64)(block.size() - sizeof(qint64)); // the size of the block to be sent
// send over TCP
qint64 written = socket->write(block);
socket->waitForBytesWritten();
datout=0;
}
datout++;
return image.sizeInBytes();
}
}
void StreamerThread::slotQuit()
{
m_quit = 1;
}
I really don't understand why it fail when i instanciate more than one client object
when it fail, it's loop here:
if ( 0 == imageSize ) {
if ( socket->bytesAvailable() < (int)sizeof(qint64) )
{
std::cout<<"error "<<std::endl;
return-1;
}
And it is the last instancied object that is running, the first created is keeping saying "error".
I really suppose it is related to socket, maybe instanciation is not done correctly.
i see that both are created with good TCP port.but, to validate my guess, i copied the
streamerthread.cpp
streamerthread.h
to a new file, a different object so:
streamerthread2.cpp
streamerthread2.h
so for the test i declare like this:
StreamerThread clientSat1(1238,"SAT1-SNTL");clientSat1.start();
StreamerThread2 clientSat2(1234,"SAT2-SNTL");clientSat2.start();
so i've one instance of 2 differents object....and it work here! stupid way of doing but it work....
I really don't want to do like this, i really want to us objects and their power.
please say me im stupid and my error is ->there<- .
many thanks all!
in Instantiation of my streamerSlot classe, i uses a static variable.
since you just have one ovbject instantiated, it seems to works.
BUT if you instantiate more than one object, the static declaration, is declared just one time...one time for every instantiations, this is why my instantiations was bad.
Hope this will help .
Regards
=====================OUTDATE=======================
I have a vector which contains threads, each thread is doing a while loop, for some reason, i need to delete the thread in the vector, to do this, i referenced this blog and write a test demo online. But when i write pthread_cancel() in Qt, it reports error: use of undeclared identifier 'pthread_cancel'. I have added LIBS += -lpthread in my .pro file and added #include <thread> in my .cpp file, this error still exists.
=====================UPDATE=====================
Afterwards, i trid to use QThread to achieve my goal. In brief, to start a qthread, i create a Worker class, then instantiate it and move it to QThread, connect &QThread::started with &Worker::process, process is the time consuming method, finnaly call thread->start();; to stop a qthread, i use a bool flag, and i store it with thread id in QMap, if the bool flag is set to false, qthread will break while loop, and emit a finished() signal and this signal will trigger &QThread::quit; to delete the qthread, i connect finished() signal with &Worker::deleteLater and &QThread::deleteLater.
The code are:
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "worker.h"
#include <QThread>
#include <QMap>
#include <QDebug>
QMap<int, bool> stateController;
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
qDebug()<<"Main UI thread id is"<<(int)QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_add_clicked()
{
int row = ui->tableWidget->rowCount();
ui->tableWidget->insertRow(row);
ui->tableWidget->setItem(row,0,new QTableWidgetItem());//hold a place for blank item, in order to uniformly determine whether its text is empty afterwards
QTableWidgetItem *ckx = new QTableWidgetItem;
ckx->setCheckState(Qt::Unchecked);
ui->tableWidget->setItem(row,1,ckx);
}
void MainWindow::on_tableWidget_cellClicked(int row, int column)
{
if(column == 1){
bool state = ui->tableWidget->item(row,1)->checkState();
if(state){
if(ui->tableWidget->item(row,0)->text().isEmpty()){//only if there is not thread id, then create the thread
QThread* thread = new QThread();
qDebug()<<"New created thread id is"<<(int)thread->currentThreadId(); //I found this thread id will equal to main ui thread id, so i use a sigal/slot to update thread id
Worker* worker = new Worker(row);
worker->moveToThread(thread);
connect( worker, &Worker::updateQThreadIDSignal, this, &MainWindow::updateQThreadID);
connect( thread, &QThread::started, worker, &Worker::process);
connect( worker, &Worker::finished, thread, &QThread::quit);
// automatically delete thread and worker object when work is done:
connect( worker, &Worker::finished, worker, &Worker::deleteLater);
connect( thread, &QThread::finished, thread, &QThread::deleteLater);
//start the thread
thread->start();
}
}else{
if(!ui->tableWidget->item(row,0)->text().isEmpty()){//only if there is already the thread, then stop it
int thread_id = ui->tableWidget->item(row,0)->text().toInt();
// qDebug()<<"get thread id is"<<thread_id;
QMutexLocker locker(&mx);
stateController[thread_id] = false;
ui->tableWidget->setItem(row,0,new QTableWidgetItem());//Because thread will be delete later, so clear its thread id
}
}
}
}
void MainWindow::on_pushButton_delete_clicked()
{
QItemSelectionModel* selectionModel = ui->tableWidget->selectionModel();
QModelIndex index = selectionModel->currentIndex();
if(index.isValid()){
int row = index.row();
if(!ui->tableWidget->item(row,0)->text().isEmpty()){//Before stop the thread, ensure it exist
int thread_id = ui->tableWidget->item(row,0)->text().toInt();
if(ui->tableWidget->item(row,1)->checkState() == Qt::Checked){
//If not stopped yet, firstly stop it
QMutexLocker locker(&mx);
stateController[thread_id] = false;
}
stateController.remove(thread_id);
}
ui->tableWidget->removeRow(row);
}
}
void MainWindow::updateQThreadID(int row, QString id)
{
ui->tableWidget->setItem(row,0,new QTableWidgetItem(QString::number(id.toInt())));
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMutex>
#include <vector>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_add_clicked();
void on_tableWidget_cellClicked(int row, int column);
void on_pushButton_delete_clicked();
public slots:
void updateQThreadID(int row, QString id);
private:
Ui::MainWindow *ui;
QMutex mx;
};
#endif // MAINWINDOW_H
worker.cpp
#include "worker.h"
#include <QThread>
#include <QDebug>
#include <QMutexLocker>
extern QMap<int, bool> stateController;
Worker::Worker(int row) : row_index(row) {
qDebug()<<"Create new worker at thread "<<(int)QThread::currentThreadId();
}
Worker::~Worker() {
qDebug()<<"Destroy the worker instance";
}
void Worker::process() {
thread_id = (int)QThread::currentThreadId();
stateController.insert(thread_id, true);
// qDebug()<<"set thread id is"<<thread_id;
emit updateQThreadIDSignal(row_index,QString("%1").arg(thread_id)); //execute once, because if delete row happen, the row index will change
while(true)
{
count++;
QThread::sleep(2);//simulate time consuming operations
qDebug()<<thread_id<<"processing"<<count;
{//life scope of locker
QMutexLocker locker(&mx);
if(!stateController[thread_id])//In every loop, determine whether it can run, if not, exit the loop
{
return;
}
}
}
emit finished();
}
worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
#include <QMutex>
class Worker : public QObject {
Q_OBJECT
public:
Worker(int row);
~Worker();
public slots:
void process();
signals:
void finished();
void updateQThreadIDSignal(int, QString);
private:
int thread_id;
int row_index;
QMutex mx;
int count = 0;
};
#endif // WORKER_H
To watch the demo video, click here.
If you have any advice, please let me know, thanks !
Even though the codes seems to work fine, but i still have a question : Why i wrote &Worker::deleteLater, but I never see the destructor of Worker is called ?
Here below are my codes on signal-slot connection demo:
Mainwindow.cpp (it receives signal data from Sender.cpp shown next)
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
status = false; //bool status
check = 0; //int check
sender = new Sender(); //Sender *sender
}
MainWindow::~MainWindow()
{
delete ui;
if(sender!=NULL)
{
delete sender;
}
}
void MainWindow::on_pushButton_clicked() //a pushbutton is created in mainwindow.ui
{
if(sender==NULL)
{
sender = new Sender();
}
if(status==false)
{
qDebug()<<"Button pressed.";
connectionStarter(); //Signal-slot connection is triggered here!
}
}
void MainWindow::connectionStarter()
{
connect(sender,SIGNAL(sendData(int)),this,SLOT(workSlot(int)),Qt::QueuedConnection);
}
void MainWindow::workSlot(int data)
{
this->data = data;
check++;
if(check!=60)
{
qDebug()<<"connected. check="<<check;
qDebug()<<"received data="<<this->data;
}
else
{
check=0;
status = true;
disconnect(sender,SIGNAL(sendData(int)),this,SLOT(workSlot(int)));
qDebug()<<"Disconnected.";
}
}
Sender.cpp (for signal generation, controlled with a QTimer object)
#include "sender.h"
Sender::Sender(QObject *parent) : QObject(parent)
{
data = 0; //data to be updated and transmitted
timer = new QTimer(this); //QTimer *timer
timer->setInterval(1000);
timer->start();
qDebug()<<"Timer started.";
connect(timer,SIGNAL(timeout()),this,SLOT(timerHandler()),Qt::DirectConnection);
}
void Sender::timerHandler()
{
data++; //int data
emit sendData(data);
qDebug()<<"Data emited.";
}
When I run the program, it has unexpectedly finished. The process was ended forcefully. Anyone can help debug my codes? Thanks!
I have a simple project on the demo of QThread using QtCreator4.5 and Qt5.7. In the project, three pushbuttons, threadA, threadB and quit, are created. My intention is to print A and B in the console when the threadA and threadB are clicked respectively, and the application is to be quitted when 'quit' is pressed.
Here is mythread.h:
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QString>
class mythread : public QThread
{
Q_OBJECT
public:
mythread();
void setMessage(const QString &message);
void stop();
protected:
void run();
private:
QString messageStr;
volatile bool stopped;
};
#endif // MYTHREAD_H
The mythread.cpp:
#include "mythread.h"
#include <iostream>
mythread::mythread()
{
stopped = false;
}
void mythread::setMessage(const QString &message)
{
messageStr = message;
}
void mythread::stop()
{
stopped = true;
}
void mythread::run()
{
while(!stopped)
std::cout<<qPrintable(messageStr);
stopped = false;
std::cout<< std::endl;
}
The mainwindow.cpp is:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_threadA_clicked()
{
mythreadA.start();
mythreadA.setMessage("A");
}
void MainWindow::on_threadB_clicked()
{
mythreadB.start();
mythreadB.setMessage("B");
}
void MainWindow::on_quit_clicked()
{
mythreadA.stop();
mythreadB.stop();
MainWindow::close();
}
When I run the project, the printed results are displayed in the Application Output of the QtCreator, not in an external prompt console. Quitting the application makes QtCreator no respond for a while, but finally restore to normal. It seems that the threads are still running when the application is quitted.
I have tested your code and there is nothing wrong with Qt Creator that is not frozen.
However, as your code is written, your threads are probably still running when you quit the application. Moreover, the private member stopped should be protected by a mutex, as volatile won't do this job.
To protect your private variable stopped with a mutex, you can use for example QMutexLocker in the following way :
void MyThread::stop() // called by the GUI Thread
{
const QMutexLocker locker(&m_mutex);
stopped = true;
}
and to read the value of the boolean :
bool MyThread::isStopped // called by run()
{
const QMutexLocker locker(&m_mutex);
return stopped;
}
Finally to ensure that the threads are properly finished when you press the quit button :
void MainWindow::on_quit_clicked()
{
mythreadA.stop();
mythreadB.stop();
myThreadA.wait();
myThreadB.wait();
this->close(); // close the main application
}
i have a problem with a small program (I am a beginner with c++ and qt).
On button press it starts a cli application with qprocess and the output should be displayed in a text field as soon as the cli app writes it to stdout or stderr.
i read that its a good idea to use signals and slots for this but it isnt working.
the compiler throws an error that in my slot getOutput() the "process" object isn't declared (C2065)
here is the code.
processgui.cpp:
#include "processgui.h"
#include "ui_processgui.h"
#include <QProcess>
processGui::processGui(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::processGui)
{
ui->setupUi(this);
}
processGui::~processGui()
{
delete ui;
}
void processGui::on_startProcess_clicked() {
QProcess *process = new QProcess(this);
QString program = "tracert";
QString arguments = "";
process->setReadChannelMode(QProcess::MergedChannels);
process->start(program, QStringList() << arguments);
process->waitForStarted();
QObject::connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(getOutput()));
}
void processGui::getOutput() {
QByteArray strdata = process->readAllStandardOutput();
ui->textLog->append(strdata);
}
processgui.h :
#ifndef PROCESSGUI_H
#define PROCESSGUI_H
#include <QMainWindow>
namespace Ui {
class processGui;
}
class processGui : public QMainWindow
{
Q_OBJECT
public:
explicit processGui(QWidget *parent = 0);
~processGui();
private slots:
void on_startProcess_clicked();
void getOutput();
private:
Ui::processGui *ui;
};
#endif // PROCESSGUI_H
thanks in advance
Move QProcess *process to your header and initialize it with process = new QProcess(this) in your constructor. That way you can access it in your slot.
QProcess *process = new QProcess(this);
is declared in:
void processGui::on_startProcess_clicked()
it's a scope problem, process is a local variable not available in the whole class.
You can access QProcess object inside a slot with sender(), like this:
void processGui::getOutput()
{
QProcess* process = qobject_cast<QProcess*>(sender());
QByteArray strdata = process->readAllStandardOutput();
}