QT开发(十三)——QT信号与槽机制

QT开发(十三)——QT信号与槽机制

1、QT消息模型

QT封装了具体操做系统的消息机制,遵循经典的GUI消息驱动事件模型。php

QT定义了与操做系统消息相关的本身的概念,即信号与槽。编程

信号signal是由操做系统产生的消息。安全

slot是程序中的消息处理函数。框架

connect将系统消息绑定到消息处理函数。ide

信号到槽的链接必须发生在两个QT对象间。函数

bool QObject::connect ( const QObject * sender, //发生对象工具

const char * signal, //消息名测试

const QObject * receiver, //接收对象spa

const char *method, //接收对象的成员函数操作系统

Qt::ConnectionType type = Qt::AutoConnection )

    在QT中消息使用字符串进行描述,connect函数在消息名和处理函数之间创建映射。

    QT中的关键字

    SIGNAL用于指定消息名

    SLOT用于指定消息处理函数名

    Q_OBJECT因此自定义槽的类必须在类声明的开始处加上Q_OBJECT

    slots用于在类中声明消息处理函数

2、信号与槽机制

    信号和槽机制是QT的核心机制,是一种高级接口,应用于QT对象之间的通讯,是QT的核心特性,也是QT区别于其它工具包的重要地方。信号和槽是QT自行定义的一种通讯机制,独立于标准的C/C++语言,要正确的处理信号和槽,必须借助一个称为moc(Meta Object Compiler)的QT工具,MOC工具是一个C++预处理程序,为高层次的事件处理自动生成所须要的附加代码。

    在QT中信号和槽取代了传统GUI框架中的回调函数,信号和槽能携带任意数量和任意类型的参数,是类型彻底安全的全部从QObject或其子类(如Qwidget)派生的类都可以包含信号和槽。当对象改变其状态时,信号就由对象发射(emit)出去,但对象不知道另外一端是谁在接收信号。槽用于接收信号,但是普通的对象成员函数。一个槽并不知道是否有任何信号与本身相链接并且对象并不了解具体的通讯机制。

一、信号

    当某个信号对其客户或全部者发生的内部状态发生改变,信号被一个对象发射。只有定义过这个信号的类及其派生类可以发射这个信号。当一个信号被发射时,与其相关联的槽将被马上执行,就象一个正常的函数调用同样。信号-槽机制彻底独立于任何GUI事件循环。只有当全部的槽返回之后发射函数(emit)才返回。 若是存在多个槽与某个信号相关联,当这个信号被发射时,这些槽将会一个接一个地执行,但执行的顺序将会是随机的,不能人为地指定哪一个先执行、哪一个后执行。

    信号的声明是在头文件中进行的,QT的signals关键字指出进入了信号声明区,随后便可声明本身的信号。

signals:

     void overflow();

    signals是QT的关键字,而非C/C++的。信号能够重载,但信号却没有函数体定义,而且信号的返回类型都是void,不要期望能从信号返回什么有用信息。

    信号由moc自动产生,不该该在.cpp文件中实现。

二、

    槽是普通的C++成员函数,能够被正常调用,惟一的特殊性就是不少信号能够与其相关联。当与其关联的信号被发射时,信号关联的槽就会被调用。槽能够有参数,但槽的参数不能有缺省值。

    槽是普通的成员函数,也有访问权限。槽的访问权限决定了谁可以与其相关联。同普通的C++成员函数同样,槽函数也分为三种类型,即public slots、private slots和protected slots。

    public slots:使用publicslots声明的槽表示任何对象均可将信号与之相链接。组件编程,能够建立彼此互不了解的对象,将它们的信号与槽进行链接以便信息可以正确的传递。

    protected slots:使用protected slots声明的槽表示当前类及其子类能够将信号与之相链接。适用于那些槽,它们是类实现的一部分,可是其界面接口却面向外部。

    private slots:使用private slots声明的槽表示只有类本身能够将信号与之相链接适用于联系很是紧密的类。

    槽也可以声明为虚函数。

    槽的声明也是在头文件中进行的。

public slots:

     void setValue(int value);

    自定义槽

    只有QObject的子类才能自定义槽

    定义槽的类必须在类声明的最开始处使用Q_OBJECT

    类中声明槽是须要使用slots关键字

    槽与所处理的信号在函数签名上必须一致

    SIGNAL与SLOT指定的名称中能够包含参数类型,不能包含具体的参数名

错误Object::connect:No such slot

A、检查类对象是否继承自QObject

B、检查类声明的开始处是否添加Q_OBJECT

C、检查是否使用slots对槽进行声明

D、检查槽的名称偏斜是否错误

E、从新编译工程

三、信号与槽的关联

    经过调用QObject对象的connect函数来将某个对象的信号与另一个对象的槽函数相关联,当发射者对象发射信号时,接收者对象的槽函数将被调用。connect函数的定义以下:

bool QObject::connect ( const QObject * sender, const char * signal, const QObject * receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection ) 

    connect函数的做用就是将发射sender对象中的信号signal与接收者receiver中的method槽函数联系起来。当指定信号signal时必须使用QT的宏SIGNAL(),当指定槽函数时必须使用宏SLOT()。若是发射者与接收者属于同一个对象的话,那么在connect 调用中接收者参数能够省略。

    一个信号可以与另外一个信号相关联,此时发射者发出信号后接收者的信号也会接着发射。

    当信号与槽没有必要继续保持关联时,可使用disconnect函数来断开链接

