How to use signals & slots in Qt for inter-threading communication?
-
I want to make an application where the user will hit a QPushButton and this will trigger a secondary thread which will add some text to a QListWidget in the main window. But for a reason that I cannot figure out ,although the signal from the thread to the main window is emitted it never reaches the destination. Probably because the connection fails. But why this happens? Here is my code(my application is compiled using Visual Studio 2010):
mythread.h:
@#ifndef MY_THREAD_H
#define MY_THREAD_H
#include <QThread>
#include <QString>
class mythread:public QThread
{
Q_OBJECTpublic:
void setName(QString& name);
signals:
void sendMsg(QString& msg);
protected:
void run();
private:
QString m_name;
QString msg;
};
#endif@mythread.cpp:
@#include "mythread.h"
void mythread::setName(QString& name)
{
m_name=name;
}
void mythread::run()
{
msg="Hello "+m_name;
emit sendMsg(msg);
}@mydialog.h:
@#ifndef MY_DIALOG_H
#define MY_DIALOG_H
#include <QtGui>
#include "mythread.h"
class mydialog:public QDialog
{
Q_OBJECT
public:
mydialog();
public slots:
void receiveMsg(QString& msg);
void fillList();
private:
QListWidget list1;
QPushButton btn1;
QGridLayout layout;
mythread thread;
};
#endif@mydialog.cpp:
@#include "mydialog.h"
mydialog::mydialog()
{
layout.addWidget(&list1,0,0);
btn1.setText("Find");
layout.addWidget(&btn1,0,1);
setLayout(&layout);
QString myname="leonardo";
thread.setName(myname);
connect(&btn1,SIGNAL(clicked()),this,SLOT(fillList()));
connect(&thread,SIGNAL(sendMsg(QString&)),this,SLOT(receiveMsg(Qstring&)));
}
void mydialog::fillList()
{
thread.start();
}
void mydialog::receiveMsg(QString& msg)
{
list1.addItem(msg);
}@find.cpp:
@#include <QApplication>
#include "mydialog.h"
int main(int argc,char* argv[])
{
QApplication app(argc,argv);
mydialog window;
window.setWindowTitle("Find");
window.show();
return app.exec();
}@@TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .Input
HEADERS += mydialog.h mythread.h
SOURCES += find.cpp mydialog.cpp mythread.cpp@ -
You have fallen victim to a common mistake. "You're doing it wrong":http://blog.qt.digia.com/blog/2010/06/17/youre-doing-it-wrong/. Don't subclass QThread but rather use the new "best practise for QThreads":http://developer.qt.nokia.com/wiki/QThreads_general_usage.
I think your problem is that you forgot to call exec() in your run() function implementation. Therefor your thread doesn't have an eventloop, and therefor the signal is not emitted. It's just one of the many pitfalls that often arise when people follow the old approach of subclassing QThread rather than just moving a worker object to a QThread. There is also a "doc note in the QThread reference":http://qt-project.org/doc/qt-4.8/QThread.html#notes.
-
Hi! This approach is vicious:
@private:
QListWidget list1;
QPushButton btn1;
QGridLayout layout;
@You should always allocate QObjects dynamically (using new):
@private:
QListWidget* list1;
QPushButton* btn1;
QGridLayout* layout;
//...// in constructor
list1 = new QListWidget();
btn1 = new QPushButton();
layout = new QGridLayout();@This is because you usually add widgets to a parent widget making them its children and QObject automatically deletes its children.
Therefore, anything that becomes someone's child should be allocated dynamically using operator new.
Although in your particular case you didn't explicitly set parent to your button, listwidget and layout but you used addWidget and setLayout on them which implicitly made them dialog's children.
"Official docs on QObject destructor":http://qt-project.org/doc/qt-4.8/qobject.html#dtor.QObject