4

I want to send a structure with a signal in Qt. How can I do this? I know how to send integers, strings, Images etc with a signal but getting confused with the structure part. I read some posts and found out about Q_DECLARE_METATYPE() but I am not understanding how to use it.

typedef struct
{
    int EmpId;
    QString Name; 
} StandardData; 

class Data::public QObject
{
    Q_DECLARE_METATYPE(StandardData);

    signals:
        void SignalData(const StandardData &f_objStandardCan);
}

The errors I get re 1.explicit specialization in non namespace scope class. 2.Specialization of template must appear at namespace scope 3. struct QMetaTypeId redeclared with a different access. Can someone please tell me where I am going wrong.

JojOatXGME
  • 3,023
  • 2
  • 25
  • 41
Sid411
  • 703
  • 2
  • 9
  • 25
  • The code you posted cannot compile. The structure has an identifier with a space in it. Please post a [sscce](http://sscce.org/). – RedX Oct 16 '13 at 07:40
  • Im working in Linux and posting this from windows machine. So that mistake...I will edit it... – Sid411 Oct 16 '13 at 07:54
  • Try http://www.qtcentre.org/archive/index.php/t-25868.html – RedX Oct 16 '13 at 08:11
  • Don't forget `qRegisterMetaType<>()` – Dmitry Sazonov Oct 16 '13 at 08:36
  • Is your plan to use `Qt::QueuedConnection`? – thuga Oct 16 '13 at 08:39
  • 1
    Just so you know, you don't need any of this unless you're using queued connections. [Read this](http://www.qtcentre.org/wiki/index.php?title=Using_custom_data_types_with_Qt#Signals_and_slots) for more info. – thuga Oct 16 '13 at 09:07
  • @thuga...No as of now its default connection. I think so it will take Direct Connection in that case. – Sid411 Oct 16 '13 at 09:07
  • 2
    @Sid411 If the signal is emitted from the same thread as the object's slot lives in, it will be a direct connection. In that case you don't have to declare a custom metatype using `Q_DECLARE_METATYPE`. – thuga Oct 16 '13 at 09:13

2 Answers2

11

The errors are because the use of Q_DECLARE_METATYPE is inside your class declaration. It must be outside any classes or namespaces. You just need to move it like this:

typedef struct
{
  int EmpId;
  QString Name; 
} StandardData;

Q_DECLARE_METATYPE(StandardData);
Dan Milburn
  • 5,600
  • 1
  • 25
  • 18
4

As you have already found out, you must use Q_DECLARE_METATYPE to make the type known to Qt.

struct StandardData {
    int EmpId;
    QString Name;
}; Q_DECLARE_METATYPE(StandardData)

Additionally, you might need to call qRegisterMetaType. Specifically, the function have to be called before using the struct in a queued signal/slot connection or before using it with the QObject::property() API.

qRegisterMetaType<StandardData>();

Working Example

standarddata.h

struct StandardData {
    int EmpId;
    QString Name;
}; Q_DECLARE_METATYPE(StandardData)

main.cpp

int main(int argc, char *argv[])
{
    // Register types on startup
    qRegisterMetaType<StandardData>();

    // Continue with the program
    // ...
}

Trick with Static Initialization

There is a trick that can be used to call qRegisterMetaType without modifying any non-related file (like main.cpp). This trick uses static initialization. However, I did not find any documentation of Qt that state that this is supported. Additionally, this might cause trouble when using in dynamic libraries.

standarddata.h

// The header file looks the same as above
struct StandardData {
    int EmpId;
    QString Name;
}; Q_DECLARE_METATYPE(StandardData)

standarddata.cpp

// We don't need this global variable at all. We just want to ensure that
// qRegisterMetaType is called when the application starts.
static const int typeId = qRegisterMetaType<StandardData>();

Q_GADGET

Alternatively, you can use Q_GADGET instead of Q_DECLARE_METATYPE:

class StandardData {
    Q_GADGET
public:
    int EmpId;
    QString Name;
};

// You still have to call qRegisterMetaType if used for queued signals or
// as property.
qRegisterMetaType<StandardData>();
JojOatXGME
  • 3,023
  • 2
  • 25
  • 41
  • I have a struct which was being sent over signals & slots. The signal gets emitted but the slot is never fired (strangely, I went through the code and where the `QObject::activate()` is called, the `**argv` was `0x0`. I added the `Q_DECLARE_METATYPE` after my `struct` declaration and `qRegisterMetaType` in the class where I have the signal emitting from / slot retrieving and it appears to work well, thanks for posting! – CybeX Oct 26 '19 at 19:13