Qt5信号与槽C++11风格链接简介

最近在论坛上看到了这个方面的问题,详见这里。 
随后浅浅地学习了一会儿,看到了Qt官方论坛上给出的说明,以为C++11的functional链接方法仍是比Qt4既有的宏链接方法有很大不一样。 
官方论坛的文档:http://doc.qt.io/qt-5/signalsandslots-syntaxes.htmlcss

1.实验代码

咱们在一个简单的Dialog中,安排以下几个信号与槽:html

class SSTest : public QDialog { //... signals: void sgn_test1(QByteArray arr); void sgn_test2(int n); void sgn_test2(QString s); void sgn_test3(double c, double d); public slots: void slt_1(); void slt_2(double v); void slt_2(QString s); void slt_3(int s); //... }; //cpp //...... void SSTest::slt_1() { qDebug()<<"SSTest::slt_1()"; } void SSTest::slt_2(double v) { qDebug()<<"SSTest::slt_2(double v):"<<v; } void SSTest::slt_2(QString s) { qDebug()<<"SSTest::slt_2(QString s):"<<s; } void SSTest::slt_3(int s) { qDebug()<<"SSTest::slt_3(int s):"<<s; } 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36

然后,在构造函数中,直接采用文档所述方法,进行链接.markdown

2.各种状况测试

2.1. 信号、槽均无重载

此类状况,对应 sgn_test一、slt_1 
直接链接便可:函数

connect (this,&SSTest::sgn_test1,this,&SSTest::slt_1); connect (this,&SSTest::sgn_test3,this,&SSTest::slt_3);
  • 1
  • 2

编译OK,说明,槽的参数能够比信号少。而且,存在着隐含参数转换: 
第一行,QByteArray arr 参数被忽略了,由于槽没有参数。 
第二行,double c, double d 两个参数,第二个被忽略了,由于槽只有一个int参数。第一个参数被隐含转换。 
测试:学习

emit sgn_test1(QByteArray()); emit sgn_test3(1.7,2.2);
  • 1
  • 2

输出:测试

SSTest::slt_1() SSTest::slt_3(int s): 1
  • 1
  • 2

可是,若是咱们把不支持隐含转换的信号与槽链接,则会错误:this

connect (this,&SSTest::sgn_test1,this,&SSTest::slt_3);
  • 1

QByteArray 没法转换为 int, 所以没法经过编译(具体错误与编译器相关):url

C:\...\qobjectdefs_impl.h:299: error: 'QByteArray::operator QNoImplicitBoolCast() const' is private within this context enum { value = sizeof(test(dummy())) == sizeof(int) }; ~~~~~^~~~~~~~~~
  • 1
  • 2
  • 3

2.2. 信号惟一,槽重载

咱们试着简单链接sgn_test3和slt_2spa

connect (this,&SSTest::sgn_test3,this,&SSTest::slt_2);
  • 1

与估计的同样,没法编译:.net

C:\...\sstest.cpp:15: error: no matching function for call to 'SSTest::connect(SSTest*, void (SSTest::*)(double, double), SSTest*, <unresolved overloaded function type>)' connect (this,&SSTest::sgn_test3,this,&SSTest::slt_2); ^
  • 1
  • 2
  • 3

此时,咱们采用下面这两种方式之一,便可:

connect (this,&SSTest::sgn_test3,this,static_cast<void(SSTest::*)(double)>(&SSTest::slt_2));
  • 1

或者(C++14以上)

connect (this,&SSTest::sgn_test3,this,qOverload<double>(&SSTest::slt_2));
  • 1

这等于强制指定了链接方法。测试:

emit sgn_test3(1.7,2.2);
  • 1

输出:

SSTest::slt_2(double v): 1.7
  • 1

2.3. 信号重载、槽重载

有了上面的经验,面对重载已经不怕了:

//C++14风格同时指定信号、槽的参数表 connect (this,qOverload<QString>(&SSTest::sgn_test2),this,qOverload<QString>(&SSTest::slt_2)); //static_cast风格同时指定信号、槽的参数表 connect (this,static_cast<void(SSTest::*)(int)>(&SSTest::sgn_test2),this,static_cast<void(SSTest::*)(double)>(&SSTest::slt_2)); //信号重载,链接到单一的槽 connect (this,static_cast<void(SSTest::*)(int)>(&SSTest::sgn_test2),this,&SSTest::slt_1); 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

测试:

emit sgn_test2("haha!"); emit sgn_test2(1);
  • 1
  • 2

输出:

SSTest::slt_2(QString s): "haha!" SSTest::slt_2(double v): 1 SSTest::slt_1()
  • 1
  • 2
  • 3

2.4. 更灵活的lambda表达式

固然,既然Qt5采用的是functional机制,必定能够用lambda:

int p = 100;
connect (this,&SSTest::sgn_test3,[=](double a ,double b)->void{  qDebug()<<(p*a+b); });
  • 1
  • 2
  • 3
  • 4

测试:

emit sgn_test3(1.7,2.2);
  • 1

输出:

172.2
  • 1

3. 总结

传统的Qt4 Signal-Slot宏链接兼容性好,可是没有编译时检查,每每会因为笔误,产生预料以外的效果。如今,有了C++11 functional的支持,能够借助编译器进行严格的类型检查,明显是有利于调试了。

 

http://blog.csdn.net/goldenhawking/article/details/78766676

相关文章
相关标签/搜索