How to stop a loop in a QPushButton pressed? - qt

I have a connection with Arduino. I need to send continuously a character to serial port to handle a motor series when I press a button. So I created a QPushButton and I want when it is pressed it send this character.
But when I need to create a loop I don't know how to break it. I tried this solution
...
Class .... {
private:
bool buttonPressed = false;
}
void MainWindow::on_pulsante1_pressed()
{
buttonPressed = true;
while (buttonPressed == true)
{
connect(ui->pulsante1,SIGNAL(released()),this,SLOT(on_pulsante1_released()));
qDebug() << "pressed";
}
}
void MainWindow::on_pulsante1_released()
{
buttonPressed = false;
qDebug() << "released";
}
Where did I do wrong?

You probably want to use a QTimer for that. Also you can define the frequency that the timer fires. For example:
#include <QTimer>
..
Class .... {
private:
QTimer timer;
}
void MainWindow::MainWindow(){
// in your constructor
connect(&timer, [this]{
//
// write to serial here
//
});
}
void MainWindow::on_pulsante1_pressed()
{
qDebug() << "pressed";
timer.start(1); // run this every 1 milisecond
}
void MainWindow::on_pulsante1_released()
{
timer.stop();
qDebug() << "released";
}
}
Take a look to QTimer documentation

Related

Qt , QMutex: destroying locked mutex then app crash

