自学内容网 自学内容网

Qt信号和槽

信号和槽的概念

 在Linux中我们也学过信号 Signal,这是进程间通信的一种方式,这里大致分为三个要素:
信号源:谁发送的信号(用户进程,系统内核,终端或者作业控制,)
信号的类型:哪种类别的信号

信号的处理方式:注册信号处理函数,在信号被触发时自动调用执行。

Qt信号和Linux的信号虽然不是同一个概念,但是有很多相似之处。、

在Qt中,谈到信号,也是三个要素:

信号源:由哪个控件发出的。
信号的类型:用户进行不同的操作,就会发送不同的信号。比如点击按钮,在输入框中移动光标

信号的处理方式:也就是槽(slot),其实也就是一个函数。Qt中用connect这样的函数,将一个信号和一个槽关联起来,后续只要信号触发了,就会自动执行槽函数。

槽函数本质也是一种 “回调函数”

关于connect函数 

connect和Linux TCP Socket 中建立连接的函数没有任何关联。

connect是Qt中,QObject类中的一个静态成员函数。

在Qt提供的这些类中,本身是存在一些继承关系的。

QObject可以说是Qt所有内置类的 “祖宗类” 

关于connect的具体使用方式:
 这里的第2 4个参数是Qt5以前的,在Qt5以后就使用了泛型类型。

另外,关于这个信号其实也是Qt中的对象中的一些成员函数,现在有这样一个代码:

这个代码就是创建了一个按钮,当我们点击按钮的时候,这个Widget的窗口就会关闭。

可以看到,关于信号我用的是QPushButton中的clicked,但是这个clicked不一定就是在QPushButton中定义的,而是在它的父类中定义的

将光标移动到clicked上,可以看到

 这里可以看到它的参数类型,返回值,包括注释中提示了它是一个qt_signal,下面还可以看到它是在哪个类的成员函数。

再看一下槽函数close

 

同样可以看到,并且它是QWidget内置的函数 

而我们的Widget就继承自QWidget

当我们想查看某个函数的具体定义时,可以将光标移动到函数上,然后 ctrl + 左键即可跳转到定义

自定义槽函数 

 在Qt5以及更高版本中,自定义一个槽函数的过程跟自定义一个普通的成员函数没有什么区别。

这种定义的方式我们之前也是用过的。

 还有一种自定义的方式:
在图形化界面这里:

右键一个控件后,有一个转到槽

这里面就把这个控件能用到的信号全部展示了出来,包括有它的父类的信号,也有它的父类的父类的信号。

比如我们之前用的clicked。点击之后

就会自动帮我们生成一个槽函数的定义:

 在这里我们就只需要编写我们槽函数的代码即可。

发现是没有问题的。

因此:在Qt中,除了通过connect来连接信号槽之外,还可以通过函数名字的方式来自动连接。

这个函数的名字要符合以下格式:

on_(这个对象的名字)_(信号的名字) 

 如果不符合这样的格式,那么就不会连接成功。

另外,我们刚刚是通过图形化界面的方式创建的控件,想要以这种方式来连接槽函数还需要一个前提:

在我们自动生成的ui_widget.h中会自动调用这个。

总结:
如果图形化界面创建控件的话,推荐使用第二种这样快速的方式来设置连接槽函数 

如果是以代码的方式创建控件的话,那还是需要用connect手动连接槽函数,因为在我们的代码中并没有调用:connectSlotsByName

自定义信号

自定义槽函数还是非常关键和常见的。

但是自定义信号就比较少见了,在GUI中,用户能够进行哪些操作,其实是可以穷举的。

在Qt内置的信号里,已经足以覆盖绝大部分使用场景了。

Qt信号本质也是一个函数。

但是这个函数比较特殊,我们程序员只需要写出函数的声明,并且告诉Qt这是一个信号,那么Qt就会在编译时自动帮我们生成函数的定义,并且这个过程程序员是无法干预的。

关于这个信号函数:它的返回值必须是void,有没有参数都可以,甚至还可以重载。

在声明信号函数前,要加上 signals: 这样的关键字:

这也是Qt自己扩展出来的关键字。

这里展示一下自定义信号的过程:
首先定义好自定义信号和槽函数:

关于自定义槽函数那里这个写法是为了提高代码可读性,说明这是一个槽函数,在Qt5以前的版本,是必须要这样写的。

关于这个槽函数的定义:

 然后再调用connect进行连接

注意这里发出信号的对象和执行槽函数的对象。

最后,我们该怎样将这个信号发射出去呢?
我们可以选一个它会在哪里发送:
假设我们将其放在另一个槽函数中:

这是按钮1的将来触发信号会执行的槽函数。

点击之后,我们的信号确实就被发送了,也执行了我们设置的槽函数。

这里又有一个关键字 emit,这个关键在Qt5以及更高版本中可以不加,但是还是建议加上,因为可以提高代码的可读性,告诉程序员这是在发送信号:

还有一个函数就是 disconnect,顾名思义就是解除某一个信号和槽函数的连接,它的参数和connect大致相同,只是执行的操作相反,在实际开发中也使用的较少。

不过如果是Qt自动连接的槽函数,那么想使用disconnect的解除连接,可能会不行。 

关于带参数的信号和槽 

到这里我们已经清楚,Qt中的信号和槽其实就是一个函数,那么它们也是可以有参数的。

这里的参数有这样的规定,那就是:
带有参数的信号,要求信号的参数和槽的参数一致(类型要一致)。

 但是信号的参数可以比槽函数的参数多,如果多了的话,槽函数就会按照参数的顺序,拿到信号的前N个参数;但是参数少了不行。

另外,在Qt中,我们发现在Qt的某个类的最开始的地方都有一个宏:

这是Qt的硬性规定,只有有这个宏,才能让类使用信号槽。

为什么要有信号槽机制

 在其它的GUI的框架中,一般都是一对一的关系,就是一个控件就对应一个函数。

但是Qt这里既可以一对一,也可以一对多,还可以多对多。

但是实际开发中,一对一就已经满足绝大部分场景了。

总结:
Qt设计信号槽的原因:

1.想把触发 用户操作的控件和处理对应用户的操作逻辑进行解耦合。

2.实现多对多的效果。

使用lambda表达式 

用connect进行连接槽函数,这个槽函数我们也可以通过lambda表达式的方式传入。

对于一些很简单的槽函数,并且是一次性使用的,我们直接传入一个lambda表达式即可。

并且捕获的时候,建议使用值捕获,因为在Qt中,捕获的一般都是控件的指针,如果是引用的话,那么还得关注这个变量的生命周期。


原文地址:https://blog.csdn.net/m0_74099572/article/details/143784109

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!