前面一些章节其实已经在使用信号和槽了,但是作为Qt中最重要的机制也是Qt区别与其他开发平台的重要核心特性,还是非常有必要单独介绍。
信号和槽是Qt特有的信息传输机制,是Qt设计程序的重要基础,它可以让互不干扰的对象建立一种联系。
信号和槽用于对象间的通信,在一个图形界面程序中,当一个部件中发生变化时,通常需要通知其他对象,在Qt中当采用特定事件发生时会发射(注意此处用的是发射(emit)而不是发送,老猿估计是因为这里的信号不是一对一发送的,而是可以一对多发射)一个信号来通知需要通知的对象,需要关注的对象就会调用信号连接的槽函数执行响应操作。
从QObject或其子类(如QWidget)继承的所有类都可以包含信号和插槽。
当对象以其他对象可能感兴趣的方式改变其状态时,它们会发出信号。
Qt中的信号本质上是一个公有函数(即方法),信号只需声明,不能对其进行定义,声明函数时不能有返回值。由于信号是某个对象的公有方法,信号可以从任何地方通过emit语句发出,与直接调用信号对应函数类似,只是在函数调用语句前多了个emit。
发射信号的语句:emit 信号函数(信号参数)
Qt建议只从定义信号的类及其子类的类发出信号,Qt中的部件(又称为控件、组件)都有一些预定义的信号,如按钮的clicked()信号。信号发出方不知道也不关心是否有对象在接收它发出的信号
槽可以用来接收信号,但槽也是部件派生类的正常成员函数,槽本质上是某个类的方法(包括虚方法),用来调用以响应特定信号,非虚函数的槽函数也可以正常调用,与普通成员方法的唯一的区别是信号可以连接到它们。
由于槽是普通成员方法,所以当直接调用时,它们遵循正常的成员方法调用规则。但是,作为槽,它们可以由任何组件通过信号连接调用,不管槽函数的访问级别是公开还是私有,信号的发射者无需知道哪些对象会执行槽函数响应它发射的信号(老猿认为由于Python的封装机制,这点在PyQt中意义不大)。
就像一个对象不知道是否有任何东西接收到它的信号一样,槽也不知道是否有任何信号连接到它。
处理信号通常的做法是对可视部件进行子类化并添加对应的槽,以便处理感兴趣的信号。
当信号发
出时,通常与之相连的槽像正常的函数调用一样会立即执行,所有槽都返回后,将执行信号发出的emit语句后面的代码。但在信号和槽连接使用队列连接(connect函数的type参数值为Qt.QueuedConnection,使用Qt Designer定义的信号和槽连接通过PyUIC生成的代码不会使用该值)时情况略有不同,在这种情况下,emit关键字后面的代码将立即继续,槽将在稍后执行。
如果多个槽连接到一个信号,则当信号发射时,槽函数将按照建立连接的顺序依次执行。
与其他平台用于对象间通信的回调函数机制相比,信号和槽的机制稍微慢一些,发射与某些槽相连的信号,比用槽函数直接调用响应慢约十倍(不考虑槽函数本身的执行时间,只是从信号发射到槽函数开始执行的时间),但这种机制提供的灵活性增加了。
槽函数可能与多个对象的多个信号连接,有时代码需要判断信号是哪个对象发送的,此时可以使用在槽函数中使用sender()函数获取信号的发送对象来进行不同的处理。具体可参考:《PyQt学习随笔:槽函数获取信号发送对象的方法》
Qt的signal s和slots机制确保,如果将一个信号连接到一个slot,该slot将在正确的时间使用信号的参数调用。在Qt中,信号和插槽可以接受任意数量的任何类型的参数,但老猿认为在PyQt中可能存在一些限制。
信号和槽的参数必须匹配体现在以下方面:
QAbstractButton *
类型在实现槽函数时应该作为QAbstractButton
类型处理。这种松耦合表现在发出信号的对象既不知道也不关心哪个槽接收信号,槽也不知道有哪些信号连接到它。从某种程度上讲,信号和槽是类似电视节目和观众之间的关系。电视节目播放类似于信号发射,观众观看节目类似于槽,观众选择自己感兴趣的节目观看就是建立信号与槽的连接。
因Qt在其类库中预定义了很多信号和槽,因此在Qt中可以仅使用Qt类库中预定义的信号和槽,也可以只使用Qt类库中预定义的信号而使用自已的槽,也可以使用Qt类库中预定义的槽来响应自已定义的信号,当然,槽和信号也都可以使用自定义的( 关于自定义信号本节不进行进一步探讨)。
在信号和槽连接之后,connect方法会返回一个QMetaObjec.Connection类型的连接句柄,通过该句柄调用 disconnect()就可以断开信号和槽的连接。
在Qt Designer中可以自定义信号,但本节只介绍使用已有信号的操作方法。
要定义一个新的槽方法,通过Edit->Edit Signals/Slots或F4快捷键进入信号和槽编辑界面,如图:
进入编辑界面后双击要新增槽函数的部件或者从发射信号的部件开始使用鼠标画连接线,线的终点为槽函数所在部件(一般在窗口对象),释放鼠标后调出配置界面,如图为从pushButton发出信号到窗口的槽函数建立连接的案例:
点击上图中蓝色标记的Edit按钮,如图:
点击上图中的加号就可以增加新的槽函数。
进入信号和槽的编辑界面后,可以通过鼠标在编辑界面右侧的信号列表中选择对应信号,在槽函数列表中选择对应槽函数,点击OK保存退出,就完成了信号和槽函数的连接建立。如图:
注意:
除了3.3部分介绍的信号和槽函数的连接方法之外,还可以在Designer右侧的信号和槽函数编辑界面进行信号和槽函数连接。如图黄色荧光笔标记窗口:
点击下面蓝色标记的加号,新增一条可以编辑记录,选择每个字段鼠标双击进行编辑,如图:
退出编辑状态后相关连接自动保存。
这种方式与第一种方式相比,有如下不同:
本节详细介绍了Qt中信号和槽的概念,同时详细阐述了PyQt中与Qt中使用的一些差别,并详细介绍了Qt Designer中的操作方法,有助于大家深入理解信号和槽的概念,并熟练使用。