Example Slot Signal C++

Example Slot Signal C++ 4,5/5 2048 reviews

Signals, slots, QOBJECT, emit, SIGNAL, SLOT. Those are known as the Qt extension to C. They are in fact simple macros, defined in qobjectdefs.h. #define signals public #define slots /. nothing./ That is right, signals and slots are simple functions: the compiler will handle them them like any other functions. The signal/slot system fits well with the way graphical user interfaces are designed. citation needed Similarly, the signal/slot system can be used for other non-GUI usages, for example asynchronous I/O (including sockets, pipes, serial devices, etc.) event notification or to associate timeout events with appropriate object instances.

  1. In signal-slot parlance this is called connecting a slot to a signal, where a 'slot' represents a callable instance and a 'connection' can be thought of as a conceptual link from signal to slot. All the snippets presented below are available in compilable source code form in the example subdirectory.
  2. There is a default behavior for some (i.e. A process is terminated when it receives an inturrupt SIGINT signal by pressing keystrokes ctrl-C) but this tutorial shows how to handle the signal by defining callback functions to manage the signal. Where possible, this allows one to close files and perform operations and react in a manner defined.

I’ve been asked multiple times how I would implement a signal / slot mechanism in modern C++. Here is the answer!

What’s the Signal / Slot Pattern?

[...] a language construct [...] which makes it easy to implement the Observer pattern while avoiding boilerplate code. The concept is that GUI widgets can send signals containing event information which can be received by other controls using special functions known as slots. - Wikipedia

So basically it allows for event based inter-object communication. In my opinion it’s intuitive to use and produces easily readable code when used in a moderate amount. And the big plus: It can be added to your program with one simple template class!

There are many libraries around (refer to the linked Wikipedia article) implementing this pattern, but it’s so easy to implement on you own that I would recommend to do this without an additional dependency. All you need is the header I posted below. And it’s a good exercise.

The signal template class

Example Slot Signal C++ Jammers

Below you can find the entire class. Because this class is using variadic templates you can define signals which pass any kind of data to their slots. Basically you can create signals which allow for arbitrary slot signatures. The emit method will accept the same argument types you declared as template parameters for the Signal class. The class is documented with comments and should be quite understandable. Further below you will find two usage examples.

Simple usage

The example below creates a simple signal. To this signal functions may be connected which accept a string and an integer. A lambda is connected and gets called when the emit method of the signal is called.

When you saved the Signal class as Signal.hpp and the above example as main.cpp you can compile the example with:

And if you execute the resulting application you will get the following output:

Advanced usage

This example shows the usage with classes. A message gets displayed when the button is clicked. Note that neither the button knows anything of a message nor does the message know anything about a button. That’s awesome! You can compile this example in the same way as the first.

You may also connect member functions which take arguments (Thank you FlashingChris for pointing out how to do this without std::placeholders!). In the following example Alice and Bob may say something and the other will hear it:

Issues & next steps

There are two drawbacks in this simple implementation: It’s not threadsafe and you cannot disconnect a slot from a signal from within the slot callback. Both problems are easy to solve but would make this example more complex.

Using this Signal class other patterns can be implemented easily. In a follow-up post I’ll present another simple class: the Property. This will allow for a clean implementation of the observer pattern.

Have some fun coding events in C++!

Signal

Edit on 2020-10-19:

  • Add move-copy-constructor and move-assignment-operator
  • Add emit_for_all_but_one and emit_for methods.
  • Remove previously added std::forward.
Please enable JavaScript to view the comments powered by Disqus.blog comments powered by Disqus

Earlier this week, I posted an example of integrating QML2 and C++. In it I showed how to call a C++ method from QML, but finished my post with this statement.

I’m still new to Qt, so this may not be the best way. It looks like you can also use signals, which would probably be better as it means your QML application isn’t tied to your C++ implementation, but I haven’t yet got that working.

I have now found a way to use signals and slots to do this, which I will describe here.

C++

Signals and Slots

Signals and Slots are a feature of Qt used for communication between objects. When something happens to an object, it can emit a signal. Zero or more objects can listen for this signal using a slot, and act on it. The signal doesn’t know if anything is listening to it, and the slot doesn’t know what object called it.

This allows you to design and build a loosely coupled application, giving you the flexibility to change, add or remove features of one component without updating all its dependencies, so long as you continue to emit the same signals and listen on the same slots.

You can see why this might be useful in GUI programming. When a user enters some input, you may want to do a number of things with it. Maybe you want to update the GUI with a progress bar, then kick off a function to handle this input. This function might emit a signal letting others know its progress, which the progress bar could listen to and update the GUI. And so on.

Even outside of GUI programming this could be useful. You might have an object watching the filesystem for changes. When a change happens, you could emit a signal to let other objects know about this change. One object might run a process against this file, while another object updates a cache of the filesystem.

The example application

I’m going to create the same example application as I did before. It will contain a text field and a button. You enter some text in the text field, and once you click the button the text will be converted to upper-case. The conversion to upper-case will be done in C++, and the interface drawn in QML2.

The source of the finished application is available on GitHub.

Emitting a signal from QML and listening to it from C++

To create a signal in QML, simply add the following line to the object which will emit the signal.

Here I have created a signal, submitTextField, which will pass a string as an argument to any connecting slots (if they choose to receive it).

I’m going to add this signal to the Window. I will emit the signal when the button is pressed, passing the value of the text field. Here is the full QML document.

We can run that and click the button. The signal is being emitted, but because no slots are listening to it nothing happens.

Let’s create a C++ class to listen to this signal. I’m going to call it HandleTextField, and it will have a slot called handleSubmitTextField. The header file looks like this.

The class file has a simple implementation for handleSubmitTextField.

To connect the QML signal to the C++ slot, we use QObject::connect. Add the following to main.cpp.

We need an instance of HandleTextField, and the QML Window object. Then we can connect the windows submitTextField signal to the handleSubmitTextField slot. Running the application now and you should get a debug message showing the text being passed to C++.

Emitting a signal from C++ and listening to it from QML

Now we want to convert the string to upper-case and display it in the text field. Lets create a signal in our C++ class by adding the following to the header file.

Then change the handleSubmitTextField function to emit this signal with the upper-cased text.

Notice we are passing the text as a QVariant. This is important, for the reasons well described in this Stack Overflow answer.

The reason for the QVariant is the Script based approach of QML. The QVariant basically contains your data and a desription of the data type, so that the QML knows how to handle it properly. That’s why you have to specify the parameter in QML with String, int etc.. But the original data exchange with C++ remains a QVariant

We now need a slot in QML to connect this signal to. It will handle the updating of the text field, and is simply a function on the Window.

Qt Signal Slot Example C

Finally we use QObject::connect to make the connection.

Run the application, and you should now see your text be converted to upper-case.

Next steps

It feels like more work to use signals and slots, instead of method calls. But you should be able to see the benefits of a loosely coupled application, especially for larger applications.

I’m not sure a handler class for the text field is the best approach for this in practice. In a real application I think you would emit user actions in your GUI and have classes to implement your application logic without knowledge of where that data is coming from. As I gain more experience with Qt, I will update the example with the best practice.

Example Slot Signal C++

Check out the full application on GitHub.

Cover image by Beverley Goodwin.