Connect Qt signal with simple function and lambda

Many programmers working with Qt4 probably had an obsessive desire to combine the signal sent by a certain QObject descendant with a simple function that is not a slot or even a member of a certain class. However, if the entire project is built on objects (as is usually the case), and all of them are inherited from QObject, then adding a slot function to where it is not difficult. And if not? If you, for example, do not want to inherit your class from QObject for memory reasons (or for other reasons), or does the slot action take only 1 line and would it be easier and more convenient to write it as a lambda expression? Or, for a number of reasons, do you want to trigger a single function that is not a member of a class?

Faced with this problem, I decided to write a class that allows you to connect a signal not only with a function slot, but also with the most ordinary function, and with C ++ 11 support, also with a lambda expression.

Writing a SmartConnect Class


For starters, what should a class do? It should inherit from QObject and store a link to our function. Those. we associate a signal of a class with some SmartConnect slot, and already SmartConnect stores a link to our independent function or lambda expression, and calls it on its own slot.

The most convenient solution is to overload the SmartConnect constructor - to link to various functions. Let it start by working with two types of signals - which pass void in the argument, as well as those that pass QString. Create a smartconnect.h file:
#include 
 
class SmartConnect: public QObject
{
  Q_OBJECT
  void (* pVoidFunc) (void);
  void (* pQStringFunc) (QString);
public:
  SmartConnect (QObject * sender, const char * signal, void (* pFunc) (void));
  SmartConnect (QObject * sender, const char * signal, void (* pFunc) (QString));
private slots:
  void voidSlot ();
  void QStringSlot (QString str);
};

Then - actually smartconnect.cpp:
#include 
#include "smartconnect.h"
 
SmartConnect :: SmartConnect (QObject * sender, const char * signal, void (* pFunc) ()) {
  pVoidFunc = pFunc;
  QObject :: connect (sender, signal, this, SLOT (voidSlot ()));
}
 
SmartConnect :: SmartConnect (QObject * sender, const char * signal, void (* pFunc) (QString)) {
  pQStringFunc = pFunc;
  QObject :: connect (sender, signal, this, SLOT (QStringSlot (QString)));
}
 
void SmartConnect :: voidSlot () {
  pVoidFunc ();
}
 
void SmartConnect :: QStringSlot (QString str) {
  pQStringFunc (str);
}

As you can see, the class is really smart - depending on the constructor called, it selects the desired internal slot and connects to it, and also saves a link to our function. If desired, we can make support for signals with any arguments - just add a link to the function with these arguments, the slot that accepts them and the constructor. But outwardly using the class will be all as simple as that.

Writing a demo


Now create the main.cpp file:
#include 
#include "smartconnect.h"
 
void onClick () {
  qDebug () << "Hello from void onClick ()";
}
 
int main (int argc, char * argv []) {
  QApplication app (argc, argv);
 
  QPushButton button1 ("button1");
  button1.show ();
  SmartConnect smartConnect1 (& button1, SIGNAL (clicked ()), onClick);
 
  QPushButton button2 ("button2");
  SmartConnect smartConnect2 (& button2, SIGNAL (clicked ()), [] () {qDebug () << "Hello from lambda";});
  button2.show ();
 
  return app.exec ();
}

Here we create 2 buttons, one of which connects to the non-slot function, the other to the lambda expression, and when you click on them, the corresponding messages are displayed. Now let's create a pro-file, not forgetting to connect C ++ 11. I must say right away that this will require a new version of Qt, assembled under the same compiler that supports C ++ 11. Otherwise, the lambda example will not work. Create the main.pro file:
QT + = gui
TEMPLATE = app
CONFIG + = release
SOURCES + = main.cpp
           smartconnect.cpp
HEADERS + = smartconnect.h
CONFIG + = console
QMAKE_CXXFLAGS + = -std = gnu ++ 11

Finally, compile and compile our example:
qmake main.pro -o Makefile 
make

If desired, the class can be improved, for example, add disconnect to it, if necessary. As you can see, using a class is simple and convenient, in some cases it can be very useful and really simplify the code.

Also popular now: