Qt Signal from QRunnable not received/not connecting - qt

I'm writing a Qt Application in C++. I have a QRunnable running in a QThreadPool, and it sends a signal to the main thread. The problem is, the connection doesn't work: the signal is never received by the main thread, even though I've verified that the code doing the emit is indeed called. Here is my code:
My QRunnable class:
class OfflineAnalysisThread : public QObject, public QRunnable
{
Q_OBJECT
public:
void run();
void sendMessage(QString &qmsg)
{
emit threadMessageCallback(qmsg);
}
signals:
void threadMessageCallback(QString &string);
};
And the calling class (main thread):
class OfflineAnalysisMain : public QObject
{
Q_OBJECT
public:
(...)
public slots:
void threadMsg(QString &string);
};
The code that instantiates the new QRunnables and starts them:
void OfflineAnalysisMain::myFunction()
{
OfflineAnalysisThread *newTask = new OfflineAnalysisThread();
QObject::connect(newTask, SIGNAL(threadMessageCallback(QString &)), this, SLOT(threadMsg(QString &)));
QThreadPool::globalInstance()->start(newTask);
}
So, from my QRunnable's run function, I call sendMessage and then I do QApplication::exec(). I have a breakpoint on the threadMsg slot implementation in OfflineAnalysisMain.cpp, and that function is never called.
What am I doing wrong?
UPDATE:
Definition of my OfflineAnalysisThread::run() function:
void OfflineAnalysisThread::run()
{
std::string myMsg("This is my message");
sendMessage(myMsg);
QApplication::exec();
}
I have also tried without the QApplication::exec();, without success.

Remove the call to QApplication::exec() from within run(). This is ideally called from within your main function.
In order to get your code to work, I had to write the following main function:
#include <QApplication>
#include <QMetaType>
#include <offlineanalysismain.h>
int main(int argc, char* argv[])
{
QApplication app(argc, argv);
qRegisterMetaType<QString>("QString&");
OfflineAnalysisMain* main = new OfflineAnalysisMain;
main->myFunction();
return app.exec();
}
Note the call to qRegisterMetaType, which allows Qt to pass a QString through a signal-slot connection that cross thread boundaries.

Related

When is it mandatory to call qRegisterMetaType()?

I have studied the qt documentation of qRegisterMetaType() where it says that this function must be called before the corresponding type can be used in signal/slot mechanism. However I couldn't find any code example where this has to be done by hand.
This page states, that the registration is done automatically by the moc if it can determine that the type may be registered as meta-type. It looks like this is right, because I tested QSignalSpy, QObject::connect() (direct and queued connection) and QVariant - with just using Q_DECLARE_METATYPE(type) and none of them needed a explicit call to qRegisterMetaType to work.
So my question is: when do I have to call qRegisterMetaType(), because otherwise the code won't work?
The Qt docs say that Q_DECLARE_METATYPE is necessary in case one has a connect being a queued connection.
Adding a Q_DECLARE_METATYPE() makes the type known to all template
based functions, including QVariant. Note that if you intend to use
the type in queued signal and slot connections or in QObject's
property system, you also have to call qRegisterMetaType() since the
names are resolved at runtime.
For this I build a small testing app, that exemplifies the behavior.
Just try to remove the Q_DECLARE_METATYPE(Message) and watch the warnings and output change. In case of the normal connect the macro seems to be unnecessary.
main.cpp
#include <QApplication>
#include <QThread>
#include "MyHeaderView.h"
Q_DECLARE_METATYPE(Message);
int main(int argc, char **args)
{
QApplication app(argc, args);
{
TestObject sender;
TestObject receiver;
QObject::connect(&sender, &TestObject::sendMessage, &receiver, &TestObject::onMessage);
sender.emitMessage(1, 2);
}
// This requires Q_DECLARE_METATYPE(Message);
QThread workerThread;
TestObject sender2;
TestObject receiver2;
receiver2.moveToThread(&workerThread);
workerThread.start();
QObject::connect(&sender2, &TestObject::sendMessage, &receiver2, &TestObject::onMessage, Qt::ConnectionType::QueuedConnection);
sender2.emitMessage(3, 4);
app.exec();
}
TestObject.h
#pragma once
#include <QObject>
#include <QDebug>
struct Message
{
int x;
int y;
};
class TestObject : public QObject
{
Q_OBJECT
public:
void emitMessage(int x, int y) { emit sendMessage(Message{ x,y }); }
signals:
void sendMessage(const Message&);
public slots:
void onMessage(const Message& m) { qDebug() << m.x << m.y; }
};

How can I connect a signal to QWidget::update slot?

