waiting for a signal - qt

I am working on an application which uploads the content of the file to server.
To upload the file to server I am using ‘QNetworkAccessManager’ class. Since it works as asynchronous way, I changed it to work as synchronous way by using QEventLoop.
Class FileTransfer
{
Public :
QNetworkAccessManager mNetworkManager;
Void Upload(QNetworkRequest request, QIODevice *data)
{
responce = mNetworkManager.put(request, data);
EventLoop.exec();
ReadResponce(responce);
}
Void Stop()
{
responce ->close();
}
}
In my sample application I have 2 windows. 1st to select the files and 2nd to show the progress.
When user click on upload button in the first window, the 2nd window will be displayed and then I create the FileTransfer object and start uploading.
While uploading the file if user closes the form then in the destructor of the window I call the stop of ‘FileTransfer’ after that I delete the ‘FileTransfer’ object.
But here the Upload() function is not yet completed so it will crash.
Please help me to:
How to wait in 'stop()' function until the Upload() function is completed

From what I can see from your code, you're executing a QEventLoop but you're not actually connecting its "quit" slot to any signal. Take the below as an example, login is a QHttp - and the code is taken from something different - but the principle applies.
/* Create the QEventLoop */
QEventLoop pause;
/* connect the QHttp.requestFinished() Signal to the QEventLoop.quit() Slot */
connect(&login, SIGNAL(requestFinished( int, bool )), &pause, SLOT(quit()));
/* The code that will run during the QEventLoop */
login.request(header,&logmein,&result);
/* Execute the QEventLoop - it will quit when the above finished due to the connect() */
pause.exec();
This could be applied to your code, if I'm not mistaken, like this...
/* connect the signal to the relevant slot */
connect(&mNetworkManager, SIGNAL(finished( QNetworkReply )), &EventLoop, SLOT(quit()));
/* Execute the code that will run during QEventLoop */
responce = mNetworkManager.put(request, data);
/* Execute the QEventLoop */
EventLoop.exec();
Apologies if I've mistaken your query! I'm only getting to grips with qt again after a break, but I believe this is what you mean! Good luck!

I think you need to add something like that in your upload function:
if (upf->openFile())
{
reply = manager->post(request, upf);
connect(reply, SIGNAL(uploadProgress(qint64,qint64)), this, SIGNAL(progress(qint64,qint64)));
connect(reply, SIGNAL(finished()), this, SLOT(replyFinished()));
isInProgress = true;
emit started();
} else
{
emit finished(true, false, tr("Error: can't open file %1").arg(filename));
}
Here is the full text code: datacod-qt-tools
Hope it help.

Personally, I would recommend to not use any of these answers.
It would be sufficient to connect a countdown latch to the signal.
So you could write:
Latch latch( 1 );
QObject::connect( reply, SIGNAL(finished()),
&latch, SLOT(countDown()) );
latch.wait();
For this you would need a wrapper:
class Latch : public QObject {
Q_OBJECT
public:
Latch( uint count );
void wait();
public slots:
void countDown();
private:
gcl::countdown_latch _latch;
};

Related

QTimer activeChanged signal

In the documentation of QTimer there is a Properties-section, containing the active-property.
This made me believe, there might be something like a activeChanged-signal, I could connect to.
For IMHO unapparent reasons
QObject::connect(m_timer, &QTimer::activeChanged, this, &MyObject::mySlot);
failes, stating activeChanged is no member of QTimer.
Basically, I want to do something, when the timer gets initially started (so not on restart) or finally stopped. When the signal activeChanged does not exist, has anyone knowledge:
Why it is a property at all?
If there are some other signals to connect to, to do this?
Any way to hook in, and do something when the timer is started or stopped?
test in main.cpp
QTimer* tim = new QTimer;
QObject::connect(tim, &QTimer::activeChanged, qApp, [tim](){qDebug() << "Active changed" << tim->isActive(); });
tim->start(40000); // I want to get a signal
tim->start(100); // I don't want to get a signal
tim->stop(); // I want to get a signal
Create your own timer class and encapsulate QTimer:
class Timer : public QObject
{
Q_OBJECT
QTimer m_timer;
public:
Timer ()
{
connect(&m_timer, &QTimer::timeout, this, &Timer::timeout);
}
void start(int msec)
{
if (m_timer.isActive())
{
// Restart detected -> block signal
m_timer.blockSignals(true);
m_timer.start(msec);
m_timer.blockSignals(false);
}
else
{
m_timer.start(msec);
}
}
}
Since the class Timer has the full control and knowledge of the QTimer, you can have any apparent behavior you want.

