鱼C论坛

 找回密码
 立即注册

小白的Qt自学(6) 信号槽的介绍

已有 698 次阅读2014-3-31 14:39 |个人分类: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();
}
我们使用了SIGNALSLOT这两个宏,将两个函数名转换成了字符串。注意,即使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()函数,第二、第四个参数需要使用SIGNALSLOT这两个宏转换成字符串(具体事宜我们在上一节介绍过)。注意SIGNALSLOT的宏参数并不是取函数指针,而是除去返回值的函数声明,并且 const 这种参数修饰符是忽略不计的。
我们提到了“槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响”,public、private 这些修饰符是供编译器在编译期检查的,因此其影响在于编译期。其连接是在运行时完成的,因此即便是 private 的槽函数也是可以作为槽进行连接的。

路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)

facelist

您需要登录后才可以评论 登录 | 立即注册

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-5-13 00:36

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

返回顶部