Qt信号槽使用结构体作为参数

廉价感情. 提交于 2020-04-06 13:05:35

信号可以带参数,参数的类型,必须是元对象系统能够识别的类型, 即元类型。

下面这几个类型是自动注册的,不需要使用Q_DECLARE_METATYPE这个宏:
1.QObject继承下来的子类的指针;
2.QList<T>, QVector<T>, QQueue<T>, QStack<T>, QSet<T> or QLinkedList<T>这些T都是自动注册的;
3.QHash<T1, T2>, QMap<T1, T2> or QPair<T1, T2> T1,和T2都是自动注册的;
4.QPointer<T>, QSharedPointer<T>, QWeakPointer<T>这3个T必须是QObject的子类;
5.枚举类型要用Q_ENUM or Q_FLAG;
6.拥有Q_GADGET宏的类。





例如:自定义结构体,connect想通过结构体参数来传递

struct _ColorBalance
{
    bool preserve_luminosity;
    int cyan_red[3];
    int magenta_green[3];
    int yellow_blue[3];
};

signals:
    void state_changed(_ColorBalance *color_balance);

connect(this, &ColorBalance::state_changed, pic, &Picture::ColorBalance);

如果不注册元类型,编译会报错:

ColorBalance.obj:-1: error: LNK2019: 无法解析的外部符号 "public: void __cdecl ColorBalance::state_changed(struct _ColorBalance *)" (?state_changed@ColorBalance@@QEAAXPEAU_ColorBalance@@@Z),该符号在函数 "public: __cdecl ColorBalance::ColorBalance(class Picture *,class QWidget *)" (??0ColorBalance@@QEAA@PEAVPicture@@PEAVQWidget@@@Z) 中被引用

 

注册元类型

Qt已经将大部分常用的基础类型,都注册进了元对象系统,可以在QMetaType类中看到。

通常写的继承于QObject的子类,本身已经附带了元信息,可以直接在信号-槽中使用。

不是继承于QObject的结构体、类等自定义类型,可以通过Q_DECLARE_METATYPE宏 和 qRegisterMetaType函数进行注册,之后就可以在信号-槽中使用。

 

官方文档

https://wiki.qt.io/New_Signal_Slot_Syntax

https://doc.qt.io/qt-5/signalsandslots-syntaxes.html

https://doc.qt.io/qt-5/qmetatype.html

int qRegisterMetaType()

Call this function to register the type T. T must be declared with Q_DECLARE_METATYPE(). Returns the meta type Id.

Example:

int id = qRegisterMetaType<MyStruct>();
This function requires that T is a fully defined type at the point where the function is called. For pointer types, it also requires that the pointed to type is fully defined. Use Q_DECLARE_OPAQUE_POINTER() to be able to register pointers to forward declared types.

After a type has been registered, you can create and destroy objects of that type dynamically at run-time.

To use the type T in QVariant, using Q_DECLARE_METATYPE() is sufficient. To use the type T in queued signal and slot connections, qRegisterMetaType<T>() must be called before the first connection is established.

Also, to use type T with the QObject::property() API, qRegisterMetaType<T>() must be called before it is used, typically in the constructor of the class that uses T, or in the main() function.

Q_DECLARE_METATYPE(Type)

This macro makes the type Type known to QMetaType as long as it provides a public default constructor, a public copy constructor and a public destructor. It is needed to use the type Type as a custom type in QVariant.

This macro requires that Type is a fully defined type at the point where it is used. For pointer types, it also requires that the pointed to type is fully defined. Use in conjunction with Q_DECLARE_OPAQUE_POINTER() to register pointers to forward declared types.

Ideally, this macro should be placed below the declaration of the class or struct. If that is not possible, it can be put in a private header file which has to be included every time that type is used in a QVariant.

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.

This example shows a typical use case of Q_DECLARE_METATYPE():

struct MyStruct
{
    int i;
    ...
};

Q_DECLARE_METATYPE(MyStruct)
If MyStruct is in a namespace, the Q_DECLARE_METATYPE() macro has to be outside the namespace:

namespace MyNamespace
{
    ...
}

Q_DECLARE_METATYPE(MyNamespace::MyStruct)
Since MyStruct is now known to QMetaType, it can be used in QVariant:

MyStruct s;
QVariant var;
var.setValue(s); // copy s into the variant

...

// retrieve the value
MyStruct s2 = var.value<MyStruct>();

Some types are registered automatically and do not need this macro:

Pointers to classes derived from QObject
QList<T>, QVector<T>, QQueue<T>, QStack<T>, QSet<T> or QLinkedList<T> where T is a registered meta type
QHash<T1, T2>, QMap<T1, T2> or QPair<T1, T2> where T1 and T2 are registered meta types
QPointer<T>, QSharedPointer<T>, QWeakPointer<T>, where T is a class that derives from QObject
Enumerations registered with Q_ENUM or Q_FLAG
Classes that have a Q_GADGET macro

 

参考文献

Qt文档阅读笔记-关于Q_DECLARE_METATYPE原理以及使用

Qt 自定义数据类型qRegisterMetaType Q_DECLARE_METATYPE 的使用 (附demo)

Qt工作笔记-对connect的第五个参数的研究

Qt原理-窥探信号槽的实现细节

Qt实用技能5-掌握信号槽使用细节

 

发布了505 篇原创文章 · 获赞 610 · 访问量 344万+
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!