QT信号槽

信号槽是Qt 框架引以为豪的机制之一。熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的技术设计能力。
所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,用自己的一个函数(成为槽(slot))来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。我们来看一下信号槽的使用:

#include <QApplication>
#include <QPushButton>
 
int main ( int argc , char * argv [ ] )
{
     QApplication app ( argc , argv ) ;
 
     QPushButton button ( "quit" ) ;
     QObject :: connect ( & button , SIGNAL ( clicked ( ) ) , & app , SLOT ( quit ( ) ) ) ;
     button . show ( ) ;
     return app . exec ( ) ;
}
我们使用了SIGNAL和SLOT这两个宏,将两个函数名转换成了字符串。注意,即使quit()是QApplication的 static 函数,也必须传入一个对象指针。这也是信号槽语法的局限之处。另外,注意到connect()函数的 signal 和 slot 都是接受字符串,因此,不能将全局函数或者 Lambda 表达式(以后再说)传入connect()。一旦出现连接不成功的情况,Qt 4 是没有编译错误的(因为一切都是字符串,编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不稳定性。

接下来看看三个不同的connect()重载:
bool connect ( const QObject * , const char * , const QObject * , const char * , Qt :: ConnectionType ) ;
 
bool connect ( const QObject * , const QMetaMethod & , const QObject * , const QMetaMethod & , Qt :: ConnectionType ) ;
 
bool connect ( const QObject * , const char * , const char * , Qt :: ConnectionType ) const

它们的返回值都是一样的,而且 signal 和 slot 只有const char * 这么一种形式。
信号槽不是 GUI 模块提供的,而是 Qt 核心特性之一。因此,我们可以在普通的控制台程序使用信号槽。
那么自定义信号槽就必不可少了, 自定义信号槽需要注意的事项:
1. 发送者和接收者都需要是QObject 的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
2.使用 signals 标记信号函数,信号是一个函数声明,返回 void,不需要实现函数代码;
3.槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
4.使用 emit 在恰当的位置发送信号;
5.使用QObject::connect() 函数连接信号和槽。
下面给出相应例子的代码:

#include <QObject>
 
// newspaper.h
class Newspaper : public QObject
{
     Q_OBJECT
public :
     Newspaper ( const QString & name ) :
         m_name ( name )
     {
     }
 
     void send ( ) const
     {
         emit newPaper ( m_name ) ;
     }
 
signals :
     void newPaper ( const QString & name ) const ;
 
private :
     QString m_name ;
} ;
// reader.h
#include <QObject>
#include <QDebug>
 
class Reader : public QObject
{
     Q_OBJECT
public :
     Reader ( ) { }
 
public slots :
     void receiveNewspaper ( const QString & name ) const
     {
         qDebug ( ) << "Receives Newspaper: " << name ;
     }
} ;
// main.cpp
#include <QCoreApplication>
 
#include "newspaper.h"
#include "reader.h"
 
int main ( int argc , char * argv [ ] )
{
     QCoreApplication app ( argc , argv ) ;
 
     Newspaper newspaper ( "Newspaper A" ) ;
     Reader reader ;
     QObject :: connect ( & newspaper , SIGNAL ( newPaper ( QString ) ) ,
                     & reader ,      SLOT ( receiveNewspaper ( QString ) ) ) ;
     newspaper . send ( ) ;
 
     return app . exec ( ) ;
}

main()函数中,QObject::connect()函数,第二、第四个参数需要使用SIGNAL和SLOT这两个宏转换成字符串(具体事宜我们在上一节介绍过)。注意SIGNAL和SLOT的宏参数并不是取函数指针,而是除去返回值的函数声明,并且 const 这种参数修饰符是忽略不计的。
我们提到了“槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响”,public、private 这些修饰符是供编译器在编译期检查的,因此其影响在于编译期。 其连接是在运行时完成的,因此即便是 private 的槽函数也是可以作为槽进行连接的。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值