I make an http operation(get,post etc...) by using QNetworkAccessManager. I run a few "get" operation in paralel. For this , I use QtConcurrent::run(this,&RestWebservice::GetHTTPData) to make multi HTTP operations.
My problem is When I close the app before HTTP operation does not complete , App is crashed.Application Output write this line QMutex: destroying locked mutex then write The program has unexpectedly finished.
I guest problem occurs in this line
void RestWebservice::get()
{
// mutex.lock();
m_networkManager.get(m_networkrequest);
// mutex.unlock();
}
But I am not sure because QtCreater Debugger is not good like VS.By the way , GetHTTPData is in different class.
MY CODE for start network Operation:(MobileOperation.cpp).For exapmle getUserAccount metod start a http operation.
void MobileOperations::getWorkOrderListT(int ekipId) {
MyGlobal::Metods metod=MyGlobal::EkipIsEmriListesi;
QString parameters="{EkipId}";
QMap<QString,QVariant> paramlist;
paramlist["EkipId"]=ekipId;
GetHTTPData(metod,parameters,paramlist);
if(m_workorder.IsSuccess==true)
{
// emit successupdatewo();
if(m_workorder.workorders.count()>0)
{
InsertWo(json.workorder->workorders);
emit processstop("İş Emri Listesi Güncellendi");
// QThread::sleep(2);
}
else
{
emit processstop(json.workorder->ReturnMessage);
}
emit successworkstart();
}
else
{
emit processstop("Bağlantı Başarısız Oldu");
}
}
void MobileOperations::getUserAccount(QString kullaniciAdi, QString sifre,bool isremember)
{
json.user=m_user;
QtConcurrent::run(this,&MobileOperations::getUserAccountT,kullaniciAdi,sifre,isremember);
// getUserAccountT(kullaniciAdi,sifre,isremember);
processstart("Baglaniyor");
}
void MobileOperations::GetHTTPData(MyGlobal::Metods MetodName, QString Parameters, QMap<QString, QVariant> paramlist)
{
try
{
parameter=new HttpRequest();
parameter->url=m_url;
parameter->metodname=MetodName;
parameter->resource=m_path;
parameter->appid=m_appid;
parameter->apppass=m_apppass;
parameter->parametersname=Parameters;
parameter->params=paramlist;
rest= new RestWebservice(parameter->GenerateHTTPQuery(),MetodName);
// json=new JSonParser();
// loop=new QEventLoop();
loop=new QEventLoop();
QObject::connect(rest,SIGNAL(sendhttpdata(QByteArray,MyGlobal::Metods)),&json,SLOT(onGetData(QByteArray,MyGlobal::Metods)));
QObject::connect(&json,SIGNAL(serilazitionCompleted()),loop,SLOT(quit()));
rest->get();
loop->exec();
}
catch(std::string &exp)
{
qDebug()<<"Sonlandırıldı";
}
}
MY CODE of classes For HTTP operatins :
#include "restwebservice.h"
#include <QJsonDocument>
#include<QJsonArray>
#include <QJsonObject>
#include<QJsonValue>
#include<QList>
#include <QThread>
RestWebservice::RestWebservice(QNetworkRequest request,
MyGlobal::Metods metod,
QObject* parent):QObject(parent),m_networkrequest(request),m_metodname(metod)
{
connect(&m_networkManager, SIGNAL(finished(QNetworkReply*)),this, SLOT(onResult(QNetworkReply*)));
// connect(&m_networkManager,SIGNAL())
}
void RestWebservice::get()
{
// mutex.lock();
m_networkManager.get(m_networkrequest);
// mutex.unlock();
}
void RestWebservice::post(QString request)
{
QByteArray requestA= request.toUtf8();
m_networkManager.post(m_networkrequest,requestA);
}
void RestWebservice::onResult(QNetworkReply* reply)
{
try
{
if (reply->error() != QNetworkReply::NoError)
{
qDebug()<<reply->error()<<":"<<reply->errorString();
MyGlobal::NetworkStatus=reply->errorString();
emit sendhttpdata(m_data,m_metodname);
return;
// throw(reply->errorString().toStdString());
}
QByteArray data = reply->readAll();
reply->deleteLater();
m_data=data;
MyGlobal::NetworkStatus="Tablolar Yüklendi";
emit sendhttpdata(m_data,m_metodname);
}
catch(std::string exp)
{
qDebug()<<"Exception:"<<QString::fromStdString(exp);
}
catch(std::exception &exp)
{
qDebug()<<"Exception:"<<QString::fromStdString(exp.what());
}
}
void RestWebservice::onError()
{
qDebug()<<"Hata VAR";
}
HttpRequest::HttpRequest(QObject *parent) :
QObject(parent)
{
}
QNetworkRequest HttpRequest::GenerateHTTPQuery()
{
// QString path="";
QString path=QString("/%1/%2/%3/%4/%5").arg(resource).arg(MyGlobal::getMetodName(metodname)).arg(appid).arg(apppass).arg(parametersname);
foreach (QString param, params.keys()) {
path.replace("{"+param+"}",params[param].toString());
}
QUrl m_url(url);
m_url.setPath(path);
m_request.setUrl(m_url);
m_request.setRawHeader("Content-Type","application/json;charset=utf-8");
// m_request.setRawHeader("SOAPAction","http://tempuri.org/IMobileClient/UserAuth");
qDebug()<<m_url.url();
return m_request;
}
QNetworkRequest HttpRequest::GenerateHTTPQueryPost()
{
// QString path="";
QString path=QString("/%1/%2").arg(resource).arg(MyGlobal::getMetodName(metodname));
QUrl m_url(url);
m_url.setPath(path);
m_request.setUrl(m_url);
m_request.setRawHeader("Content-Type","application/json;charset=utf-8");
// m_request.setRawHeader("SOAPAction","http://tempuri.org/IMobileClient/UserAuth");
qDebug()<<m_url.url();
return m_request;
}
Is you mutex a member of your class. In that case the mutex is destructed before it is unlocked (as I presume the containing class goes out of scope), which causes the message you see. The destructor of the mutex is called when the class is destructed, while the lock is held. This is a problem. Typically you will have to find a way to not block indefinitely during your network request.

QMessagebox not show text when call show()