Qt widget element doesn't want to hide

In my Qt application after pressing button I want to hide that button and start quite long process. While this process is running PushButton shouldn't be visible but it seems to be waiting for process being executed and after that hide button. It looks like QWidget is refreshing after end of PushButton slot function. Here's my simplified code:
void MainWindow::on_pushButton_clicked()
{
ui->progressBar->setVisible(true);
ui->pushButton->setVisible(false);
while(x<1000000) x++; //e.g of my long time function
}
When that function (on_pushButton_clicked() -> generated by mouse->go to slot) ends up my "view" is updated and button dissappear.
Is there any function to refresh my widget or maybe I forgot about sth?
Thanks in advance
Changes to the gui aren't shown until the program has a chance to redraw itself which won't happen until you return.
you'll need to defer the execution of the code somehow:
void MainWindow::on_pushButton_clicked()
{
ui->progressBar->setVisible(true);
ui->pushButton->setVisible(false);
QMetaObject::invokeMethod(this, &MainWindow::longFunction, Qt::QueuedConnection);
}
void MainWindow::longFunction()
{
while(x<1000000) x++; //e.g of my long time function
}
This returns to the event loop and then runs the longFunction but it will still block on and the progress bar won't show any updates until it is done.
To fix that you will either need to move the execution to a new thread or split the function up in shorter parts and invoke them in sequence with QMetaObject::invokeMethod and a QueuedConnection.
In order for the button to change state, it needs to return to process events in the event loop.
You could call QApplication::processEvents before the while loop in order to fix this, though it would be better to return to the event loop naturally, before you start the long-time function, by invoking the function as a QueuedConnection.
Alternatively, the better method would be to run the function in a separate thread, which will enable your GUI to remain active during the processing of the 'long function'
Start by creating an object to encapsulate the function that will do the work:-
class Worker : public QObject {
Q_OBJECT
public:
Worker();
~Worker();
public slots:
void process(); // This is where your long function will process
signals:
void finished();
void error(QString err);
};
void Worker::process()
{
while(x<1000000) x++; //e.g of my long time function
emit finished();
}
Create a new thread and start it when the button is clicked
void MainWindow::on_pushButton_clicked()
{
// change button visibility
ui->progressBar->setVisible(true);
ui->pushButton->setVisible(false);
// create the new thread and start the long function
QThread* thread = new QThread;
Worker* worker = new Worker();
worker->moveToThread(thread);
connect(worker, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), worker, SLOT(process()));
//ensure the objects are cleared up when the work is done
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
//start the thread and the long function processing
thread->start();
}

How can I solve the problem of (Incompatible sender/receiver arguments)?

