PDA

View Full Version : Calling functions from other classes from QThread object



caesius
12th January 2010, 23:08
I'm coding a small front end GUI for some chat client code I've written in C. I'm not really worrying about the networking aspect yet, just getting the GUI and signals set up etc.

Here's what the app looks like, it's pretty simple, type input, click submit, it (will eventually) sends the message to the chat server.

http://www.freeimagehosting.net/uploads/th.eb77174698.jpg (http://www.freeimagehosting.net/image.php?eb77174698.jpg)

I've tried to set up a new qthread object to deal with the task of continually checking for messages sent by the chat server. The problem is when it finds one I want it to update the main "display" with the received message. I've written code to that effect but it doesn't work.

Here's the relevent code segments:

This is the main "display" window..


class Output : public QWidget
{
public:
Output(QWidget *parent = 0);

public slots:
void displayMsg(QString msg);

private:
QTextEdit *display;

};


And the qthread object...


class MyThread : public QThread
{
protected:
void run();
};

void MyThread::run()
{


for (int count = 0; count < 20; count++)
{
sleep(1);
Output::displayMsg("test");
}


/*char *rawmessage = (char *)malloc(MAX_MSG_LENGTH);

while(1)
{
//rawmessage = network_getmessage();
// translate from char * to QString
//displayMsg(msg);
}
*/
}

You can see I've commented out the network stuff, I just want to get the threads communicating in a basic way before I move on.

I get the compile time error:


main.cpp: In member function 'virtual void MyThread::run()':
main.cpp:94: error: cannot call member function 'void Output::displayMsg(QString)' without object


I can post the full source if it will help, but I think the parts above are all that is needed?

tl;dr version: how can I call another class's member functions from within a qthread object?

Thanks, Benjamin

wysota
12th January 2010, 23:37
You are calling the method as a static method but it is not a static method. If you had two "Output" objects, how would "Output::displayMsg()" know which one to output the message to?

Emit a signal from the thread every time a new message arrives and connect that signal to your displayMsg() slot. Or better yet implement your chat backend a bit differently and don't use a thread at all, you don't need it.

caesius
13th January 2010, 00:05
Thanks wysota, I understand now. Elementry mistake.

Could you elaborate on why I don't need a thread? I thought about this for a while and I can't see any other options...

wysota
13th January 2010, 11:24
Let's reverse the situation. Tell me why you think you need a thread. And I want you to think about details - an answer that "I want to do two things at the same time" is not a correct one.

caesius
15th January 2010, 07:22
Alright, so I understand that the program can get away with a millisecond delay while receiving the message so I don't really need a new thread. I've tried to rewrite it accordingly but I keep running into the problem that I need to have the following somewhere in my code:


for(;;)
{
rawmessage = network_getmessage(socket);
emit recvdMsg(rawmessage);
}

I've put it in one of the constructors but as I expected it just hangs...

Here's my new, more condensed program (network code omitted):

dialogue.cpp (message display, text input etc)


#include "dialogue.h"

Dialogue::Dialogue(int socket)
{

char *rawmessage = (char *)malloc(MAX_MSG_LENGTH);

commSocket = socket;

input = new QLineEdit(this);
output = new QTextEdit(this);

QPushButton *submit = new QPushButton("Submit", this);
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(input);
layout->addWidget(output);
layout->addWidget(submit);
setLayout(layout);

connect(submit, SIGNAL(clicked()), this, SLOT(sendMsg()));
connect(this, SIGNAL(recvdMsg(char *)), this, SLOT(displayMsg(char *)));



for(;;)
{
rawmessage = network_getmessage(socket);
emit recvdMsg(rawmessage);
}

}

void Dialogue::sendMsg(int socket)
{
QString qMsg = input->text();
QByteArray ba = qMsg.toLatin1();
char *msg = ba.data();
network_sendmessage(socket, msg);
}

void Dialogue::displayMsg(char *msg)
{
QString qMsg = msg;
output->append(msg);
}


main.cpp


#include <QApplication>
#include <QWidget>

#include "dialogue.h"
#include "network.h"

class Client : public QWidget
{
public:
Client(QWidget *parent = 0);
};

Client::Client(QWidget *parent) : QWidget(parent)
{
int socket = network_tcpconnect();

QPushButton *quit = new QPushButton("Quit", this);
Dialogue *dialogue = new Dialogue(socket);

QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(quit);
layout->addWidget(dialogue);
setLayout(layout);
}

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
Client client;
client.show();
return app.exec();
}

wysota
15th January 2010, 10:11
(...)I need to have the following somewhere in my code:


for(;;)
{
rawmessage = network_getmessage(socket);
emit recvdMsg(rawmessage);
}

Let's focus on that...

All problems and ideas related to threads boil down to this piece of code. You have an infinite loop here where you read messages from network. The network_getmessage call is most likely a blocking one. If you made it non-blocking, all your problems would go away and there would be no need to use threads. If "socket" is a BSD socket then you can use select() or QSocketNotifier (which may be using select() internally) to only read from the socket when there is actually something to be read.

caesius
15th January 2010, 20:28
Thanks wysota, your explanations are useful.

I must be missing something - because the one thing I still don't understand is how am I meant to check for messages OVER and OVER and OVER again?

Whatever thought process I use it comes back to an infinite loop, i.e., if I wrote

connect(this, SIGNAL(gotMsg()), dialogue, SLOT(displayMsg()));
then somewhere in my code I'm still going to need an infinite for loop constantly waiting for messages and sending the gotMsg() signal when one arrives (that's what I used the thread for..)

I think I'm missing something big...

wysota
15th January 2010, 20:45
With Qt it's almost always about signals and slots :) Take a look at QSocketNotifier::activated().