鱼C论坛

 找回密码
 立即注册
查看: 1629|回复: 0

[技术交流] Qt-003信号和槽

[复制链接]
发表于 2018-10-14 10:54:04 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 moc 于 2018-10-14 10:53 编辑

1、信号和槽机制
信号槽是 Qt 框架引以为豪的机制之一。信号槽,实际就是一种观察者模式:当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播,如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。
也即:当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。(这里提一句,Qt 的信号槽使用了额外的处理来实现,并不是 GoF 经典的观察者模式的实现方式。)
QPushButton button("Quit");
QObject::connect(&button,  &QPushButton::clicked,&app,  &QApplication::quit);
上面就是一个简单的信号槽,当按扭button被单击后,他会发出clicked信号,引用程序接收到这个信号,会执行quit这个回调函数。
2、connect()函数
信号与槽的连接函数connect()的一般形式:
        connect(sender, signal, receiver, slot);
参数:
        sender:发出信号的对象;
        signal:发送对象发出的信号;
        receiver:接收信号的对象;
        slot:接收对象在接收到信号之后所需要调用的函数。
注意:
        信号槽要求信号和槽的参数一致,所谓一致,是参数类型一致。如果不一致,允许的情况是,槽函数的参数可以比信号的少,即便如此,槽函数存在的那些参数的顺序也必须和信号的前面几个一致起来。
Qt4版本的信号槽连接方式:
        connect(button, SIGNAL(clicked()), &a, SLOT(quit()));
这里使用了SIGNAL和SLOT这两个,将两个函数名转换成了字符串。注意到connect()函数的 signal 和 slot 都是接受字符串,一旦出现连接不成功的情况,Qt4是没有编译错误的(因为一切都是字符串,编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不稳定性。
Qt5版本的信号槽连接方式:
        connet()函数中的信号函数和槽函数不再使用SIGNAL和SLOT宏,信号函数和槽函数使用 父类::函数名  即可。
注意: 在遇到重载信号或槽函数的时候需要借助函数指针,来避免函数的二义性。
void (SubWidget::*myfun1)() = &SubWidget::mySignal;
connect(&subw, myfun1, this, MainWidget::dealSubWin);

void (SubWidget::*myfun2)(int, QString) = &SubWidget::mySignal;
connect(&subw, myfun2, this, MainWidget::dealSlot2);
3、自定义信号和槽
使用connect()可以让我们连接系统提供的信号和槽。但是,Qt 的信号槽机制并不仅仅是使用系统提供的那部分,还会允许我们自己设计自己的信号和槽。
1. 自定义信号
        ① 信号必须要有signals声明。
        ② 信号没有返回值,但可以有参数。
        ③ 信号就是函数的声明,只需声明,无需定义。
        ④ 信号可以重载。
2. 自定义槽
        Qt 5 中,任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数。槽函数就是普通的成员函数,因此作为成员函数,也会受到 public、private 等访问控制符的影响。(如果信号是 private 的,这个信号就不能在类的外面连接,也就没有任何意义。)
3. 注意事项
emit  ==> Qt 对 C++ 的扩展,是一个关键字(其实也是一个宏)。emit 的含义是发出信号。感兴趣的接收者会关注这个信号,当接收者连接这个信号时,就可以通过槽函数获得实际值。这样就完成了数据从发出者到接收者的一个转移。
Q_OBJECT    ==>  这个宏的展开将为我们的类提供信号槽机制、国际化机制以及 Qt 提供的不基于 C++ RTTI 的反射能力。
        ① 使用信号槽时,发送者和接收者都需要是QObject的子类(当然,槽函数是全局函数、Lambda 表达式等无需接收者的时候除外);
        ② 使用 signals 标记信号函数,信号是一个函数声明,返回 void,不需要实现函数代码;
        ③ 槽函数是普通的成员函数,作为成员函数,会受到 public、private、protected 的影响;
        ④ 使用 emit 在恰当的位置发送信号;
        ⑤ 使用QObject::connect()函数连接信号和槽;
        ⑥ 任何成员函数、static 函数、全局函数和 Lambda 表达式都可以作为槽函数。

4、信号槽扩展用法
1. 一个信号可以和多个槽相连
        如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的
2. 多个信号可以连接到一个槽
        只要任意一个信号发出,这个槽就会被调用。
3. 一个信号可以连接到另外的一个信号
        当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式没有什么区别。
4. 槽可以被取消链接
        这种情况并不经常出现,因为当一个对象delete之后,Qt自动取消所有连接到这个对象上面的槽
5. 信号直接连接Lambda表达式
        在使用 Qt 5 的时候,能够支持 Qt 5 的编译器都是支持 Lambda 表达式的。使用时需要在工程文件中加上:   CONFIG += C++11
connect(b4, &QPushButton::clicked, this,
            [b4](bool isCheck){
                   b4->setText("123");
                   qDebug() << "12345";
                   qDebug() << isCheck;
                });
在连接信号和槽的时候,使用Lambda表达式的方式可以更快捷进行处理。

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

GMT+8, 2024-11-23 19:10

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表