Solved Trouble understanding qRegisterMetaType docs.
-
Hi everyone!
Im having trouble understanding the docs about QRegisterMetaType, and I would like to know if someone could point me in the right direction.
My main program has 2 different threads, ClassSignalling and ClassUSB. Im not going to put the whole code, but only the relevant parts.
#include "struct.h" class ClassSignalling : public QThread { Q_OBJECT public: explicit ClassSignalling(QObject *parent = 0); void run(); signals: void SignalDarDeAltaLlamada(StructDataFisicaLlamada DataFisicaLlamada); }; class ClassUSB : public QThread { Q_OBJECT public: explicit ClassUSB(QObject *parent = 0); void run(); public slots: void SlotDarDeAltaLlamada(StructDataFisicaLlamada DataFisicaLlamada); };
Of course each class has more methods/variables/signals and slots that arent relevant here.
Each of these QThreads works reimplementing the run method (Havent used the move to worker approach)Then in my struct.h i have
struct StructDataFisicaLlamada { QByteArray E1_0; QByteArray E1_1; unsigned char Mascara; unsigned char Slot; unsigned char Desplazamiento; unsigned long long int IdentificadorLlamada; unsigned long int Incrementalllamada; }
So, as many might guess, what Im trying to do is the following. The class "ClassSignalling" emits the signal SignalDarDeAltaLlamada, that needs to get connected to the slot SlotDarDeAltaLlamada of "ClassUSB"
On my main, i have the following
ClassUsb *ThreadUsb; ThreadUsb = new ClassUsb; // Here I initialize my USB Class ClassSignalling *ThreadSignalling; ThreadSignalling = new ClassSignalling; // Here I initialize my Signalling Class if(!connect(ThreadSignalling,SIGNAL(SignalDarDeAltaLlamada(StructDataFisicaLlamada)),ThreadUSB,SLOT(SlotDarDeAltaLlamada(StructDataFisicaLlamada))) { QMessageBox Error; Error.setText("Connection failed"); Error.exec(); }
Ok, so what happens? The connect sentence compiles perfectly, and when the program passes through that line, the messageBox doesnt appear (Meaning the connection was properly done)
The program starts, and nothing happens, the signal is emitted, but the slot never activates.
If i check the console, the following appears....QObject::connect: Cannot queue arguments of type 'StuctDataFisicaLlamada' (Make sure 'StructDataFisicaLlamada' is registered using qRegisterMetaType().)
Ok, So i start reading some information. Apparently only Qt data types can be passed through the signal/slots system, and if you want to send something different, you need to first "register it".
Ive tried my luck with stuff likeQRegisterMetaType<StructDataFisicaLlamada>("Data Fisica");
or
int Id=QRegisterMetaType<StructDataFisicaLlamada>("Data Fisica"); connect(ThreadSignalling,SIGNAL(SignalDarDeAltaLlamada(QMetaType(Id))),ThreadUSB,SLOT(SlotDarDeAltaLlamada(QMetaType(Id)));
Nothing seems to work, but the truth is, I dont understand how tu actually register this struct/
According to the docs" Call qRegisterMetaType() to make types available to non-template based functions, such as the queued signal and slot connections.
Any class or struct that has a public default constructor, a public copy constructor, and a public destructor can be registered."
Thats the part that I really dont understand... I need to create a constructor and a destructor for a Struct? As far as i knew, constructors/destructors are only for classes, nos structs, and theres no need for me to pass a whole class... I just need 2 QByteArrays and a couple of unsigned char...
Been reading the MetaType and QRegisterMetaType docs, but I cant completely understand what Im supposed to do.
Any tip?
Thanks in advance! -
@NicolasKsi said in Trouble understanding qRegisterMetaType docs.:
Each of these QThreads works reimplementing the run method (Havent used the move to worker approach)
So, as many might guess, what Im trying to do is the following. The class "ClassSignalling" emits the signal SignalDarDeAltaLlamada, that needs to get connected to the slot SlotDarDeAltaLlamada of "ClassUSB"
Which will not work no matter if you register your type or not. You can not have queued events (what a signal-slot call across threads is) without a running event loop (and you don't have a running event loop when you reimplement
QThread::run
(except in a handful of special cases).Nothing seems to work, but the truth is, I dont understand how tu actually register this struct
struct StructDataFisicaLlamada { // ... }; Q_DECLARE_METATYPE(StructDataFisicaLlamada)
To declare it as a metatype. And then you need to register it (usually in
main()
) so it can be an argument for a queued connection with:qRegisterMetaType<StructDataFisicaLlamada>();
Thats the part that I really dont understand... I need to create a constructor and a destructor for a Struct?
The compiler creates a default constructor, a default copy constructor and a default assignment operator (since C++11 it also creates a default move constructor) for any POD struct (or class).
As far as i knew, constructors/destructors are only for classes, nos structs
In C++ there's no difference between a class and a struct except for the default access specifier, being
private
for classes andpublic
for structures. -
Wow, thanks for taking your time and Explaining it in that detail!
Theres only 1 thing that im still not sure what you ment..."Which will not work no matter if you register your type or not. You can not have queued events (what a signal-slot call across threads is) without a running event loop (and you don't have a running event loop when you reimplement QThread::run (except in a handful of special cases)."
That means that if I reimplement the run, i cant use the Signal and Slot System?
Example from the docs found at http://doc.qt.io/qt-4.8/qthread.html#details
class WorkerThread : public QThread { Q_OBJECT void run() { QString result; /* expensive or blocking operation */ emit resultReady(result); } signals: void resultReady(const QString &s); }; void MyObject::startWorkInAThread() { WorkerThread *workerThread = new WorkerThread(this); connect(workerThread, SIGNAL(resultReady(QString)), this, SLOT(handleResults(QString))); connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater())); workerThread->start(); }
From what I understand, here they are Reinstancing the run method, and they are also using the Signal, Slot system... Or did you mean something different?
Anyway, even if right now my connection with a struct isnt working, both my ClassSignalling and ClassUsb have a signal ErrorFound(QString) , thats connected to my main program, so that If a thread founds an error, I can open a QMessageBox from the main window. This connection is currently working. It would be something like...
//Code on my main program connect(ThreadSignalling,SIGNAL(SignalErrorFound(QString)),this,SLOT(SlotErrorFound(QString))
This connection isnt between 2 threads, its between 1 thread and my main program, and its currently working fine.
-
Update:
I implemented the changes you said, Calling Q_DECLARE_METATYPE after the definition of the struct and registering it on my Main.c and its working properly!
Is my approach wrong and its working out of pure luck? -
@NicolasKsi said in Trouble understanding qRegisterMetaType docs.:
I implemented the changes you said, Calling Q_DECLARE_METATYPE after the definition of the struct and registering it on my Main.c and its working properly!
Is my approach wrong and its working out of pure luck?It isn't luck but it's probably not what you want. You have your slot in your
QThread
object and that object "lives" in the main thread. You have a running event loop in the main thread, so you can have queued slot calls there no problem. Ultimately, your slot is executed in the main thread, not in the thread you want (or at least I assume you want the slot to be run in the worker thread).@NicolasKsi said in Trouble understanding qRegisterMetaType docs.:
That means that if I reimplement the run, i cant use the Signal and Slot System?
You can
emit
from arun()
reimplementation, but you can't have slots executed in that thread that are connected to signals from other threads.