先看下示例:
QPushButton *btn = new QPushButton;// 方式一:老式写法connect(btn, SIGNAL(clicked()), this, SLOT(close()));// 方式二:Qt5后新写法connect(btn, &QPushButton::clicked, this, &MainWindow::close);// 方式三:lambda表达式connect(btn, &QPushButton::clicked, this, [&]() {this->close();});
方式一:
老式写法,在编译的时候即使信号或槽不存在也不会报错,但是在执行的时候无效,对于C++这种静态语言来说,这是不友好的,不利于调试;
方式二:
Qt5后推荐的写法,如果编译的时候信号或槽不存在是无法编译通过的,相当于编译时检查,不容易出错,还有就是槽的写法可以直接写在public控制域下,不一定非要写在public slots:控制域下;
方式三:
采用了lambda表达式的写法,更加方便快捷。
关于lambda需要注意一点:
QTimer::singleShot(3000, /* this, */ [&]{this->close();});connect(btn, &QPushButton::clicked, /* this, */ [&]() {this->close();});
看下上面的示例,当我们用lambda表达式的时候,槽的接收者QObject是可以省略不写的,这时候Qt会默认发射者与接收者属于同一个QObject;
//connect to a functortemplate <typename Func1, typename Func2>static inline typename std::enable_if<QtPrivate::FunctionPointer<Func2>::ArgumentCount == -1, QMetaObject::Connection>::typeconnect(const typename QtPrivate::FunctionPointer<Func1>::Object *sender, Func1 signal, Func2 slot){return connect(sender, signal, sender, slot, Qt::DirectConnection);}
当我们省略槽函数接收者QObject时,那我们就必须要注意lambda内成员的生命周期;
例如示例的singleShot,若在槽函数响应前,this已经销毁变为无效指针,后果就会很严重!!!
为什么?
我们知道,connect的发射者与接收者任意一个销毁,那么这个connect就已经断开了;
当我们省略接收者QObject的时候,发射者与接收者属于同一个QObject;
在上面的示例中,信号槽connect关联依然存在,信号槽依然会触发,但此时this已经被销毁就不好玩了!
另外:
使用lamda表达式的话就不能用SIGNAL函数,不然会报错
connect(timerChart, &QTimer::timeout, this,[&]{timer_count+=0.2;});
SIGNAL函数和SLOT函数要一起用