Here is the code where I use CONNECT.I use it to go to the slot slotReadyRead where i can read the content the reply.
But I have a message while debugging or running the program which is
QObject::connect: Incompatible sender/receiver arguments
QNetworkReplyImpl::readyRead() --> MainWindow::slotReadyRead(QNetworkReply*)
.cpp
void MainWindow::on_pushButton_clicked()
{
QNetworkAccessManager* manager = new QNetworkAccessManager(this);
QNetworkRequest request;
request.setUrl(QUrl("http://lascivio.co/mobile/get.php?name=marwa"));
QNetworkReply *reply = manager->get(request);
connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead(QNetworkReply*)));
}
void MainWindow::slotReadyRead(QNetworkReply* reply)
{
QByteArray b (reply->readAll());
QString s(b);
ui->lineEdit->setText(s);
}
.h
public slots:
void slotReadyRead(QNetworkReply* reply);
The slot needs to have a signature compatible with the signal. So either define it as:
void slotReadyRead();
Or make the reply optional:
void slotReadyRead(QNetworkReply* reply = null);
You cannot force a plug into a socket, if it is not meant to be. I see two options:
Make reply a member of MainWindow (the quick and dirty solution)
Create a new class that will have a QNetworkReply* as a member and a slot to process the data of the reply, when it is ready.
BTW: I think you want to connect(reply, SIGNAL(finished()), this, SLOT(slotProcessReply()) (documentation). And here is the HTTP example from the Qt example collection! Have a look at network/http/httpwindow.h and network/http/httpwindow.cpp

How to delete a QProcess instance correctly?

I have a class looking like this:
class FakeRunner : public QObject
{
Q_OBJECT
private:
QProcess* proc;
public:
FakeRunner();
int run()
{
if (proc)
return -1;
proc = new QProcess();
QStringList args;
QString programName = "fake.exe";
connect(comp, SIGNAL(started()), this, SLOT(procStarted()));
connect(comp, SIGNAL(error(QProcess::ProcessError)), this,
SLOT(procError(QProcess::ProcessError)));
connect(comp, SIGNAL(finished(int, QProcess::ExitStatus)), this,
SLOT(procFinished(int, QProcess::ExitStatus)));
proc->start(programName, args);
return 0;
};
private slots:
void procStarted() {};
void procFinished(int, QProcess::ExitStatus) {};
void procError(QProcess::ProcessError);
}
Since "fake.exe" does not exist on my system, proc emits the error() signal. If I handle it like following, my program crashes:
void FakeRunner::procError(QProcess::ProcessError rc)
{
delete proc;
proc = 0;
}
It works well, though, if I don't delete the pointer. So, the question is how (and when) should I delete the pointer to QProcess? I believe I have to delete it to avoid a memory leak. FakeRunner::run() can be invoked many times, so the leak, if there is one, will grow.
Thanks!
You can't delete QObject instance inside slot which is connected to a signal in this instance using normal delete operator. This is due to the fact that if signal and slot connected using direct connection then the slot actually called from the signal implementation made by moc. This is like attempt to delete this; from inside the member of a class. There is a solution QObject::deleteLater(). Object will be deleted by Qt event loop inside events processing function. So you need to call proc->deleteLater() in your case.
And you don't need to disconnect signal from slot since Qt do it automatically when QObject is deleted.

QT EventTransition implementation

I am trying to build an QT State Maschine. I have some States, and for those States i need Transition that alter the Graphics on my gui.
The Problem i having and the only reason i am asking, i am Stuck and Point 1.
The compiler cant identifie the QTEventTransition. I have QT 4.6 wroking with QT Creator on Windows.
The compiler does not find Header #include < QtEventTransition >
This is what i did i never did this bevor but i think it should be correct, I have A Header File where i have my Transitions Declareted like this:
class validateBoatTransition : public QtEventTransition
{
public:
validateBoatTransition(Widget *widget,ServerSkeleton* server);
protected:
bool eventTest(QEvent *e);
void onTransition(QEvent *);
private:
Chart* ourChart;
Message current;
BarelySocket* myBarelySocket;
};
Than i have my Cpp File where i have this:
validateBoatTransition::validateBoatTransition(Widget *widget,ServerSkeleton* server)
{
}
void validateBoatTransition::onTransition(QEvent *e)
{
/*
My Logik should go here
*/
}
What i want is that if the Transition is activated by an Button (clicked) it should fire this transition!
I searched the net, but cant find an solution. Can i do that? I should i think.
Yours Thomas
Maybe you should take a look to signals/slot mechanism. I think this is what you need to achieve what you want.
Make your onTransition function a slot instead of an event handler and connect it to the signal clicked of the button.
class validateBoatTransition : public QtEventTransition
{
...
public slots:
void onTransition();
...
}
Somewhere in your code, connect the button to the slot:
QObject::connect(myButton, signal(clicked()), myValidateBoatTransition, slot(onTransition());
Each time the button will be clicked the execution will go through the onTransition function.
I think you're trying to use wrong classes/mechanisms to achieve your goals. If I understand you correctly, you have some GUI and after clicking some button you want to validate some stuff and if this validation is successful the state machine should change it's state. I'd write it this way:
Create some class to handle validation:
class BoatValidator : public QObject
{
Q_OBJECT
// boring stuff like constructor, etc.
public slots:
void validate()
{
if ( /*your validation logic goes here*/ ) {
emit boatTransition();
}
}
signals:
void boatTransition(); // emitted if validation is succesful
};
Then you connect your QPushButton::clicked() to BoatValidator::validate() and use BoatValidator::boatTransition() signal to drive the state machine:
QStateMachine machine;
QState *state1 = new QState(&machine);
QState *state2 = new QState(&machine);
// more state machine setup
// connect validator and button
QPushButton button;
BoatValidator validator;
connect(&button, SIGNAL(clicked()), &validator, SLOT(validate()));
// use validator to change states
state1->addTransition(&validator, SIGNAL(boatTransition()), state2);
Generally I'd use signal to drive state machine, unless some transitions are obviously event driven (for example some QEvent::Enter/QEvent::Leave on GUI widgets, etc.).
What i wanted to do is build a Qt State Machine. The Problem was that i could not trigger my own Transitions (let alone with my own Events). The answers given are good but would lead to a messy code. Why should i use a QT State Machine if i could not use the QT Transitions?
The First Problem above is solved, if you create a new Project. QT Creater is very annoying.
But here now my solution , may it help others.
First my State:
class ServerState : public QState
{
Q_OBJECT
public:
ServerState(QPushButton * pushButton);
~ServerState();
public slots:
void buttonWasClicked();
protected:
void onEntry(QEvent *e);
void onExit(QEvent *e);
private:
QPushButton * pushButton;
};
Normal, but you see i added an Slot. This slot enables me to connect a bottom signal or a Widget Mouse Press Signal to it !
Like this:
QStateMachine *machine = new QStateMachine(this);
ServerState *s1 = new ServerState(connectButton);
connect(connectButton, SIGNAL(clicked()), s1, SLOT(buttonWasClicked()));
machine->addState(s1);
s1->addTransition(connectTransition);
all i needed to to is now fire a declared Event like this one :
#define RegisterToServerEventIndex User+5
class ConnectToServerEvent : public QEvent
{
public:
ConnectToServerEvent() : QEvent(QEvent::Type(QEvent::ConnectToServerEventIndex))
{}
};
when the slot was called:
void ServerState::buttonWasClicked()
{
this->machine()->postEvent(new ConnectToServerEvent());
qDebug("ServerState::buttonWasClicked");
}
The QT State Machine would now call all the Transitions , link with this state:
ConnectToServerTransition::ConnectToServerTransition(QPushButton * pushButtonB,ServerSkeleton* serverSkeleton)
{
this->pushButtonB = pushButtonB;
this->pushButtonB->hide();
this->serverSkeleton = serverSkeleton;
qDebug("ConnectToServerTransition::ConnectToServerTransition");
}
bool ConnectToServerTransition::eventTest(QEvent *e)
{
return (e->type() == QEvent::ConnectToServerEventIndex);
}
void ConnectToServerTransition::onTransition(QEvent *e)
{
if (true == this->serverSkeleton->initalisieren())
{
this->pushButtonB->show();
}else{
qDebug("Conection to Server faild");
}
emit kill();
return;
}
Whats so great that i dare to post?
Well first you can link a Qt SM to a widget where a mouse press event , or somthing else, is called and process the raw data to a an level you need later in your program. All you then need to do is, to emit the singal:
void Widget::mousePressEvent(QMouseEvent *event){
Coordinates current;
current.line = 0;
current.row = A;
current.row = (Row) (event->x() / 30); // 30 = breite von einen Feld
current.line = event->y() / 30; // 30 = länge von einen Feld
emit this->clicked(current);
return;
}
Then this enhenced information (current) is passed to the slot at my state, where i chose to call the correct transition that does the work. You could link more transitions to it, if you need it.
But most importend you dont need to reprogramm the Transition, a think i realy disliked.
Thank you for your help , i could not done it alone.

Resources