Qt信号槽使用结构体作为参数:Q_DECLARE_METATYPE和qRegisterMetaType的作用

简介: Qt信号槽使用结构体作为参数:Q_DECLARE_METATYPE和qRegisterMetaType的作用

问题由来


定义一个结构体


struct myStruct

{

 int a;

 float b;

};

通过信号槽传递该结构体


connect(this, SIGNAL(m_signal(myStruct)), this, SLOT(m_slot(myStruct)));

这样做是行不通的,正确的做法:

通过Q_DECLARE_METATYPE声明自定义的结构体


struct myStruct

{

 int a;

 float b;

};

Q_DECLARE_METATYPE(myStruct);


然后以QVariant代替自定义的结构体


connect(this, SIGNAL(m_signal(QVariant)), this, SLOT(m_slot(QVariant)));

在发射信号前,将自定义结构体打包为QVariant


myStruct mstruct;

QVariant data;

data.setValue(mstruct);

emit signal_child(data);


在槽函数中,解析QVariant


myStruct mstruct = data.value<myStruct>();


注册元类型


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


下面这几个类型是自动注册的,不需要使用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);


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


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


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



官方文档


https://wiki.qt.io/New_Signal_Slot_Syntax


https://woboq.com/blog/new-signals-slots-syntax-in-qt5.html


https://woboq.com/blog/how-qt-signals-slots-work.html


https://woboq.com/blog/how-qt-signals-slots-work-part2-qt5.html


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


相关文章
|
4天前
Qt第二课 核心机制信号槽
Qt第二课 核心机制信号槽
10 1
|
4天前
|
存储 API C++
【Qt 信号槽】深入探索 Qt 信号和槽机制中的引用传递“ (“A Deep Dive into Reference Passing in Qt Signal and Slot Mechanism“)
【Qt 信号槽】深入探索 Qt 信号和槽机制中的引用传递“ (“A Deep Dive into Reference Passing in Qt Signal and Slot Mechanism“)
62 0
|
4天前
【qt】核心机制信号槽(下)
【qt】核心机制信号槽(下)
8 1
|
4天前
|
消息中间件 存储 安全
深入理解 Qt 信号槽:高效沟通的桥梁
深入理解 Qt 信号槽:高效沟通的桥梁
69 1
|
4天前
|
开发框架 算法 Linux
【知识点回顾 】Qt信号槽与Linux信号处理 的处理机制 深入探讨
【知识点回顾 】Qt信号槽与Linux信号处理 的处理机制 深入探讨
43 0
|
4天前
|
消息中间件 算法 开发者
【Qt面试题】多线程情况下, Qt中的信号槽分别在什么线程中执行, 如何控制?
【Qt面试题】多线程情况下, Qt中的信号槽分别在什么线程中执行, 如何控制?
26 1
|
4天前
|
安全 编译器 C++
【Qt 面试题】Qt信号槽机制与优势与不足
【Qt 面试题】Qt信号槽机制与优势与不足
38 1
|
4天前
Qt6学习笔记二(信号槽)
Qt6学习笔记二(信号槽)
52 0
|
9月前
|
编译器 C++
【Qt】信号槽的三种连接形式
三种形式的信号槽连接,connect 语法...
92 0

推荐镜像

更多