Qt 信号和槽函数

信号和槽是一种高级接口,应用于对象之间的通讯,它是 QT 的核心特性。当某个信号被发射,就须要调用与之相绑定的槽函数。这与Windows下的消息机制相似,消息机制是基于回调函数。一个回调便是一个函数的指针,所以若是但愿一个处理函数通知一些事件,能够传递一个函数(回调函数)的指针给这个处理函数。这个处理函数就会在适当的时候调用回调函数。可是回调函数有两大缺点:第一,它们不是类型安全的。咱们历来不敢肯定处理函数会用正确的参数来调用回调函数;第二,回调函数被强力和处理函数联系着,由于处理函数必须知道去调用哪一个回调函数。编程

信号和槽的机制是类型安全的:一个信号的签名必须与接收槽的签名相匹配。(实际上一个槽可能有一个比它所接收到的信号的签名更短的签名由于它可以忽略额外的参数。)由于签名是一致的,因此编译器可以帮助咱们发现类型不匹配。信号和槽是松散的联系在一块儿的:一个发射信号的类历来不知道也不关心哪一个槽接收这个信号。Qt的信号和槽机制确保若是你将一个信号和一个槽链接起来,这个槽将在正确的时间被用这个信号的参数所调用。信号和槽能够带任何数量任何类型的参数。它们彻底是类型安全的。安全

信号(Signals)

当对象改变其状态时,信号就由该对象发射 (emit) 出去,并且对象只负责发送信号,它不知道另外一端是谁在接收这个信号。这样就作到了真正的信息封装,能确保对象被看成一个真正的软件组件来使用。函数

信号只须要在头文件中进行声明,不须要在cpp中实现。放在Qt自定义关键字signals下,在此以前必定要加上Q_OBJECT宏。spa

在编程中,通常使用的是控件内部定义好的信号。如:QTreeWidget类下的 Signals:指针

void    currentItemChanged ( QTreeWidgetItem * current, QTreeWidgetItem * previous );
void    itemActivated ( QTreeWidgetItem * item, int column );
void    itemChanged ( QTreeWidgetItem * item, int column );
void    itemClicked ( QTreeWidgetItem * item, int column );
void    itemCollapsed ( QTreeWidgetItem * item );
void    itemDoubleClicked ( QTreeWidgetItem * item, int column );
void    itemEntered ( QTreeWidgetItem * item, int column );
void    itemExpanded ( QTreeWidgetItem * item );
void    itemPressed ( QTreeWidgetItem * item, int column );
void    itemSelectionChanged ();

也能够自定义信号,并经过emit在代码中发射信号。code

class sender : public QObject
{
    Q_OBJECT

    public:
        void doSend();
    signals:
        void send(int);
};
// ------------ sender.cpp -----------
#include "sender.h"
void sender :: doSend()
{
    emit send(40);
}

槽函数(Slots)

槽和普通的C++成员函数几乎是同样的(能够是虚函数,能够被重载,能够是public slots、protected slots、private slots,能够被其余C++成员函数直接调用;惟一不一样的是:槽还能够和信号链接在一块儿,在这种状况下,信号被发射时,会自动调用这个槽。)槽不须要信号传过来的参数时,能够不要参数;但槽一旦要参数,其参数个数,类型,顺序必需要和对应的信号保持一致。另外,槽的参数不能有缺省值。xml

class receiver : public QObject
{
    Q_OBJECT
 
    public slots:
        //带有参数的槽函数,需和绑定的信号的参数保持一致
        void recv(int);
};
// ------------ Receiver.cpp -----------
void receiver :: recv(int n)
{
    qDebug()<<"recv number: "<<n<<endl;
}

关联信号和槽(connect)

可使用QObject类的静态成员函数connect来创建信号的槽的关联对象

bool QObject::connect (const QObject * sender, const char * signal, const QObject * receiver, const char * slot) [static]

具体的调用为:connect(sender, SIGNAL(signal), receiver, SLOT(slot)); 其中sender和receiver为QObject类对象的指针; SIGNAL宏和SLOT宏将信号的槽转换成字符串。blog

sender s;
receiver r;
QObject::connect(&s, SIGNAL(send(int)), &r, SLOT(recv(int)));

注:在connect函数中信号函数和槽函数如有参数,只能写出参数类型,而不能也将变量名写出;不然,链接会失败!接口

  • 一个信号能够链接多个槽

当信号发射时,会以不肯定的顺序一个接一个的调用各个槽。

  • 多个信号能够链接同一个槽

即不管是哪个信号被发射,都会调用这个槽。

  • 信号直接能够相互链接

发射第一个信号时,也会发射第二个信号。

断开信号和槽(disconnect)

当信号和槽没有必要继续保持链接时,能够经过调用disconnect来断开它们。

bool QObject::disconnect (const QObject * sender, const char * signal,  const Object * receiver, const char * slot) [static]

有三种状况必须使用 disconnect() 函数:

(1)断开与某个对象相关联的任何对象。

disconnect(sender, 0, 0, 0) ;
//或者
sender->disconnect();

(2)断开与某个特定信号的任何关联。

disconnect(sender, SIGNAL(signal()), 0, 0);
//或者
sender->disconnect(SIGNAL(signal()));

(3)断开两个对象之间的关联。 

disconnect(sender, 0, receiver, 0);
//或者
sender->disconnect(receiver);

应注意的问题

  1. 信号与槽机制与普通函数的调用同样,若是使用不当的话,在程序执行时也有可能产生死循环。所以,在定义槽函数时必定要注意避免间接造成无限循环,即在槽中再次发射所接收到的一样信号。例如 , 在前面给出的例子中若是在 mySlot() 槽函数中加上语句 emit mySignal() 便可造成死循环。
  2. 若是一个信号与多个槽相联系的话,那么,当这个信号被发射时,与之相关的槽被激活的顺序将是随机的。
  3. 宏定义不能用在 signal 和 slot 的参数中。
  4. 信号和槽的参数个数与类型必须一致。
相关文章
相关标签/搜索