【Qt初识】信号槽(二):自定义信号函数与槽函数
大家好我是Halcyon.平安欢迎文末添加好友交流共同进步目录一、自定义槽函数1.1 背景1.2 实现二、自定义信号函数三、带参的信号函数和槽函数3.1 为什么要带参数3.2 参数规则补充说明3.3 代码演示3.4 参数个数不一致的情况目录一、自定义槽函数1.1 背景在以前的Qt版本中槽函数必须放在public/procted/privatedslots;slots是Qt自己扩展出来的关键字它并不是C的标准语法。Qt是广泛使用元变成技术基于代码生成代码。qmake在构建Qt项目的时候就会调用专门的扫描机器识别代码中的特定关键词如slots然后根据特定的关键字去生成一大段相关的代码。但是在Qt5这个新版本中我们则可以不用这样很大的简洁了代码毕竟谁不喜欢哪样简单用哪样呢但是我还是推荐大家使用关键字因为这样写起来是更加的规范1.2 实现方式一我们这里通过自定义槽函数来实现通过点击按钮然后改变窗口标题来看看效果首先我们自己新建一个项目然后去widget.h进行声明,然后去.cpp进行函数的实现并用connect进行连接。publicslots:voidhandleclicked();接下来进行槽函数的实现#includewidget.h#includeui_widget.h#includeQPushButtonWidget::Widget(QWidget*parent):QWidget(parent),ui(newUi::Widget){ui-setupUi(this);QPushButton*pushbuttonnewQPushButton(this);pushbutton-setText(按钮);connect(pushbutton,QPushButton::clicked,this,Widget::handleclicked);}Widget::~Widget(){deleteui;}voidWidget::handleclicked(){this-setWindowTitle(恭喜你转换成功);}因为我使用的版本是Qt5.14的所以如果我不在widget.h中public slots声明这个函数也是可以运行实现的但是为了代码的规范性所以是加上了方式二我们其实还可以用第二种方式那句是在widget.ui中拖动按钮然后右键选择转到槽选择后自动生成好一个函数定义声明然后我们自己去函数里编写代码即可因为我们的信号类型是点击按钮所以选择clicked即可随后会自动跳到自动生成的函数编写代码处我们来验证一下我们可以看到自动生成的是使用private slots进行声明限定我们来编写自定义槽函数代码试试#includewidget.h#includeui_widget.hWidget::Widget(QWidget*parent):QWidget(parent),ui(newUi::Widget){ui-setupUi(this);}Widget::~Widget(){deleteui;}voidWidget::on_pushButton_clicked(){this-setWindowTitle(恭喜你成功转换)}我们发现在第二种方法并没有通过connect连接信号和槽但是槽函数效果的成功演示证明了着信号和槽进行了连接那我们该如何进行理解呢其实在Qt中除了通过connect来连接信号槽之外还可以通过函数名字来进行信号和槽的连接所以我们来看看自动生成的槽函数的名称on_pushButton_clickedon是固定写法pushButton是Qt Designer给我们自动生成的按钮的属性objectName对应的值pushButton关于按钮属性之前是讲过的clicked信号函数的名称这就刚好符合connect函数要的前两个参数信号源信号类型那么第三个参数就是当前on_pushButton_clicked所在的类第四个参数就是on_pushButton_clicked这个自定义槽函数这必须一一对应如果哪一个参数你修改了的话就都会运行失败相对于自己写代码完成信号和槽函数的连接的话我更推荐图形化创建控件因为图形化创建控件更加的快速能够自动连接不需要我们自己手动去建立联系二、自定义信号函数信号其实就相当于对应的是用户的操作比如点击按钮等。我们上面讲的自定义槽函数其实在开发中是占很大部分的很多情况这个触发某个信号操作后的业务逻辑都需要我们自己去写但是信号不一样Qt内置的信号已经基本覆盖了这些操作Qt信号本质上也是一个函数它有两个比较特殊的点我们只需要写函数声明并告诉Qt这是一个“信号”定义会在Qt的编译中自动生成。作为信号函数返回类型必须是void对于参数的话有没有都可以甚至是可重载的我们说需要告诉Qt这是一个信号那么该如何告诉对signals,我们需要用到这个关键字但是我们建立连接其实并不代表发射信号那么我们如何发出信号呢那就需要emit来进行发射其实内置信号也是需要发射的但是发射信号已经内置到了Qt的框架中不需要我们自己去手动触发接下来我们来自定义一个信号函数来加深理解signals:voidmysignal();publicslots:voidhandleMysignal();#includewidget.h#includeui_widget.hWidget::Widget(QWidget*parent):QWidget(parent),ui(newUi::Widget){ui-setupUi(this);connect(this,Widget::mysignal,this,Widget::handleMysignal);}Widget::~Widget(){deleteui;}voidWidget::handleMysignal(){this-setWindowTitle(自定义信号函数关联自定义槽函数成功);}有没有发现什么问题那就是我们上面说的建立连接其实并不代表发射信号需要emit来进行发射{ui-setupUi(this);connect(this,Widget::mysignal,this,Widget::handleMysignal);emitmysignal();}接下来我们来看看效果三、带参的信号函数和槽函数信号函数带参数的时候起到复用代码的作用是必须要求和槽函数的参数类型必须与信号一致但是个数可以不一致。虽然个数可以不一致但是信号函数的参数个数必须大于槽函数的参数个数。那么为什么个数可以不一致呢因为一个槽可以绑定多个信号非要要求参数个数一致的话信号绑定槽的要求更高没那么灵活3.1 为什么要带参数我们前面写的信号和槽都是不带参数的但是大家想想在实际开发中光靠一个信号来了这种干巴巴的通知是远远不够的比如我们窗口中有两个按钮点击哪一个都要触发同一个槽函数去修改窗口标题那到底要改成什么内容这时候光靠信号本身已经不够用了必须让信号把具体的内容也一起带过去这就是信号和槽带参数的意义——让信号在触发的同时把数据顺带传递给槽函数这样槽函数就能根据传过来的参数去执行不同的逻辑从而起到复用代码的作用3.2 参数规则补充说明我们把上面的规则再换个角度理解一下信号是发送方槽是接收方发送方发送出去的东西接收方可以选择全部接收也可以选择只接收前面几个但是发送方都没发出去的东西接收方又怎么可能凭空收得到呢所以槽函数的参数个数绝对不能超过信号函数的参数个数这也就是为什么必须是信号 槽另外参数类型也得对得上比如信号传的是QString槽也得用QString接收类型不匹配的话编译是会报错的3.3 代码演示我们来自定义一个带参数的信号函数和槽函数让信号把一个字符串带过去槽函数接收后把它设置成窗口标题首先是widget.h中的声明signals:voidmysignal(QString text);publicslots:voidhandleMysignal(QString text);然后是widget.cpp中的实现和连接#includewidget.h#includeui_widget.hWidget::Widget(QWidget*parent):QWidget(parent),ui(newUi::Widget){ui-setupUi(this);// 建立连接信号和槽的参数类型一致个数也一致connect(this,Widget::mysignal,this,Widget::handleMysignal);// 发射信号并把字符串作为参数一起传过去emitmysignal(带参信号成功触发了);}Widget::~Widget(){deleteui;}voidWidget::handleMysignal(QString text){this-setWindowTitle(text);}运行后我们就能看到窗口标题被成功修改了这说明信号在发射的时候确实把字符串 text 这个参数顺带传给了槽函数槽函数接收到之后用它来设置窗口标题3.4 参数个数不一致的情况上面是参数个数一致的情况那么我们前面说的个数可以不一致又是怎样的呢我们把槽函数的参数省略掉试试signals:voidmysignal(QString text);publicslots:voidhandleMysignal();// 槽函数不接收参数这样同样是合法的信号带了参数槽函数可以选择性失明只接收信号触发的这个时机不接收信号带的数据这就是 Qt 信号槽给我们提供的灵活之处但是要注意如果反过来信号没有参数而槽函数却有参数那就是不行的了因为槽函数需要的参数信号根本就没传过来这就违背了我们前面讲的信号 槽的规则运行时也就不会得到我们想要的结果