Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Trouble understanding qRegisterMetaType docs.
Forum Updated to NodeBB v4.3 + New Features

Trouble understanding qRegisterMetaType docs.

Scheduled Pinned Locked Moved Solved General and Desktop
5 Posts 2 Posters 2.5k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Offline
    N Offline
    NicolasKsi
    wrote on 23 Mar 2017, 11:31 last edited by
    #1

    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 like

    QRegisterMetaType<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!

    K 1 Reply Last reply 23 Mar 2017, 12:08
    0
    • N NicolasKsi
      23 Mar 2017, 11:31

      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 like

      QRegisterMetaType<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!

      K Offline
      K Offline
      kshegunov
      Moderators
      wrote on 23 Mar 2017, 12:08 last edited by kshegunov
      #2

      @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 and public for structures.

      Read and abide by the Qt Code of Conduct

      N 2 Replies Last reply 23 Mar 2017, 14:15
      6
      • K kshegunov
        23 Mar 2017, 12:08

        @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 and public for structures.

        N Offline
        N Offline
        NicolasKsi
        wrote on 23 Mar 2017, 14:15 last edited by
        #3

        @kshegunov

        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.

        1 Reply Last reply
        0
        • K kshegunov
          23 Mar 2017, 12:08

          @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 and public for structures.

          N Offline
          N Offline
          NicolasKsi
          wrote on 23 Mar 2017, 14:27 last edited by
          #4

          @kshegunov

          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?

          K 1 Reply Last reply 24 Mar 2017, 17:01
          0
          • N NicolasKsi
            23 Mar 2017, 14:27

            @kshegunov

            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?

            K Offline
            K Offline
            kshegunov
            Moderators
            wrote on 24 Mar 2017, 17:01 last edited by
            #5

            @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 a run() reimplementation, but you can't have slots executed in that thread that are connected to signals from other threads.

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            0

            1/5

            23 Mar 2017, 11:31

            • Login

            • Login or register to search.
            1 out of 5
            • First post
              1/5
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved