1. 发现问题
今天使用信号与槽遇到一个这样的问题,我自定义了一个信号类型:
signals: void update_product_info(int, ProductInfoSign);
ProductInfoSign的定义:
struct Version_info { unsigned char m_ver; unsigned char s_ver; unsigned char year_h; unsigned char year_l; unsigned char month; unsigned char day; }; union ProductInfoSign { unsigned int calendarinfo; Version_info versioninfo; };
自定义槽函数,在里面打印info.calendarinfo的值:
void ProductInfo::update_product_info_data(int read_mode, ProductInfoSign info) { qDebug("info.calendarinfo = %#x", info.calendarinfo); }
连接信号与槽:
connect(serialsign, SIGNAL(update_product_info(int, ProductInfoSign)), this, SLOT(update_product_info_data(int, ProductInfoSign)));
使用emit发出信号,并且在发送信号之前用qDebug打印info.calendarinfo的值,代码如下:
qDebug("info.calendarinfo = %#x", info.calendarinfo); emit update_product_info(temp, info);
这样编译没有问题,但是运行的时候却出了问题,最后两次打印的结果如下:
info.calendarinfo = 0x88776655 info.calendarinfo = 0xdb3d9b80
第一行是发送信号之前打印的,这个结果是正确的,第二行是在槽函数中打印的,这个结果是不对的,而且看上去好像两个数之间没有任何联系,并且每次软件重启之后第二个数都不一样,因此我意识到可能是QT信号与槽的机制的问题。
2. 解决问题
2.1 首先需要用Q_DECLARE_METATYPE宏声明自定义的数据类型
struct Version_info { unsigned char m_ver; unsigned char s_ver; unsigned char year_h; unsigned char year_l; unsigned char month; unsigned char day; }; union ProductInfoSign { unsigned int calendarinfo; Version_info versioninfo; }; Q_DECLARE_METATYPE(ProductInfoSign)
比如我想将ProductInfoSign类型的参数作为信号与槽的参数,那么我就在定义了ProductInfoSign之后用Q_DECLARE_METATYPE(ProductInfoSign)声明一下,不过虽然ProductInfoSign中又包含了另外一个自定义的数据类型, 另外的自定义的数据类型是不需要声明的。
2.2 自定义的参数类型要使用QVariant类型
虽然我们想传递的参数类型是ProductInfoSign,但是不能直接传递ProductInfoSign类型,而是要借助QVariant类型,最后类似于将ProductInfoSign中的内容放到了QVariant中去。好像还是不能传递自定义的类型,但是问题不大,我们关注的不是数据类型,而是数据内容。
于是信号与槽的相关部分代码改成这样:
自定义信号类型:
signals: void update_product_info(int, QVariant);
自定义槽函数:
void ProductInfo::update_product_info_data(int read_mode, QVariant dataVar);
连接信号与槽:
connect(serialsign, SIGNAL(update_product_info(int, QVariant)), this, SLOT(update_product_info_data(int, QVariant)));
2.3 对QVariant进行注册
在connect之前要调用这个函数:
qRegisterMetaType<QVariant>("QVariant");
这是因为信号和槽的参数类型并不认识QVariant。
那么问题来了,既然注册了QVariant之后信号与槽就认识QVariant了,那么直接注册自己定义的数据类型不就完了吗?比如我想要传递的数据类型是ProductInfoSign,那我直接注册ProductInfoSign不就完了吗?为什么非得用QVariant类型?事实上网上查到的资料确实有按照这个想法去弄的,但问题是我按照这个方法试了结果是不行。
2.4 发出信号时将自己的数据转变为QVariant类型
QVariant DataVar;
DataVar.setValue(info);
emit update_product_info(temp, DataVar);
上面代码中要先定义一个QVariant类型的数据,然后调用DataVar.setValue(info); info就是自己定义的数据,最后发出信号的时候传递的参数是QVariant类型的数据。
2.5 接收信号时将QVariant类型的数据转变为自定义的数据类型
槽函数这么写:
void ProductInfo::update_product_info_data(int read_mode, QVariant dataVar) { ProductInfoSign info = dataVar.value<ProductInfoSign>(); qDebug("info.calendarinfo = %#x", info.calendarinfo); }
这样一来发出的数据就和接收的数据一致了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
2019-01-07 linux执行可执行文件时报xxx:not found