I am using Qt5 with new signal/slot syntax.
I don't know why the following code doesn't work:
QWidget *widget = new QWidget();
connect(pipeline, &Pipeline::NewFrame, widget, &QWidget::update);
I get the error:
no matching member function for call to 'connect' why?
Pipeline class inherits from QObject and NewFrame signal has the same signature as QWidget::update
class Pipeline
: public QObject
{
Q_OBJECT
Q_DISABLE_COPY(Pipeline)
public:
Pipeline(QObject *parent);
signals:
void NewFrame();
};
I am using QtCreator on Arch Linux with g++.
TL;DR: The pipeline should be signaling an image, and the widget should have a SetImage method:
class Pipeline : public QObject {
Q_OBJECT // important
public:
Q_SIGNAL void NewFrame(const QImage &);
...
};
class Viewer : public QWidget {
Q_OBJECT // important
QImage m_image;
public:
Q_SLOT void SetImage(const QImage &image) {
m_image = image;
update();
}
...
};
This is how you'd be using it - note that Viewer knows nothing about Pipeline, because it shouldn't: it just shows new frames, wherever they come from.
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
Pipeline pipeline;
Viewer viewer;
QObject::connect(&pipeline, &Pipeline::NewFrame, &viewer, &Viewer::SetImage);
return app.exec();
}
Connecting anything to QWidget::update directly, especially from external sources, is usually a sign of bad design.
To satisfy your curiosity, you can use a lambda or qOverload to specify what you're connecting to, to fix the very error you're seeing - caused by ambiguity of the the type of the method pointer. Any of the following will work:
connect(…, widget, qOverload<>(&QWidget::update));
or
auto constexpr update = qOverload<>(&QWidget::update));
connect(…, widget, update);
or
connect(…, widget, [widget]{ widget->update(); });

Connection of pure virtual signal of interface class

I want to connect some object's signals derived from an interface class.
The connection is done in QWidget::listenToAnimal(AnimalInterface*).
This does not work because qt_metacall is not a member of 'AnimalInterface' and static assertion failed: No Q_OBJECT in the class with the signal.
Of course AnimalInterface does not have the Q_OBJECT macro and does not inherit QObject because it is an interface...
I want to connect through the interface class because I do not want to manually retype the same code for Cat and for Dog.
Is it possible to connect the signal the way I want to? Perhaps with templates? Is this perhaps a lambda-specific problem?
header:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class AnimalInterface{
public:
virtual ~AnimalInterface();
virtual void makeSound() = 0;
/*signals*/
virtual void madeSound() = 0;
};
Q_DECLARE_INTERFACE(AnimalInterface,"interface")
class Dog : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};
class Cat : public QObject, public AnimalInterface
{
Q_OBJECT
Q_INTERFACES(AnimalInterface)
public:
void makeSound();
signals:
void madeSound();
};
class Widget : public QWidget
{
Q_OBJECT
Cat *cat_;
Dog *dog_;
public:
Widget(QWidget *parent = 0);
~Widget();
void listenToAnimal(AnimalInterface *animal);
};
#endif // WIDGET_H
cpp:
#include "widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
dog_ = new Dog;
cat_ = new Cat;
listenToAnimal(dog_);
listenToAnimal(cat_);
dog_->makeSound();
cat_->makeSound();
}
void Widget::listenToAnimal(AnimalInterface *animal)
{
connect(animal, &AnimalInterface::madeSound,
this,
[](){
qDebug()<<"animal made sound";
});
}
Widget::~Widget()
{
}
void Cat::makeSound()
{
qDebug()<<"Cat says miaow";
emit madeSound();
}
void Dog::makeSound()
{
qDebug()<<"Dog says wuff";
emit madeSound();
}
main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
Since you know the derived type at compile type, you can connect to the proper, statically-known QObject-derived type. No need for dynamic casting or anything of the sort. You just don't want the listenToAnimal method to be available for non-AnimalInterface-inheriting types, though, even if it they have a compatible madeSound method:
C++11
#include <type_traits>
template< class T,
typename =
typename std::enable_if<std::is_base_of<AnimalInterface, T>::value>::type >
void listenToAnimal(T * animal) {
connect(animal, &T::madeSound, this, []{ qDebug() << "animal made sound"; });
}
C++03
template <class T>
void listenToAnimal(T * animal) {
Q_UNUSED(static_cast<AnimalInterface*>(animal));
connect(animal, &T::madeSound, this, &Widget::onAnimalMadeSound);
}
You can then use it without having to spell out the type - it's already known to the compiler:
listenToAnimal(dog_);
listenToAnimal(cat_);
If the derived type is not known at compile time, you have to dynamically cast to QObject and connect by name, not by method pointer. It will assert at runtime if you've passed in a wrong type - after all, it's not enough for it to be an instance of AnimalInterface, it also needs to be a QObject instance.
void listenToAnimal(AnimalInterface * animal) {
auto object = dynamic_cast<QObject*>(animal);
Q_ASSERT(object);
connect(object, SIGNAL(madeSound()), this, SLOT(onAnimalMadeSound()));
}
The fact that the type AnimalInterface has a virtual madeSound method is somewhat relevant - it guarantees that the derived class implements the method with such a signature. It doesn't guarantee that the method is a signal, though. So you should probably rethink your design and ask yourself: "What do I gain by using a static type system when I can't really use it for static type checking"?
Most likely you should make any methods that would nominally accept the AnimalInterface*, be parametrized and take a pointer to the concrete class. Modern code generators and linkers will deduplicate such code if type erasure leads to identical machine code.
Found a solution with templates. Did not work the first time I tried, obviously did something wrong first. Here it goes...
Just replace the corresponding parts from the example in the question (and remove definition of listenToAnimal from the source file):
header:
template<class T>
void listenToAnimal(AnimalInterface *animal)
{
T *animal_derivate = dynamic_cast<T*>(animal);
if (animal_derivate){
connect(animal_derivate, &T::madeSound,
this,
[](){
qDebug()<<"animal made sound";
});
}
}
cpp:
listenToAnimal<Dog>(dog_);
listenToAnimal<Cat>(cat_);
Update:
After trying Kuba Ober's answer, it seems like this is working best now:
template<typename T>
typename std::enable_if<std::is_base_of<AnimalInterface, T>::value,void>::type
listenToAnimal(T *animal)
{
connect(animal, &T::madeSound, this, [](){ qDebug()<<"animal made sound"; });
}
However, the one point still not working is how to connect if I create an animal like AnimalInterface *bird = new Bird, because it throws the same error that the base class does not have the signal.

