Multiple calls to same slot
-
i have put this code in a for loop
@
EnginioReply *reply=client->downloadUrl(query);connect(reply,SIGNAL(finished(EnginioReply*)),this,SLOT(urlDownload(EnginioReply*)));
@
this slot calls another slot which needs to executed
now what is happening is that the next call to the slot(i.e. second call to the slot mentioned in code) is being made before the execution for previous one has been completed
is it possible that i can prevent the second call to same slot to allow previous one to complete and then go forward with next one? -
Do you call the next slot through another emitted signal?
AFAIK in that case the slots are executed in sequence of signals. If there is already a signal waiting your new signal will be placed in he queue.However, a slot is nothing else that any an ordinary method of your class. The only specialty is that you can use it as slot in a connect statement. So you may call the slot method directly without the deroute through an additional signal.
-
yes the next slot is being called when another signal is emitted
i also accept that a slot is another method of class so when second signal is emitted it calls the second slot which means that control does not comes back till execution of second slot is completed
but it is not happening this way, after calling the second function before its execution is completed, control goes back to main and because of for loop on
@
EnginioReply *reply=client->downloadUrl(query);connect(reply,SIGNAL(finished(EnginioReply*)),this,SLOT(urlDownload(EnginioReply*)));
@
the whole process repeats again
-
If your objects are in the same thread they will be connected "Directly" by default. This means when it recieves the signal it will process it immediatley (and stop what it is doing, even if it is processing a previous signal)... this means it acts somewhat like an interrupt....
Usually you want things to be processed in the same order that they arrive. You can force this by using Queued connection:
@
connect(reply,SIGNAL(finished(EnginioReply*)),this,SLOT(urlDownload(EnginioReply*)), Qt::QueuedConnection);
@From what I read of your issue, this could be the problem (if they are in the same thread). If they are in different threads then Qt::QueuedConnection is default anyway.
-
i am sorry i tried as you mentioned but it does not seems to be working
let me post the code@
for(int i=0;i<2;i++)
{
query.insert("id",fileId[i]);qDebug()<<"query 1: "<<query; EnginioReply *reply=client->downloadUrl(query);
connect(reply,SIGNAL(finished(EnginioReply*)),this,SLOT(showResult(EnginioReply*)),Qt::QueuedConnection);
connect(client,SIGNAL(error(EnginioReply*)),this,SLOT(showError(EnginioReply*)));}
void MainWindow::showResult(EnginioReply *reply)
{
QString url=reply->data().value("expiringUrl").toString();
// qDebug()<<"Reply data: "<<reply->data();
QNetworkRequest request(url);m_reply=client->networkManager()->get(request); m_reply->setParent(this); connect(m_reply,SIGNAL(finished()),this,SLOT(downloadFinished()),Qt::QueuedConnection); qDebug()<<"Exiting showResult";
}
void MainWindow::downloadFinished()
{
QByteArray imageData=m_reply->readAll();
m_image.loadFromData(imageData);
qDebug()<<m_image.isNull()<<" Check for NULL";
pix[index]=QPixmap::fromImage(m_image.scaled(300,300,Qt::KeepAspectRatio,Qt::SmoothTransformation));qDebug()<<"Exiting downloadFinish"; if(index==0) { ui->label->setPixmap(pix[0]); index=1; } if(index==1) { ui->label_2->setPixmap(pix[1]); }
}
@ -
Do you have more then one instance of the objects called "reply" and "client"?
You are making the same connection to them more then once, I can't see the reason for this.
Also with the queued connection, I would use it for all of your connections, this should at least sort out any order-related issues.
Also.... where are your "emits"?, you have connected some signals but not actually emitted anything.... (or you have omitted that code?)
-
Hii..
I think Your second slots gets called due to for loop ,because loop gets executed in a very fast manner,so it forces to second call even the first not finished.
//note that -->the finish() signal emitted when the reply has finished processing. -
That kind of error/conflict would be corrected by using Queued connection :)
But still... I see lots of "connects", but no signal emits...
-
ok so i noticed my error
and i have added emit instructions but i need more advice
now if u notice i have a reply pointer
@
EnginioReply *reply=client->downloadUrl(query);
@
i need to call the slot when it finishes but it takes time to finish
so how do i delay execution of other instructions to allow it to be finished -
Sorry, your question is not quite accurate enough to understand.
When you say "need to call the slot when it finishes" can you clarify what is:
"it" - what?
"the slot" - which slot?Thanks! - also if you have fixed your code and added emit's, then please re-display your new code, probably easier to talk about it then :)
-
my apologies
by it i meant slot
each reply is connects to a slot at different points and i want those slots to be called after reply has received all the data
in this case
@
EnginioReply *reply=client->downloadUrl(query);connect(reply,SIGNAL(finished(EnginioReply*)),this,SLOT(showResult(EnginioReply*)),Qt::QueuedConnect
@ -
and as you asked for the displaying the code where i have added emit signals
@
for(int i=0;i<2;i++)
{
query.insert("id",fileId[i]);qDebug()<<"query 1: "<<query; EnginioReply *reply=client->downloadUrl(query); if(reply->isFinished()) { qDebug()<<"Check for reply->data()"<<reply->data().isEmpty(); emit reply->finished(reply); connect(reply,SIGNAL(finished(EnginioReply*)),this,SLOT(showResult(EnginioReply*)),Qt::QueuedConnection); connect(client,SIGNAL(error(EnginioReply*)),this,SLOT(showError(EnginioReply*))); }
}
void MainWindow::showResult(EnginioReply *reply)
{
QString url=reply->data().value("expiringUrl").toString();
// qDebug()<<"Reply data: "<<reply->data();
QNetworkRequest request(url);m_reply=client->networkManager()->get(request); m_reply->setParent(this); if(m_reply->isFinished()) { emit m_reply->finished(); connect(m_reply,SIGNAL(finished()),this,SLOT(downloadFinished()),Qt::QueuedConnection); } qDebug()<<"Exiting showResult";
}
@
-
ok, I think you have some issues with the way you are trying to use slots / signals.
I would really recommend re-reading the Qt slots and signals chapter - its not very long and is good reading :)
Your code could work by luck, but probably won't work at all. This is the way slots/signals should be done:
Define a signal in an object
Define a slot in an object
Use connect() to connect an existing signal to an existing slot
Add code to emit a signal (this can only be done AFTER the connection is made).
In your code you are doing an emit before you have connected the signal to a slot!, this means the emit will be ignored (not handled/consumed by any objects at the time of emit).
Connection must be done first so:
@
// First connect the objects
connect(reply,SIGNAL(finished(EnginioReply*)),this,SLOT(showResult(EnginioReply*)),Qt::QueuedConnection);// Now emit a signal over the connection we just made.
emit reply->finished(reply);
@But even this looks a bit wrong. The signal should really come from within the object itsself, such that some code within object reply should send out the emit:
@
// This code is somewhere within "reply"
emit finished();
@ -
Ok
I actually noticed something
I am trying to download data from enginio(the cloud server)
now data is taking a lot of time, a few milliseconds but it is long enough so that the data is not stored in reply before control starts executing further instructions
so i am at present also looking for a solution to pause execution of further commands till data is entered into reply -
You want to wait until you get the data before you go around the loop again?
Well, there are generally two methods of waiting:
- polling - keep looking at the result until it is finished. A very crude way to do this is loop until some check == true with a 1ms sleep in there so that it does not tie up the processor.
- Event-driven / separate threads. you make each request in a different thread and start them off. Once they complete they send a message back (via slot/signal) and then you move on to the next item.
the second method is the preferred one, but the first method is easier to apply to your code. But really, when you get a chance, you should try to implement the slot/signals correctly - this will help with later design, its a bit messy at the moment and it is limiting your options :(
-
i think you are right ill start by reading the signal/slot chapter
then ill come back to you if i face any problem -
its a good plan! :)