一. 前言
在Qt
视觉项目中,一般需要用到信号和槽机制主要有两个地方:
- 软件功能模块和Qt界面的各个控件进行交互的时候,需要使用信号和槽机制来完成信息的传递。
- 视觉算法模块和上位机代码之间的信息传递需要通过信号和槽的机制来完成。
上面两者信号传递的方式本质是一样的,都是通过信号和槽的方式来完成信号的传递与接收,不同点就是前者的Qt
控件的触发信号是Qt
内部定义好的,我们定义一个槽函数直接用就可以;而后者各个类之间的信息传递是需要我们手动定义信号与槽函数来完成。
二. Qt界面控件信号传递
这里基本上都是和Qt界面上的一些按钮、复选框、编辑框等控件产生的触发信号,可以定义一个槽函数接收信号,也可以直接在connect
链接信号与槽时,直接完成信号的接收与处理:
按钮QPushButton
:
connect(ui.pushButton_compute, &QPushButton::clicked, this, [=]() { //槽函数实现 return; }
单选按钮QRadioButton
:
connect(ui.radioButton_imageLocate, &QRadioButton::toggled, this, [=](bool state) { //槽函数实现 ui.widget_view->clearImage(); ui.comboBox->clear(); if (m_imageViewLocate.size() > 0) { for (int index = 0; index < m_imageViewLocate.size(); index++){ ui.comboBox->addItem(QString::number(index + 1, 10)); } ui.comboBox->setCurrentIndex(m_imageID); ui.widget_view->setImage(m_imageViewLocate.at(m_imageID)); } });
下拉框QComboBox
:
connect(ui.cmbAffineType, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [=](int index) { //槽函数实现 int mFlag = index; ui.cmbAffineType->setItemData(1, "v", Qt::UserRole - 1); //设置第二行不可选中 });
计数器QSpinBox
:
connect(ui->spinBox_colNum, QOverload<int>::of(&QSpinBox::valueChanged),this, [=](int value) { //槽函数实现 int mFlag = value; });
浮点计数器QDoubleSpinBox
:
connect(ui.spbGlueAreaRatio_2, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, [=](double value){ //槽函数实现 int mFlag = value; });
三. 自定义信号传递
下面重点介绍一些第二种信号传递的方式,它涉及到了各个类之间的信号传递与接收。
3.1. 信号传递单类型数据(适用于传递的数据较少的情况)
功能需求:在视觉库中通过信号的形式传两个double
类型的数据给上位机项目代码
代码逻辑:
- 在基类
MU_InspUiBase
中定义信号,派生类GetMountOffset
的槽函数中发送信号(各个派生类(包含GetMountOffset
)继承基类MU_InspUiBase
,所以在基类MU_InspUiBase
中声明信号就相当于在各个子类中声明) - 在看项目代码中各个类之间的包含关系,我这里是基类数据
MU_InspUiBase
会传递到类MainUI
中,再由类MainUI
中传递到与软件的接口类VisionUI
中,最终上位机软件接收类VisionUI
中信号。
这里说的啰嗦了一点主要是想告诉大家,在信号传递之前要搞清楚代码中各个类之间的逻辑关系,才能层层递进完成信号的传递。
具体流程如下:
1、基类MU_InspUiBase
中定义信号
class MU_InspUiBase : public QWidget { Q_OBJECT signals: void SIG_calculateOffSetOK(double x, double y); };
2、基类MU_InspUiBase
的派生类GetMountOffset
中发送信号
#include "MU_InspUiBase.h" GetMountOffset::GetMountOffset(const char* _path, QWidget *parent) : MU_InspUiBase(parent) { emit SIG_calculateOffSetOK(x, y); }
3、类MainUI
中接收类GetMountOffset
发送的信号
#include"MU_InspUiBase.h" class MF_VISIONUI_EXPORT MainUI : public QWidget { Q_OBJECT signals: void SIG_calculateOffSetOK(double x, double y); private: MU_InspUiBase *m_InspUi = nullptr; };
//.cpp MainUI::MainUI(const char* _filePath, VISIONOPERATETYPE _functionOption, QWidget *parent) : QWidget(parent) { m_InspUi = new GetMountOffset(_filePath); connect(m_InspUi, &MU_InspUiBase::SIG_calculateOffSetOK, [this](double x, double y) { emit SIG_calculateOffSetOK(x, y); }); }
4、软件的接口类VisionUI
中重复上面的步骤:定义信号、接收信号、在发送信号,最终由上位机代码中接收该信号,获取其参数值。
注:判断信号有没有发送成功时,可以在connect处加个断点,打印一串代码,看看最终是否打印出来,如:
connect(m_InspUi, &MU_InspUiBase::SIG_calculateOffSetOK, [this](double x, double y) { qDebug() << "yyyyyy"; });
3.2 信号传递自定义结构体数据(适用于传递的数据较多的情况)
1、定义结构体,使用宏Q_DECLARE_METATYPE,向QT声明这个结构体
#include <QVariant> struct MS_MountOffset_SigResult { MS_MountOffset_SigResult() :m_offsetX(0), m_offsetY(0) {} double m_offsetX; //X方向补偿 double m_offsetY; //Y方向补偿 }; Q_DECLARE_METATYPE(MS_MountOffset_SigResult);
注:
①宏Q_DECLARE_METATYPE作用:对于自定义的结构体参数,信号槽无法识别参数,导致信号槽连接不起作用。所以需要在结构体中声明结束的地方加上结构体注册。
②自定义类型中一定要有默认构造函数,如果已经显式的定义了带有无默认参数的构造函数则需要另外写上默认构造函数 Test(){}。
③最好在类定义的头文件中加上#include < QVariant>,保证编译器能够识别该宏,否则可能会报错“错误提示: error C4430: 缺少类型说明符 - 假定为 int。”
2、定义信号和槽 — signals&slots
signals: void SIG_calculateOffSetOK(QVariant VarDetailInfo); slot: void slot_calculateOffSetOK(QVariant VarDetailInfo); QObject::connect(m_InspUi, SIGNAL(&SIG_calculateOffSetOK(QVariant)), this, SLOT(&slot_calculateOffSetOK(QVariant)), Qt::QueuedConnection);
3、在发送信号的位置将自定义结构类型封装成QVariant的形式
QVariant m_DataVar; m_DataVar.setValue(m_MountOffset_SigResult); emit SIG_calculateOffSetOK(m_DataVar);
注:m_MountOffset_SigResult
为定义的结构体MS_MountOffset_SigResult
的对象。
4、在接收信号的位置从封装中取出结构体参数
MS_MountOffset_SigResult m_MountOffset_SigResul_2; m_MountOffset_SigResul_2 = m_DataVar.value<MS_MountOffset_SigResult>();//m_DataVar为上面QVariant的对象
下雨天,最惬意的事莫过于躺在床上静静听雨,雨中入眠,连梦里也长出青苔。 |