⬆️ ⬇️

Signals and Slots in Qt5

Qt5 alpha saw the light. In this article I will describe one of the features that I worked on - this is a new syntax of signals and slots.



Previous syntax



Here is how we usually connect the signal and the slot:



connect(sender, SIGNAL(valueChanged(QString,QString)), receiver, SLOT(updateValue(QString)) ); 


In fact, the SIGNAL and SLOT macros convert their arguments to strings. Then QObject::connect() compares these strings with the introspection data collected by the moc utility.

')

What is the problem with this syntax?


Despite the fact that, in general, everything works well, there are some inconveniences:





New syntax: use of function pointers



Qt5 in preparation supports alternative syntax. In addition to the above approach, you can use this new way of connecting signals and slots:



 connect(sender, &Sender::valueChanged, receiver, &Receiver::updateValue ); 


Which one is more beautiful is a matter of taste. But getting used to the new version is very simple.



Now consider the advantages that it gives:



Check at compile time


You will get a compilation error if you make a mistake in the name of the signal or slot, or if the slot arguments do not match the signal arguments. This will save you time after refactoring.



In addition, static_assert used to show understandable errors in cases where the arguments do not match or Q_OBJECT omitted.



Automatic coercion of argument types


Now you can not only fear using typedef or namespaces, but also connect signals with slots that accept arguments of other types if implicit coercion is possible.



In the following example, we connect a signal that takes a QString as a parameter to a slot that accepts a QVariant . This works without problems, since QVariant has an implicit constructor that accepts a 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 &); }; 


Connect the signal with any function


As you noted in the last example, someSlot was declared simply as a public method, without a slot . Qt can call a slot directly and no longer needs introspection for this. (Although it is still needed for signals)



But now we can also connect a sinal with any function or functor:



 static void someFunction() { qDebug() << "pressed"; } // ... somewhere else QObject::connect(button, &QPushButton::clicked, someFunction); 


This can be a very powerful feature in combination with boost or tr1 :: bind.



Anonymous functions from C ++ 11


Everything described above works with the old C ++ 98. But if you are using a compiler that supports C ++ 11, then I strongly recommend using new language features. Lambda expressions are supported at least MSVC 2010, GCC 4.5, clang 3.1. For the last two, you must specify -std=c++0x as a flag.



Now you can write this code:



 void MyWindow::saveDocumentAs() { QFileDialog *dlg = new QFileDialog(); dlg->open(); QObject::connect(dlg, &QDialog::finished, [=](int result) { if (result) { QFile file(dlg->selectedFiles().first()); // ... save document here ... } dlg->deleteLater(); }); } 


This makes writing asynchronous code very simple.

Source: https://habr.com/ru/post/141983/



All Articles