Can't receive tcp message when popping up a modal dialog?
-
My goal is to receive the tcp message from the server, and execute some jobs.
But it's hard to copy all code to here...In short, I refer to the Qt example "Fortune client", make it connect to server, receive message, etc.
Just like the example :@
connect(tcpSocket, SIGNAL(readyRead() ), this, SLOT(slot_myReadMsg()) );
@And the slot_myReadMsg() :
@
void QxSpySocket::slot_myReadMsg(){
QDataStream in(connection);
in.setVersion(QDataStream::Qt_4_0);
if (blockSize == 0) {
if (connection->bytesAvailable() < (int)sizeof(quint16))
return;
in >> blockSize;
}
if (connection->bytesAvailable() < blockSize)
return;
QString msg;
in >> msg;
blockSize = 0;
QxSpy::getInstance()->slot_parseTCPMessage(msg);
}
@It works fine for a while.
But recently, I found a weird problem of Qt.When I open a modal dialog, then the server sends message to client, readyRead() never be triggered.
Why? Does it mean that when I open a modal dialog, qt will be blocked at the dialog until I click "OK" or "Cancel"?After that I've tried to create two socket, one for write, one for read.
Make one of them to listen in another thread (see Example "Blocking Fortune Client")
The thread just like this :@
void QxSocketThread::run(){
const int Timeout = 60 * 1000;while(1){
QString command = "";
while (_socket->getSocket()->bytesAvailable() < (int)sizeof(quint16)) {
if (!_socket->getSocket()->waitForReadyRead(Timeout)) {
//emit error(_socket->getSocket()->error(), _socket->getSocket()->errorString());
return;
}
}
quint16 blockSize;
QDataStream in(_socket->getSocket());
in.setVersion(QDataStream::Qt_4_0);
in >> blockSize;while (_socket->getSocket()->bytesAvailable() < blockSize) {
if (!_socket->getSocket()->waitForReadyRead(Timeout)) {
//emit error(_socket->getSocket()->error(), _socket->getSocket()->errorString());
return;
}
}
in >> command;MyCommandParser::getInstance()->parse(command);
msleep(50);
}
}
@In VC, it will output the warning : "QSocketNotifier: socket notifiers cannot be disabled from another thread"
I've read several thread about it, but none of them can tackle it.Anyone can help me??? Plz...
My opinion, I like the signal-slot approach rather than the blocking approach. -
bq. When I open a modal dialog, then the server sends message to client, readyRead() never be triggered.
Why? Does it mean that when I open a modal dialog, qt will be blocked at the dialog until I click “OK” or “Cancel”?No: opening a dialog with exec() will reenter the event loop (with all the pros/cons).
-
Thanks to Volker and peppe.
So, does it means I never could open a dialog with exec() and listen the socket message??
is there any possible implementation?It's a classical web client program. User can manipulate and the program will communicate with server in background.
But I just open a modal dialog (QFileDialog) to ask user to select a file :@
QString fileName = QFileDialog::getOpenFileName(label, "Open Image",
"C:\", "Image Files (*.png *.xpm *.jpg)");if(fileName != NULL) {
label->setText("<center>" + fileName + "</center>");
}
@Does it means that the modal window is a bad use?
thanks again.
-
Arguably, most model dialogs are a design problem from a UI point of view to begin with, so in that sense the answer to your last question is "yes".
You can open a modal dialog and still let the eventloop continue. Read up on the documentation of QDialog for tips on that. However, that will mean re-thinking your application flow, because the call to show the dialog will return immediately. The problem is, that especially for file dialogs on windows, you really want to use the static methods like you do in order to get the native file dialogs. And those are blocking by design. A bit of a catch 22, I'm afraid.
One way out could be - dare I say it? - multithreading. If you put your networking code in a thread of its own, you can have your UI code show all the modal, blocking dialogs you want and still not stop the networking thread. However, threading brings its own set of problems and can get you into trouble real fast if you're not careful what you're doing.
-
Thank you Andre.
I've tried to use multithread to tackle it before. But, as I say, When I put a socket to a thread , and make it continuously listen the tcp message, qt still shows the warning, "QSocketNotifier: socket notifiers cannot be disabled from another thread".
Here's the code snippet :
@
void QxSocketThread::run(){
const int Timeout = 60 * 1000;while(1){
QString command = "";
while (_socket->getSocket()->bytesAvailable() < (int)sizeof(quint16)) {
if (!_socket->getSocket()->waitForReadyRead(Timeout)) {
//emit error(_socket->getSocket()->error(), _socket->getSocket()->errorString());
return;
}
}
quint16 blockSize;
QDataStream in(_socket->getSocket());
in.setVersion(QDataStream::Qt_4_0);
in >> blockSize;while (_socket->getSocket()->bytesAvailable() < blockSize) {
if (!_socket->getSocket()->waitForReadyRead(Timeout)) {
//emit error(_socket->getSocket()->error(), _socket->getSocket()->errorString());
return;
}
}
in >> command;MyCommandParser::getInstance()->parse(command);
msleep(50);
}
}
@
When the socket is connected (signaled in main thread), I put it t to another thread, and start it.
Does anybody meet this problem?One more question, follow this flow :
- main thread : open a modal dialog (execute it in a slot function).
- my thread : receive tcp message, and try to update ui, emit a signal to ui object.
- main thread : close the modal dialog.
- Does the ui will be updated?
I just wondering whether signal-slot is asynchronous or not?
At step 1, this slot is blocking be the "dialog.exec()",
At step 2, there's another signal be emitted.
Will qt handle this signal immediately? or it will hand this signal after the modal dialog be closed?thank you all guys again.
-
Ehm... yes. Well, it seems that You Are Doing It Wrong (TM).
The (now) recommended way to use threading, is to use QThread as-is. Don't subclass it, but instead push a parent-less, QObject-derived worker object to the newly created thread to make it do its work in that thread.
This wiki article gives an overview of your options and pitfalls: http://developer.qt.nokia.com/wiki/Threads_Events_QObjects
Edit:
On your last question:
Signal-slot can be asynchronous. There are basically three connection modes:
- a direct connection: this is a synchronous connection. Connected slots are executed immediately.
- an queued connection: this is an asynchronous connection. Signals are marchalled as an event on the event loop of the receiving object, and executed when that event is processed by that event loop. The caller will continue executing immediately.
- a blocking queued connection: same as the above, but execution of the calling code halts until all connected slots have finished executing.
The standard connection type is autoConnection. This type works as a direct connection in the normal, non-threaded case. When a signal crosses a thread-boundary (that is, the thread affinity of the sending object and of the receiving object are not the same), auto connection uses a queued connection.
-
if u create the my thread(tcp thread) inside your main thread and run it from that thread not other classes and if u also connect the signals and slots in your main thread and manage all events in that i think ur problem will be solved.
u should pay attention to start the tcp thread from ur main thread and no where else and to create it there and add this class to the header of your main thread
i think if u do this exactly your program will work correclty