my problem is I need to show a message ask users wait when I check network availability of other clients.My way is I have a class workerThread to do the business, before start it I create a qMessageBox. But the message only shows the title, not the content. I have no idea why, pls help :(
Here's the worker thread:
#include <QObject>
#include <QString>
#include "clientdataobj.h"
class WorkerThread : public QObject
{
Q_OBJECT
public:
explicit WorkerThread(QObject *parent = 0);
QList<ClientDataObj> listClient() const;
void setListClient(const QList<ClientDataObj> &listClient);
signals:
void finished();
void error(QString err);
void listClientPingChecked( QList <ClientDataObj> list);
public slots:
void testPing();
private:
QList <ClientDataObj> mListClient;
bool pingEachClient(QString ip);
};
implement:
#include "workerthread.h"
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
WorkerThread::WorkerThread(QObject *parent) :
QObject(parent)
{
}
void WorkerThread::testPing()
{
if (mListClient.size()==0) {
emit finished();
return;
}
else{
for(unsigned i=0;i<mListClient.size();i++){
bool result = pingEachClient(mListClient[i].ip());
if(result)
mListClient[i].setStatus(true);
else
mListClient[i].setStatus(false);
}
emit listClientPingChecked(mListClient);
}
emit finished();
}
bool WorkerThread::pingEachClient(QString ip)
{
QString pingCommand = "ping " +ip + " -c 3 | grep loss | awk ' {print $7}' > pingResult.txt";
system(qPrintable(pingCommand));
QString lossPercentTxt = readFileText("pingResult.txt") ;
lossPercentTxt.chop(1);
int lossPercent = lossPercentTxt.toInt();
if(lossPercent<10){
return true;
}
else return false;
}
QList<ClientDataObj> WorkerThread::listClient() const
{
return mListClient;
}
void WorkerThread::setListClient(const QList<ClientDataObj> &listClient)
{
mListClient = listClient;
}
How I call it in MainWindow:
on_pbSendUpdate_clicked()
{
changeModeWaitPing();
getClientOnlineList();
}
getClientOnlineList()
{
if(mListClient.size()==0){
return;
}
mpThreadPing = new QThread;
mpWorkerThread = new WorkerThread;
mpWorkerThread->setListClient(mListClient);
connectThreadPingToGui();
mpThreadPing->start();
}
changeModeWaitPing()
{
ui->pbSendUpdate->setEnabled(false);
callMsgBox("Pinging client... Pls wait!");
// callWaitDialog();
}
callMsgBox( QString text)
{
if (NULL==mMsg) {
return;
}
mMsg->setWindowTitle("INFO");
// mMsg->setAttribute(Qt::WA_DeleteOnClose);
mMsg->setWindowModality(Qt::NonModal);
mMsg->setModal(false);
QString info ="Pinging client... Pls wait!";
mMsg->setText(info);
mMsg->show();
}
connectThreadPingToGui()
{
connect(mpWorkerThread, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(mpThreadPing, SIGNAL(started()), mpWorkerThread, SLOT(testPing()));
connect(mpWorkerThread, SIGNAL(finished()), mpThreadPing, SLOT(quit()));
connect(mpWorkerThread, SIGNAL(finished()), mpWorkerThread, SLOT(deleteLater()));
connect(mpThreadPing, SIGNAL(finished()), mpThreadPing, SLOT(deleteLater()));
connect(mpWorkerThread,SIGNAL(listClientPingChecked(QList<ClientDataObj>)),this,SLOT(updateListClientOnline(QList<ClientDataObj>)));
}
updateListClientOnline(QList<ClientDataObj> list)
{
mListClientOnline = list;
mPingDone = true;
if (NULL==mMsg) {
return;
}
else{
mMsg->hide();
}
if(mpDialogWaitPing==NULL){
return;
}
else{
mpDialogWaitPing->hide();
}
launchClientListTable();
}
You create a new thread, but you don't move any objects to that thread. So your new thread does nothing. I assume you wan't mpWorkerThread to be moved to the new thread. In that case you're missing mpWorkerThread->moveToThread(mpThreadPing);

QNetworkAccessManager doesnt emit finished signal

I am trying to multiple request with QNetworkAccessManager even I connect slots QNetworkAccessManager cant emit finished() signal.
Here is the code I implemented.
void GetNetwork::getAction(QStringList *urls, QList<QByteArray> *result)
{
uint size=urls->size();
multiGetResult=result;
getUrls=urls;
setFlags();
for(uint x=0;x<size;x++)
{
int test=caluculateIndex(x);
getNAM[test]->get(QNetworkRequest(QUrl(urls->at(x))));
}
//qDebug()<<reply->readAll();
while (!waitWithFlag()) QThread::msleep(15);
delete threadFlag;
}
bool GetNetwork::setMultipleGet(uint number)
{
int diff=number-(getNAM.size()-1);
if(((getNAM.size()-1)+diff)<0)
return false;
for(int i=0;i<diff;i++)
{
getNAM.append(new QNetworkAccessManager(this));
connect(getNAM[getNAM.size()-1],SIGNAL(finished(QNetworkReply*)),this,SLOT(handleMultiRequest(QNetworkReply*)));
}
for(int i=diff;i<0;i++)
{
disconnect(getNAM[getNAM.size()-1],SIGNAL(finished(QNetworkReply*)),this,SLOT(handleMultiRequest(QNetworkReply*)));
delete getNAM[getNAM.size()-1];
getNAM.remove(getNAM.size()-1);
}
return true;
}
void GetNetwork::handleMultiRequest(QNetworkReply * reply)
{
int index=getUrls->indexOf(reply->url().toString());
if(reply->error()!=QNetworkReply::NoError||index==-1)
{
QString error=QString("Network Error file:%1 line:%2 error:%3")
.arg(__FILE__)
.arg(__LINE__)
.arg(reply->errorString());
emit errorOccured(error);
return;
}
multiGetResult->insert(index,reply->readAll());
threadFlag[index]=true;
}
What's wrong in these codes? I cant figure it out.
Thank you.
First of all you don't need a separate thread for QNetworkAccessManager as it internally runs in a separate thread (asynchronous) since Qt 4.8.1.
Secondly you are only connecting the last instance of QNetworkAccessManager with a finished slot, instead of doing that, connect each instance of QNetworkAccessManager with handleMultiRequest Slot and keep increasing the count whenever the slot is invoked. You don't need sleep and all that stuff, it is all event driven.
So,
void GetNetwork::handleMultiRequest(QNetworkReply * reply)
{
int index=getUrls->indexOf(reply->url().toString());
if(reply->error()!=QNetworkReply::NoError||index==-1)
{
QString error=QString("Network Error file:%1 line:%2 error:%3")
.arg(__FILE__)
.arg(__LINE__)
.arg(reply->errorString());
emit errorOccured(error);
return;
}
count++;
if(count == num_get_requests)
{
emit
allDone()
}
}
and I changed fucntions like Adnan idea
void GetNetwork::handleMultiRequest(QNetworkReply * reply)
{
int index=getUrls->indexOf(reply->url().toString());
if(reply->error()!=QNetworkReply::NoError||index==-1)
{
QString error=QString("Network Error file:%1 line:%2 error:%3")
.arg(__FILE__)
.arg(__LINE__)
.arg(reply->errorString());
emit errorOccured(error);
return;
}
multiGetResult->insert(index,reply->readAll());
threadDoneCounter++;
if(threadDoneCounter==getUrls->size())
emit threadsAreDone();
}
and
void GetNetwork::getAction(QStringList *urls, QList<QByteArray> *result)
{
uint size=urls->size();
multiGetResult=result;
getUrls=urls;
threadDoneCounter=0;
for(uint x=0;x<size;x++)
{
int test=caluculateIndex(x);
getNAM[test]->get(QNetworkRequest(QUrl(urls->at(x))));
}
QEventLoop eLoop;
connect(this,SIGNAL(threadsAreDone()),&eLoop,SLOT(quit()));
eLoop.exec();
disconnect(this,SIGNAL(threadsAreDone()),&eLoop,SLOT(quit()));
}

How to pause and resume a Qtimer (Qt 5)

I need some help on the usage of Qtimer.
I work with Qt 5.0.2 and here my problem :
I am trying to develop a Timer, and the interface is simple :
There is just 2 button : the button "Start", to launch the timer, and the "Pause" Button, and a QtimeEdit to display the time.
This screenshot shows how it looks like : http://img834.imageshack.us/img834/1046/5ks6.png
The problem is that the pause function doesn't work. I have read all the documentation about Qtimer here : http://harmattan-dev.nokia.com/docs/library/html/qt4/qtimer.html and here : qt.developpez.com/doc/5.0-snapshot/qtimer/ , but no result.
This is the source code I have : (I put only what is needed)
// Creation of the Buttons and the time area
void MainWindow::createBottom()
{
bottom = new QWidget();
play = new QPushButton("Launch",this);
pause = new QPushButton("Pause",this);
play->setDisabled(false);
pause->setDisabled(true);
timeEdit = new QTimeEdit(this);
timeEdit->setDisplayFormat("mm:ss");
layout->addWidget(play);
layout->addWidget(pause);
layout->addWidget(timeEdit );
bottom->setLayout(layout);
connect(play, SIGNAL(clicked()), this, SLOT(startSimulation()));
connect(pause, SIGNAL(clicked()), this, SLOT(pauseSimulation()));
}
// to resume the timer where is was stopped
void MainWindow::resumeSimulation()
{
timer->blockSignals( false );
pause->setText("Pause");
pause->disconnect(SIGNAL(clicked()));
connect(pause, SIGNAL(clicked()), this, SLOT(pauseSimulation()));
paused = false;
timer->start();
int timeOfPause = time->restart();
int timeTotal = timeOfPause + timeElapsed;
time->addMSecs(-timeTotal);
}
// to Start the timer
void MainWindow::pauseSimulation()
{
timer->blockSignals(true);
pause->setText("Resume");
timer->stop();
play->setDisabled(false);
//pause->setDisabled(true);
pause->disconnect(SIGNAL(clicked()));
connect(pause, SIGNAL(clicked()), this, SLOT(resumeSimulation()));
paused = true;
}
// to Start the timer from zero.
void MainWindow::startSimulation()
{
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this , SLOT(updateTime()));
timer->start(500);
play->setDisabled(true);
pause->setDisabled(false);
}
void MainWindow::updateTime()
{
if(time == NULL)
{
time = new QTime(0,0,0,0);
time->start();
}
//timeEdit->setTime(QTime::fromS(time->elapsed()));
//time = &(time->addMSecs(1000));
if(hasRestart)
{
time->restart();
time->addMSecs(-timeElapsed);
hasRestart = false;
}
else
{
timeElapsed =+ time->elapsed();
}
int seconds = 0;
int minutes = 0;
int hours = 0;
if(!paused)
{
seconds = (timeElapsed/1000)%60;
minutes = (timeElapsed/60000)%60;
hours = (timeElapsed/3600000)%24;
std::cout << "Test : " << hours << ":" << minutes << ":" << seconds << std::endl;
timeEdit->setTime(QTime(0,minutes,seconds,0));
timeEdit->update();
}
}
When I push the Start button, the timer starts well, but when I push "Pause" it only pause it on the graphic interface, but when I resume, it shows the present time as if it hadn't paused.
For instance :
I start.
I pause at 00:05. It blocks apparently the timer.
I wait for 10 seconds. I resume the timer, it shows 00:15 instead of 00:06
How could I fix that ?
Thank you !
EDIT : Thanks Kuba Ober, but could you explain me the code you posted please ?
How does the pause work ?
Below is a SSCCE, tested under both Qt 4.8 and 5.1.
//main.cpp
#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QElapsedTimer>
#include <QTime>
class Window : public QWidget {
Q_OBJECT
int m_timerId;
qint64 m_accumulator;
QLabel *m_label;
QElapsedTimer m_timer;
Q_SLOT void on_restart_clicked() {
m_accumulator = 0;
m_timer.restart();
if (m_timerId == -1) m_timerId = startTimer(50);
}
Q_SLOT void on_pause_clicked() {
if (m_timer.isValid()) {
m_accumulator += m_timer.elapsed();
m_timer.invalidate();
} else {
m_timer.restart();
m_timerId = startTimer(50);
}
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_timerId) {
QWidget::timerEvent(ev);
return;
}
QTime t(0,0);
t = t.addMSecs(m_accumulator);
if (m_timer.isValid()) {
t = t.addMSecs(m_timer.elapsed());
} else {
killTimer(m_timerId);
m_timerId = -1;
}
m_label->setText(t.toString("h:m:ss.zzz"));
}
public:
explicit Window(QWidget *parent = 0, Qt::WindowFlags f = 0) : QWidget(parent, f), m_timerId(-1) {
QVBoxLayout * l = new QVBoxLayout(this);
QPushButton * restart = new QPushButton("Start");
QPushButton * pause = new QPushButton("Pause/Resume");
restart->setObjectName("restart");
pause->setObjectName("pause");
m_label = new QLabel("--");
l->addWidget(restart);
l->addWidget(pause);
l->addWidget(m_label);
QMetaObject::connectSlotsByName(this);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
#include "main.moc"
QTime totalTime, sinceStart;
void MainWindow::createBottom()
{
bottom = new QWidget();
play = new QPushButton("Launch",this);
pause = new QPushButton("Pause",this);
play->setDisabled(false);
pause->setDisabled(true);
timeEdit = new QTimeEdit(this);
timeEdit->setDisplayFormat("mm:ss");
layout->addWidget(play);
layout->addWidget(pause);
layout->addWidget(timeEdit);
bottom->setLayout(layout);
connect(play, SIGNAL(clicked()), this, SLOT(startSimulation()));
connect(pause, SIGNAL(clicked()), this, SLOT(pauseSimulation()));
connect(this, SIGNAL(timeChanged(QTime)), timeEdit, SLOT(setTime(QTime)));
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this , SLOT(updateTime()));
}
void MainWindow::updateTime() {
emit timeChanged(totalTime.addMSecs(sinceStart.elpased()));
}
void MainWindow::resumeSimulation() {
sinceStart.restart();
timer->start();
}
void MainWindow::pauseSimulation() {
timer->stop();
totalTime = totalTime.addMSecs(sinceStart.restart());
emit timeChanged(totalTime);
}
I made a Timer class for the start, stop, pause and resume
class MyTimer
{
public:
MyTimer();
QTime m_qtime;
int m_accumulator;
void start();
int stop();
void pause();
void resume();
};
MyTimer::MyTimer()
:m_accumulator(0), m_qtime(QTime())
{
}
void MyTimer::start()
{
m_qtime.start();
m_accumulator = 0;
}
int MyTimer::stop()
{
if(!m_qtime.isNull())
{
int l_elapsedTime = m_qtime.elapsed();
m_accumulator += l_elapsedTime;
}
m_qtime = QTime();
return m_accumulator;
}
void MyTimer::pause()
{
if(!m_qtime.isNull())
{
int l_elapsedTime = m_qtime.elapsed();
m_accumulator += l_elapsedTime;
}
}
void MyTimer::resume()
{
if(!m_qtime.isNull())
{
m_qtime.restart();
}
}

Dequeue always fails, queue is always empty

I do not know what the heck is wrong with my code that it never Dequeus the queue, instead isEmpty always meets true.
class ConcurrentQueue
{
private:
QQueue<QByteArray> dataStore;
public:
void Enqueue(QByteArray value);
QByteArray Dequeue();
bool isEmpty();
private:
QMutex mutex;
};
void ConcurrentQueue::Enqueue(QByteArray value)
{
qDebug() << dataStore.length();
mutex.lock();
dataStore.enqueue(value);
mutex.unlock();
qDebug() << dataStore.length();
}
QByteArray ConcurrentQueue::Dequeue()
{
// mutex.lock();
// return dataStore.dequeue();
// mutex.unlock();
QByteArray tmp;
mutex.lock();
if(!dataStore.isEmpty())
{
tmp = dataStore.dequeue();
}
mutex.unlock();
return tmp;
}
bool ConcurrentQueue::isEmpty()
{
return dataStore.isEmpty();
}
next a timer is connected to a slot to Enqueu a packet every lt's say 10 milliseconds:
QByteArray built((char*)data, len) ;
//qDebug() << built.toHex();
qDebug() << "EnQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQQ";
queue.Enqueue(built);
A thread regularly checks if this queue is not empty it dequeues the queue and does something, but isEmplty always returns true
if(queue.isEmpty())
{
qDebug() << "#####################################";
return;
}
//NEVER COMES HERE
QByteArray rd15Bytes = queue.Dequeue();
here's the thread:
Write::Write()
{
}
void Write::run(){
while(1)
{
rs.writeToSerialPort(); // in this function above always isemplty is true
this->msleep(10);
}
}

Resources