QThread never runs/finishes before it can be used?

I have created a custom QObject class called EncodeThread, which looks as follows:
class EncodeThread : public QObject {
Q_OBJECT
public:
void set(SWSL::Video* v, QStringList f, QDir vDir);
void run();
public slots:
void encode();
signals:
void encodeProgress(int i);
private:
SWSL::Video* video;
QStringList files;
QDir videoDir;
};
As may be obvious, this class is used for encoding a video using an external library. Encode() contains the actual encoding routine, run() is a function I added while troubleshooting, though it's obviously non-functional:
void EncodeThread::run() {
if (currentThread() != this) {
// caller is in different thread.
QMetaObject::invokeMethod(this, "encode", Qt::QueuedConnection);
}
else {
encode();
}
}
The problem is when I use a QThread and the moveToThread() function on the EncodeThread instance, namely that nothing seems to happen. No data is written, and the instance never emits the signal which should save the encoded file to disk.
encThread.set(video, files, videoDir);
connect(&encThread, SIGNAL(encodeProgress(int)), cookVideoProgress, SLOT(setValue(int)));
connect(&encThread, SIGNAL(finished()), this, SLOT(videoCookEnd()));
connect(this, SIGNAL(videoEncode()), &encThread, SLOT(encode()));
encThread.moveToThread(&thread);
thread.start();
The above is how the whole setup is started. EncThread and thread variables are declared in the MainWindow class. I have made the set() function of EncodeThread call encode() after attempts to call encode() from the main thread using signals and QMetaObject failed.
I'm not new to threading, having used native Windows and Linux threads, as well as those of various cross-platform implementations, but QThreads really seem to baffle me. Any suggestions are more than welcome :)
Probably way to late to be any help to you, but here's a little demo program that puts an EncoderThread class to work. It probably doesn't quite mesh with your design (which your question only had fragments of), but it demonstrates running an object instance on its own thread and wiring 2 objects on different threads via signals/slots to let them communicate:
#include <stdio.h>
#include <QObject>
#include <QThread>
#include <QtCore/QCoreApplication>
// QSleeper is just a toy utility class that makes the
// protected QThread::sleep() family of functions
// publicly accessible. It's only use is for demo
// programs like this
class Sleeper : QThread
{
public:
static void sleep(unsigned long secs) { QThread::sleep(secs); }
static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
static void usleep(unsigned long usecs) { QThread::usleep(usecs); }
};
// an Encoder class that maintains itself on is own thread
class EncodeThread : public QObject {
Q_OBJECT
public:
EncodeThread();
public slots:
void encode();
signals:
void encodeProgress(int i);
void finished();
private:
QThread myThread;
};
EncodeThread::EncodeThread() {
moveToThread(&myThread);
myThread.start();
}
void EncodeThread::encode()
{
printf("EncodeThread::encode() on thread %u\n", (unsigned int) QThread::currentThreadId());
for (int i = 0; i < 6; ++i) {
// encode for 1 second or so
printf("EncodeThread::encode() working on thread %u\n", (unsigned int) QThread::currentThreadId());
Sleeper::sleep(1);
emit encodeProgress(i);
}
emit finished();
printf("EncodeThread::encode() - done\n");
}
// a controller to manage and monitor an EncoderThread instance
class VideoEncoderController : public QObject
{
Q_OBJECT
public:
void start();
public slots:
void setValue(int);
void encodingDone();
signals:
void encodingBegin();
};
void VideoEncoderController::start()
{
printf("VideoEncoderController::start() on thread %u\n", (unsigned int) QThread::currentThreadId());
emit encodingBegin();
}
void VideoEncoderController::setValue(int x)
{
printf("VideoEncoderController::setValue(int %d) on thread %u\n", x, (unsigned int) QThread::currentThreadId());
}
void VideoEncoderController::encodingDone()
{
printf("VideoEncoderController::encodingDone() on thread %u\n", (unsigned int) QThread::currentThreadId());
}
// a demo program that wires up a VideoEncoderController object to
// an EncoderThread
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
EncodeThread encThread;
VideoEncoderController controller;
QObject::connect(&encThread, SIGNAL(encodeProgress(int)), &controller, SLOT(setValue(int)));
QObject::connect(&encThread, SIGNAL(finished()), &controller, SLOT(encodingDone()));
QObject::connect(&controller, SIGNAL(encodingBegin()), &encThread, SLOT(encode()));
printf("hello world on thread %u\n", (unsigned int) QThread::currentThreadId ());
controller.start();
return a.exec();
}
#include "main.moc"
You must derive QThread, not QObject. run() method is an abstract method of QThread.
For future programmers I'm adding this answer. There are generally 3 approaches to multi-threading in Qt. Low Level, Reusing(lets say Mid Level) and High Level.
Low level also includes two different approaches. In Low level you can Inherit QThread class and provide the code that you want to run in parallel inside void QThread::run() override;. After calling QThread::start() on your drived class, code in run will execute.
Another approach in Low Level Multi-threading in Qt is relaying on Qt's event loops. In this way you create a class that is drived from QObject, not necessarily from QThread and then move that class to a new QThread with this. And after that you will call start() on that QThread object(this QThread object is an object of type QThread . You don't have to subclass QThread here. Just instantiate one object. It is where I believe you misunderstood in your code).
After calling start() on your QThread object, its event loop starts in another thread and signals from anywhere in your code that are connected to your QObject drived class's slots will run in that event loop in parallel as long as you don't use Qt::DirectConnection as last argument to this.
These two approaches has their own benefits and drawbacks. When sub-classing QThread and using Qthread::run(), if your code inside run is running inside a while(true) loop, one of your processor's threads will always be occupied with Qthread::run() code and not in the threadpool for other threads in your program.
The QObject::moveToThread() approach is useful for most cases. But if the QObject drived classe's slot is going to be called very frequently, like 100 or 1000 times per second, memory usage rises, due to possible arguments passed to the slot, and some of this signals may never reach the slot.

unable to bind a signal to a slot in QT

I just started with QT and I know the concept of signal/slot but in implementing it I have problem.
take a look at my code :
#include "test.h"
#include <QCoreApplication>
test::test()
{
// TODO Auto-generated constructor stub
}
test::~test()
{
// TODO Auto-generated destructor stub
}
void test::fireslot(){
qDebug("the slot fired");
}
void test::dosignaling(){
QObject::connect(this,SIGNAL(callslot()),this,SLOT(fireslot()));
}
note : I've added the Q_OBJECT macro and inherit from QObject in test.h
and here is my test container
#include "test.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//test t1();
test *t2 = new test();
t2->dosignaling();
return a.exec();
}
code compile perfect but the nothing gonna happen . I'm not quite sure which part I've made mistake :-?
The code you have in void test::dosignaling connects a slot "fireslot" to a signal "callslot", but where are you emitting the callslot signal?
You should change your code and place your QObject::connect() in the constructor (or someplace else) and change your dosignaling method to:
void test::dosignaling()
{
emit callslot();
}
Also, you haven't shown the header file but it should include a declaration of the callslot signal, like this:
class test
{
...
signals:
void callslot();
};

Resources