How do I send text from one thread to main GUI?
-
I might have party too hard over the weekend, but this problem has me stymied.
I am working on an application that is structured similarly to the QT examples threadedfortuneserver and fortuneclient, so I am going to use them as my working example.
The question in its simplest form is how do I modify a QLabel text in the main thread from another thread which does not know about the GUI?
Specifically, this question can be demonstrated by wanting to send a QString
QString connectionMsg = "Remote connection received from: " + tcpSocket.peerAddress().toString();
from fortunethread.cpp to the main dialog window to modify the text of statusLabel in dialog.cpp?
In the sample program, fortunethread.cpp has no way of knowing anything about dialog and, as implemented in the example, cannot be modified to use signals/slots since there is no way to connect them (at least as far as I can find.)
Any thoughts will be greatly appreciated.
-
- add a signal to FortuneThread
- add the same signal to FortuneServer
- add a slot to Dialog
- emit signal in FortuneThread
- connect FortuneThread's signal to FortuneServer signal in FortuneServer
- connect FortuneServer's signal to Dialog's slot in the dialog
done, should work :-)
-
I think I followed the outline as you suggested. I get the execution time message "QObject::connect: No such signal FortuneThread::connectionMade(QString msg) in ../threadedfortuneserver/fortuneserver.cpp:78"
I used this example program with changes as follows:
Added to dialog.h:
public slots:
void setConnectionText (QString msg );Added to dialog.cpp
void Dialog::setConnectionText(QString msg) {
statusLabel->setText(msg);
}Added to fortuneserver.h
signals:
void connectionMade(QString msg);Added to fortuneserver.cpp FortuneServer::incomingConnection
connect(thread, SIGNAL(connectionMade(QString msg)), this, SIGNAL(connectionMade(QString msg)));Added to fortunethread.h
void connectionMade(QString msg);Added to fortunethread.cpp in FortuneThread::run():
QString connectionMsg = "Remote connection from: " + tcpSocket.peerAddress().toString();
emit connectionMade(connectionMsg);Had you tested your response? Did I miss something from your outline?
I'm confused by the connecting SIGNAL to SIGNAL--This seems like a very indirect way of connecting different classes. How does it work internally?
Thanks
-
Hi
Signal to signal is ok. it simply forwards a signal.It's not so odd as it seems. Default the UI part of a form/widget is private. if you want to let the outside world connect to any widget in the UI struct, then a clean way is simply to expose the signal in question via signal to signal connects internally. So outside world connects to a "repeated" signal and knows little about the actual widget. This is a decoupling design and very beneficial with apps that have long lifespans as they are more resilient to change.
However, a small error in the connect.
You included the parameter name also. should just be the type
connect(thread, SIGNAL(connectionMade(QString msg)), this, SIGNAL(connectionMade(QString msg)));
---> change to
connect(thread, SIGNAL(connectionMade(QString )), this, SIGNAL(connectionMade(QString )));and preferably check the return type
like
if (! connect(thread, SIGNAL(connectionMade(QString )), this, SIGNAL(connectionMade(QString ))) ) {
qDebug() << "connect fail";
}
or use the (not so) new compile time checking syntax
https://wiki.qt.io/New_Signal_Slot_Syntax -
Thank you, thank you, thank you. It is always a pleasure to work with someone who knows their stuff.
I had overlooked the step of connecting FortuneServer's signal to Dialog's slot in the dialog.
I added in dialog.cpp:
connect(&server, SIGNAL(connectionMade(QString)), this, SLOT(setConnectionText(QString)) );Once I put this in, it worked like a champ!
Marking it solved.
Thanks again.