《《信号与槽》PPT课件.ppt》由会员分享,可在线阅读,更多相关《《信号与槽》PPT课件.ppt(31页珍藏版)》请在三一办公上搜索。
1、第二章 信号与槽,信号与槽是一种高级接口,应用于对象之间的通信,它是QT的核心特性。信号与槽机制是Qt中非常重要的机制,也是Qt中所特有的一种机制,几乎贯穿整个Qt的学习过程中。,信号与槽简介预定义信号与槽自定义信号与槽,本章要点:,在GUI用户界面中,当用户操作一个窗口部件时,需要其它窗口响应或者可以激活其它的操作。在我们所熟知的很多 GUI 工具包中,窗口小部件(widget)都有一个回调函数用于响应它们能触发的每个动作,这个回调函数通常是一个指向某个函数的指针。但是,在 QT 中信号与槽取代了这些凌乱的函数指针,使得我们编写这些通信程序更为简洁明了。,2.1 理解信号与槽,所有从 QOb
2、ject 或其子类(例如 Qwidget)派生的类都能够包含信号与槽。当对象改变其状态时,信号就由该对象发射(emit)出去,这就是对象所要做的全部事情,它并不知道另一端是谁在接收这个信号。这个过程就是真正的信息封装,它确保对象是被当作一个真正的软件组件来使用的。槽用于接收信号,但它们是普通的对象成员函数。一个槽并不知道是否有任何信号与自己相连接。而且,对象并不了解具体的通信机制。,信号与槽通过QObject:connect(const QObject*sender,const char*signal,const QObject*receiver,const char*method,Qt:Co
3、nnection type=Qt:AutoCompatConnection)函数关联,参数type 定义了信号与槽的关联方式,决定一个信号是立即传递到槽还是排队等待以后传递。,Qt:ConnectionType定义信号和槽关联方式有三种:Qt:DirectConnection:信号发送后立即传递给相关联的槽,只有槽函数执行完毕返回后,发送信号“emit”之后的代码才被执行。Qt:QueuedConnection:信号发送后排队,直到事件循环(event loop)有能力将它传递给槽,而不管槽函数有没有执行Qt:AutoCompatConnection:如果信号和槽在同一个线程,信号发出后槽函数
4、立即执行,Qt信号与槽机制的优点:类型安全的:需要关联的信号与槽的参数类型和参数个数必须是等同的。松散耦合的:Qt信号和槽机制减弱了Qt对象的耦合度。,当某个信号对其客户或所有者发生的内部状态发生改变,信号被一个对象发射。只有定义过这个信号的类及其派生类能够发射这个信号。当一个信号被发射时,与其相关联的槽将被立刻执行,就象一个正常的函数调用一样。信号与槽机制完全独立于任何 GUI 事件循环。如果存在多个槽与某个信号 相关联,那么,当这个信号被发射时,这些槽将会一个接一个地 执行;但是它们执行的顺序将会是随机的、不确定的,不能随意地指定哪个先执行、哪个后执行。,2.2 预定义的信号与槽实例,信号
5、的声明是在头文件中进行的,QT 的 signals 关键字指出进入了信号声明区,随后即可声明自己的信号。例如,下面定义了三个信号:signals:void mySignal();void mySignal(int x);void mySignalParam(int x,int y);,信号,槽是普通的 C+成员函数,可以被正常调用,它们唯一的特殊性就是很多信号可以与其相关联。当与其关联的信号被发射时,这个槽就会被调用。槽可以有参数,但槽的参数不能有缺省值。,槽,既然槽是普通的成员函数,因此与其它的函数一样,它们也有权限。槽的权限决定了谁能够与其相关联。同普通的 C+成员函数一样,槽函数也分为三
6、种类型:public slots:在这个区内声明的槽意味着任何对象都可将信号与之相连接。protected slots:在这个区内声明的槽意味着当前类及其子类可以将信号与之相连接。private slots:在这个区内声明的槽意味着只有类自己可以将信号与之相连接。,槽的声明也是在头文件中进行的。例如,下面声明了三个槽:public slots:void mySlot();void mySlot(int x);void mySignalParam(int x,int y);,通过调用 QObject 对象的 connect 函数来将某个对象的信号与另外一个对象的槽函数相关联,这样当发射者发射信号
7、时,接收者的槽函数将被调用。该函数的定义如下:bool QObject:connect(const QObject*sender,const char*signal,const QObject*receiver,const char*member),信号与槽的关联,一个信号甚至能够与另一个信号相关联,看下面的例子:class MyWidget:public QWidget public:MyWidget();.signals:void sig1();.private:.QPushButton*Button1;MyWidget:MyWidget()Button1=new QPushButton(
8、this);connect(Button1,SIGNAL(clicked(),SIGNAL(Sig1();,示例,当信号与槽没有必要继续保持关联时,我们可以使用 disconnect 函数来断开连接。其定义如下:bool QObject:disconnect(const QObject*sender,const char*signal,const Object*receiver,const char*member)static这个函数断开发射者中的信号与接收者中的槽函数之间的关联。,有三种情况必须使用 disconnect()函数:断开与某个对象相关联的任何对象。disconnect(myOb
9、ject,0,0,0)断开与某个特定信号的任何关联。disconnect(myObject,SIGNAL(mySignal(),0,0)断开两个对象之间的关联。disconnect(myObject,0,myReceiver,0),元对象编译器 moc(meta object compiler)对 C+文件中的类声明进行分析并产生用于初始化元对象的 C+代码,元对象包含全部信号与槽的名字以及指向这些函数的指针。元对象代码是 signal/slot 机制所必须的。用 moc产生的 C+源文件必须与类实现一起进行编译和连接,或者用#include 语句将其包含到类的源文件中。moc并不扩展#inc
10、lude 或者#define 宏定义,它只是简单的跳过所遇到的任何预处理指令。在编译完之后也会产生一个链接文件sigtest_moc.o。,元对象工具,信号与槽函数的声明一般位于头文件中,同时在类声明的开始位置必须加上 Q_OBJECT 语句;这条语句是不可缺少的,它将告诉编译器在编译之前必须先应用 moc 工具进行扩展。关键字 signals 指出随后开始信号的声明,siganls 没有 public、private、protected 等属性,这点不同于 slots。另外,signals、slots 关键字是 QT 自己定义的,不是 C+中的关键字。,程序样例,信号与槽之间的联系必须事先用
11、 connect 函数进行指定。如果要断开二者之间的联系,可以使用函数 disconnect。/tsignal.h.class TsignalApp:public QMainWindow Q_OBJECT./信号声明区 signals:void mySignal();/声明信号 mySignal()void mySignal(int x);/声明信号 mySignal(int)void mySignalParam(int x,int y);/声明信号 mySignalParam(int,int)/槽声明区 public slots:void mySlot();/声明槽函数 mySlot()vo
12、id mySlot(int x);/声明槽函数 mySlot(int)void mySignalParam(int x,int y);/声明槽函数 mySignalParam(int,int),./tsignal.cpp.TsignalApp:TsignalApp()./将信号 mySignal()与槽 mySlot()相关联 connect(this,SIGNAL(mySignal(),SLOT(mySlot();/将信号 mySignal(int)与槽 mySlot(int)相关联 connect(this,SIGNAL(mySignal(int),SLOT(mySlot(int);/将信
13、号 mySignalParam(int,int)与槽 mySlotParam(int,int)相关联connect(this,SIGNAL(mySignalParam(int,int),SLOT(mySlotParam(int,int);,/定义槽函数 mySlot()void TsignalApp:mySlot()QMessageBox:about(this,Tsignal,This is a signal/slot sample without parameter.);/定义槽函数 mySlot(int)void TsignalApp:mySlot(int x)QMessageBox:ab
14、out(this,Tsignal,This is a signal/slot sample with one parameter.);,/定义槽函数 mySlotParam(int,int)void TsignalApp:mySlotParam(int x,int y)char s256;sprintf(s,x:%d y:%d,x,y);QMessageBox:about(this,Tsignal,s);void TsignalApp:slotFileNew()/发射信号 mySignal()emit mySignal();/发射信号 mySignal(int)emit mySignal(5)
15、;/发射信号 mySignalParam(5,100)emit mySignalParam(5,100);,信号与槽机制是比较灵活的,但有些局限性我们必须了解,这样在实际的使用过程中做到有的放矢,避免产生一些错误:信号与槽的效率是非常高的,但是同真正的回调函数比较起来,由于增加了灵活性,因此在速度上还是有所损失;当然这种损失相对来说是比较小的,但如果我们要追求高效率的话;比如在实时系统中,就要尽可能的少用这种机制。,应注意的问题,信号与槽机制与普通函数的调用一样,如果使用不当的话,在程序执行时也有可能产生死循环。因此,在定义槽函数时一定要注意避免间接形成无限循环,即在槽中再次发射所接收到的同样
16、信号。防止形成死循环。如果一个信号与多个槽相联系的话,那么,当这个信号被发射时,与之相关的槽被激活的顺序将是随机的。宏定义不能用在 signal 和 slot 的参数中。既然 moc 工具不扩展#define,因此,在 signals 和 slots 中携带参数的宏就不能正确地工作,如果不带参数是可以的。,构造函数不能用在 signals 或者 slots 声明区域内。的确,将一个构造函数放在 signals 或者 slots 区内有点不可理解,无论如何,不能将它们放在 private slots、protected slots 或者 public slots 区内。函数指针不能作为信号或槽的
17、参数。信号与槽不能有缺省参数。既然 signal-slot 绑定是发生在运行时刻,那么,从概念上讲使用缺省参数是困难的。信号与槽也不能携带模板类参数。如果将信号、槽声明为模板类参数的话,即使 moc 工具不报告错误,也不可能得到预期的结果。,嵌套的类不能位于信号或槽区域内,也不能有信号或者槽。友元声明不能位于信号或者槽声明区内。相反,它们应该在普通 C+的 private、protected 或者 public 区内进行声明。,在这里看一个具体的实例,在日常生活中是很常见的计算器。,2.3 创建和使用用户信号与槽,这界面上有很多按键,实现了计算器的一些简单功能,以及一些科学计算器的功能。当然,一个完整的QT应用好包括其它的一些知识;比如这个应用,布局也是其中的一个重点内容,但是这里主要讲的就是有关信号与槽的应用,其它的内容在后面的章节大家会介绍。,谢 谢!,