参考原文:woboq: Olivier Goffart – Signals and Slots in Qt5
Qt 5 Alpha已经发布。我曾经工作过的一个新特性就是信号和槽的新语法。本篇博客将会为您讲解这一内容。
Qt 5之前的语法
这里是我们如何把信号和槽连接起来的方法:
connect(sender, SIGNAL(valueChanged(QString, QString)), receiver, SLOT(updateValue(QString)));
幕后的实际情况是SIGNAL
和SLOT
这两个宏会把它们的参数转换成字符串。然后QObject::connect()
将会把这些字符串和moc
工具所收集的内省(introspection)数据进行比较。
Qt 5之前信号和槽语法的问题
虽然通常情况下都可以正常工作,我们还是发现了如下问题:
- 没有编译期检查:因为函数名被处理成字符串,所有的检查都是在运行时完成的。这就是为什么有时会发生编译通过了,但槽并没有被调用。此时,你就应该去检查标准输出,看看有没有什么警告说明这个连接没有成功。
- 因为处理的是字符串,所以槽函数中的类型名字必须与信号的完全一致,而且在头文件中的和实际的
connect()
语句中的也必须一致。也就是说,如果你使用了typedef
或者命名空间,那么这个连接就不能正常工作。
新语法:使用函数指针
在即将到来的Qt 5中提供了一套新的语法。之前的语法依然可以使用,但是现在,我们有了全新的方式:
connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue);
哪一种方式更酷可能取决于个人喜好。但大家会更快的适应新方式。
现在让我们先远离美学视角,来看看新语法有什么好处:
编译期检查
如果信号或者槽的名字的拼写发生了错误,或者槽函数的参数与信号的不一致,你会在编译期就得到一个错误。
这肯定会在重构、或者修改信号或槽函数的名字时节省很多时间。
另一个好处是,如果我们少了Q_OBJECT
宏,可以利用static_cast
返回更友好的错误信息。
参数的自动类型转换
现在,我们不仅可以更好地使用typedef
或者命名空间,而且可以利用隐式类型转换。
在下面的例子中,我们的信号有一个QString
参数,而槽函数需要的是QVariant
。它可以正常工作,是因为QVariant
有一个可以使用QString
的隐式构造函数。
class Test : public QObject { Q_OBJECT public: Test() { connect(this, &Test::someSignal, this, &Test::someSlot); } signals: void someSignal(const QString &); public: void someSlot(const QVariant &); };
连接到任意函数
如果你留心上面的例子,就会发现,我们的信号被连接到了一个槽,但是它的声明只有public
,没有slot
。Qt的新语法通过函数指针直接调用函数,而不再需要moc
的内省(但是信号依然需要)。
更进一步,我们可以将信号连接到任意函数或者函数对象(functor):
static void someFunction() { qDebug() << "pressed"; } // ... 然后其它地方 QObject::connect(button, &QPushButton::clicked, someFunction);
这样处理,就可以让你很方便的同boost
或者tr1::bind
进行协作。
C++11 Lambda表达式
至此之前,我们所有的示例都是基于C++98
标准的。但是,如果你的编译器支持C++11
,我还是强烈建议你使用一些这个语言的新特性。现在,Lambda
表达式至少被MSVC 2010
、GCC 4.5
、clang 3.1
这几个编译器支持。不过对于后面两个编译器,你需要在编译时加上-std=c++0x
参数。
然后我们就可以这样写代码了:
void MyWindow::saveDocumentAs() { QFileDialog *dlg = new QFileDialog(); dlg->open(); QObject::connect(dlg, &QDialog::finished, [=](int result) { if (result) { QFile file(dlg->selectedFiles().first()); // ... 在这里保存文档 ... } dlg->deleteLater(); }); }
这种语法允许我们更方便地编写异步代码。
更新:您还可以看看Qt 5中提供的其它C++11特性。
现在该干什么呢?
让我们来尝试一下吧。下载Qt 5 Alpha,开始玩吧。不要忘记报告Bug呀。
(译者注:感谢齐亮对本篇博客全文进行了修正。)
The post Qt 5中信号和槽的新语法 appeared first on Qt Chinese blog.