bool QObject::disconnect ( const QObject * sender, const char * signal, const QObject * receiver, const char *method ) 

    disconnect函数断开发射者中的信号与接收者中的槽函数之间的关联。

    在disconnect函数中0能够用做一个通配符,分别表示任何信号、任何接收对象、接收对象中的任何槽函数。可是发射者sender不能为0,其它三个参数的值能够等于0。

    如下三种状况须要使用disconnect()函数断开信号与槽的关联:

    A、断开与某个对象相关联的任何对象

    disconnect(sender, 0, 0, 0);

        sender->disconnect();

    B、断开与某个特定信号的任何关联

    disconnect(sender, SIGNAL(mySignal()), 0, 0);

        sender->disconnect(SIGNAL(mySignal()));

    C、断开两个对象之间的关联

    disconnect(sender, 0, receiver, 0);

        sender->disconnect(receiver);

    Qt利用信号与槽(signals/slots)机制取代传统的callback来进行对象之间的沟通。当操做事件发生的时候,对象会发提交一个信号(signal);而槽(slot)则是一个函数接受特定信号而且运行槽自己设置的动做。信号与槽之间,则经过QObject的静态方法connect来连接。

    信号在任何运行点上皆可发射,甚至能够在槽里再发射另外一个信号,信号与槽的连接不限定为一对一的连接,一个信号能够连接到多个槽或多个信号连接到同一个槽,甚至信号也可链接到信号。

    以往的callback缺少类型安全,在调用处理函数时,没法肯定是传递正确型态的参数。但信号和其接受的槽之间传递的数据型态必需要相符合,不然编译器会提出警告。信号和槽可接受任何数量、任何型态的参数,因此信号与槽机制是彻底类型安全。

    信号与槽机制也确保了低耦合性,发送信号的类的并不知道是哪一个槽会接受,也就是说一个信号能够调用全部可用的槽。此机制会确保当在"链接"信号和槽时,槽会接受信号的参数而且正确运行。

四、元对象工具

    元对象编译器moc(meta object compiler)对C++文件中的类声明进行分析并产生用于初始化元对象的C++代码,元对象包含所有信号和槽的名字以及指向函数的指针。

moc读C++源文件,若是发现有Q_OBJECT宏声明的类,就会生成另一个C++源文件,新生成的文件中包含有该类的元对象代码。例如,假设咱们有一个头文件mysignal.h,在这个文件中包含有信号或槽的声明,那么在编译以前 moc 工具就会根据该文件自动生成一个名为mysignal.moc.h的C++源文件并将其提交给编译器;对应于mysignal.cpp文件moc工具将自动生成一个名为mysignal.moc.cpp文件提交给编译器。

    元对象代码是signal/slot机制所必须的。用moc产生的C++源文件必须与类实现一块儿进行编译和链接,或者用#include语句将其包含到类的源文件中。moc并不扩展#include或者#define宏定义,只是简单的跳过所遇到的任何预处理指令。

    信号和槽函数的声明通常位于头文件中,同时在类声明的开始位置必须加上Q_OBJECT语句,Q_OBJECT语句将告诉编译器在编译以前必须先应用moc工具进行扩展。关键字signals是对信号的声明,siganls没有public、private、protected等属性,slots是对槽函数的声明,slotspublic、private、protected等属性。signals、slots关键字是QT 本身定义的,不是C++中的关键字。

    信号的声明相似于函数的声明而非变量的声明,左边要有类型,右边要有括号,若是要向槽中传递参数的话,在括号中指定每一个形式参数的类型,固然,形式参数的个数能够多于一个。

    关键字slots指出随后开始槽的声明,这里slots用的也是复数形式。

    槽的声明与普通函数的声明同样,能够携带零或多个形式参数。既然信号的声明相似于普通C++函数的声明,那么,信号也可采用C++中虚函数的形式进 行声明,即同名但参数不一样。例如,第一次定义的void mySignal()没有带参数,而第二次定义的却带有参数,从这里咱们能够看到QT的信号机制是很是灵活的。

    信号与槽之间的联系必须事先用connect函数进行指定。若是要断开两者之间的联系,可使用函数disconnect。

五、信号与槽机制的局限

    信号与槽是一种高效灵活的通讯机制,但有其缺陷:

    A、信号与槽的很是高效的,可是回调函数相比,因为增长了灵活性,所以在速度上有所损失,这种损失相对来讲是比较小的,经过在一台i586-133的机器上测试是10微秒(运行Linux),可见这种机制所提供的简洁性、灵活性仍是值得的。通常来讲,在实时系统中就要尽量的少用信号与槽机制。

    B、信号与槽机制与普通函数的调用同样,若是使用不当的话,在程序执行时也有可能产生死循环。所以,在定义槽函数时必定要避免在槽函数中再次发射所接收到的一样信号。

    C、若是一个信号与多个槽相关联,那么当这个信号被发射时,与之相关的槽函数调用的顺序将是随机的。

    D、宏定义不能用在信号的参数中。

    moc工具不扩展#define,在信号槽的参数中使用不能正确地工做,不带参数是能够的。

    E、构造函数不能用在signals或者slots声明区域内。

    F、函数指针不能做为信号或槽的参数。

    函数指针做为参数是不合语法,但可使用typedef将函数指针类型重命名,使用函数指针类型做为参数是合语法的。

    G、信号与槽不能有缺省参数。

    H、信号与槽也不能使用模板类参数

    可使用typedef重命名模板类,重命名后的类型名能够做为信号与槽的参数

    I、嵌套的类不能位于信号或槽区域内,也不能有信号或者槽。

    J、友元声明不能位于信号或者槽声明区内应该在普通C++的private、protected或者public区内进行声明

相关文章
相关标签/搜索