Passing structure to signal in Qt

2019-05-09 10:19发布

问题:

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.

回答1:

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);


回答2:

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>();