QT信号槽

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

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

接下来看看三个不同的connect()重载:
bool connect(constQObject *, const char *,constQObject *, const char *,Qt::ConnectionType);
 
bool connect(constQObject *, const QMetaMethod &,constQObject *, const QMetaMethod &,Qt::ConnectionType);
 
bool connect(constQObject *, const char *,constchar *,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(constQString & name):
        m_name(name)
    {
    }
 
    voidsend() const
    {
        emit newPaper(m_name);
    }
 
signals:
    voidnewPaper(const QString&name) const;
 
private:
    QString m_name;
};
////////// reader.h
#include <QObject>
#include <QDebug>
 
class Reader: public QObject
{
    Q_OBJECT
public:
    Reader(){}
 
public slots:
    voidreceiveNewspaper(const QString & name)const
    {
        qDebug()<< "Receives Newspaper: " << name;
    }
};
////////// main.cpp
#include <QCoreApplication>
 
#include "newspaper.h"
#include "reader.h"
 
int main(intargc, char *argv[])
{
    QCoreApplicationapp(argc, argv);
 
    Newspaper newspaper("Newspaper A");
    Reader reader;
    QObject::connect(&newspaper,SIGNAL(newPaper(QString)),
                     &reader,    SLOT(receiveNewspaper(QString)));
    newspaper.send();
 
    returnapp.exec();
}

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