通过Qt内置的数据类型进行信号与槽参数传递很方便;如果是自己定义的类型如果想使用signal/slot来传递的话,则没有这么简单。直接使用的话,会产生下面这种错误:
QObject::connect: Cannot queue arguments of type ‘MyClass’ (Make sure ‘MyClass’ is registed using qRegisterMetaType().)
原因:当一个signal被放到队列中(queued)时,它的参数(arguments)也会被一起一起放到队列中(queued起来),这就意味着参数在被传送到slot之前需要被拷贝、存储在队列中(queue)中;为了能够在队列中存储这些参数(argument),Qt需要去construct、destruct、copy这些对象,而为了让Qt知道怎样去作这些事情,参数的类型需要使用qRegisterMetaType来注册(如错误提示中的说明)
步骤:(以自定义MyClass类型为例)
自定一种类型,在这个类型的顶部包含:#include
在类型定义完成后,加入声明:Q_DECLARE_METATYPE(MyClass);
在main()函数中注册这种类型:qRegisterMetaType(“MyClass”);
如果还希望使用这种类型的引用,可同样要注册:qRegisterMetaType(“MyClass&”);
#include
//必须包含QMetaType,否则会出现下面错误:
//error: expected constructor, destructor, or type conversion before ‘;’ token
#include
class MyClass {
public:
MyClass();
MyClass(int, QString);
int count();
QString text();
private:
int _count;
QString _text;
};
Q_DECLARE_METATYPE(MyClass); //在自定义类或者结构体等声明后紧接着用宏Q_DECLARE_METATYPE声明自定义自定义数据类型
#endif
示例二
#ifndef MEASCOMPONENT_H
#define MEASCOMPONENT_H
#include
#include
class MeasComponent : public QObject
{
Q_OBJECT
public:
explicit MeasComponent(QObject *parent = nullptr);
MeasComponent(const MeasComponent& obj);
signals:
public:
QString _name; //组份名称
QString _unit; //组份单位
float _value; //组份实测值
float _upperLimit; //组份上限
float _lowLimit; //组份下限
quint8 _status; //组份状态
};
Q_DECLARE_METATYPE(MeasComponent);
#endif // MEASCOMPONENT_H
qRegisterMetaType<MeasComponent>("MeasComponent"); //在main函数一开始的地方注册自定义类型
qRegisterMetaType<MeasComponent>("MeasComponent&"); //在main函数一开始的地方注册自定义类型
void MainWindow::on_pBtn_DeliverPara_clicked()
{
_meas_1._name = ui->lineEdit_name->text();
_meas_1._unit = ui->lineEdit_unit->text();
_meas_1._value = ui->lineEdit_value->text().toFloat();
_meas_1._status = ui->lineEdit_status->text().toUtf8().toShort();
_meas_1._lowLimit = ui->lineEdit_lowLimit->text().toFloat();
_meas_1._upperLimit = ui->lineEdit_upperLimit->text().toFloat();
emit sigDeliver(_meas_1);
if(dlg1.isHidden())
dlg1.show();
}
一、第一种模式,直接用在信号槽中使用自定义数据类型
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
qRegisterMetaType<MyClass>("MyClass"); //在main函数一开始的地方注册自定义类型
qRegisterMetaType<MyClass>("MyClass&"); //在main函数一开始的地方注册自定义类型
QObject::connect(&obj1, SIGNAL(writeText(MyClass&)), &obj2, SLOT(write(MyClass&)));
QObject::connect(&obj1, SIGNAL(writeText(MyClass&)), &obj2, SLOT(write(MyClass&)));
}
参考:https://blog.csdn.net/m0_37624078/article/details/82738183?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-0.essearch_pc_relevant&spm=1001.2101.3001.4242
二、第二种模式,通过QVariant类型中转
定义一个结构体
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>();