Code interlude – signals and slots

Exclusive offer: get 50% off this eBook here
Application Development with Qt Creator

Application Development with Qt Creator — Save 50%

A fast-paced guide for building cross-platform applications using Qt and Qt Quick book and ebook.

$20.99    $10.50
by Ray Rischpater | November 2013 | Open Source

This article is by Ray Rischpater, author of the book Application Development with Qt Creator. In software systems, there is often the need to couple different objects. Ideally, this coupling should be loose, that is, not dependent on the system's compile-time configuration. This is especially obvious when you consider user interfaces; for example, a button press may adjust the contents of a text widget or cause something to appear or disappear. Many systems use events for this purpose; components offering data encapsulate that data in an event, and an event loop (or, more recently, an event listener) catches the event and performs some action.

(For more resources related to this topic, see here.)

Qt offers a better way: signals and slots. Like an event, the sending component generates a signal—in Qt parlance, the object emits a signal—which recipient objects may receive in a slot for the purpose. Qt objects may emit more than one signal, and signals may carry arguments; in addition, multiple Qt objects can have slots connected to the same signal, making it easy to arrange one-to-many notifications. Equally important, if no object is interested in a signal, it can be safely ignored, and no slots connected to the signal. Any object that inherits from QObject, Qt's base class for objects, can emit signals or provide slots for connection to signals. Under the hood, Qt provides extensions to C++ syntax for declaring signals and slots.

A simple example will help make this clear. The classic example you find in the Qt documentation is an excellent one, and we'll use it again it here, with some extension's. Imagine you have the need for a counter, that is, a container that holds an integer. In C++, you might write:

class Counter { public: Counter() { m_value = 0; } int value() const { return m_value; } void setValue(int value); private: int m_value; };

The Counter class has a single private member, m_value, bearing its value. Clients can invoke the value to obtain the counter's value, or set its value by invoking setValue with a new value.

In Qt, using signals and slots, we write the class this way:

#include <QObject> class Counter : public QObject { Q_OBJECT public: Counter() { m_value = 0; } int value() const { return m_value; } public slots: void setValue(int value); void increment(); void decrement(); signals: void valueChanged(int newValue); private: int m_value; };

This Counter class inherits from QObject, the base class for all Qt objects. All QObject subclasses must include the declaration Q_OBJECT as the first element of their definition; this macro expands to Qt code implementing the subclass-specific glue necessary for the Qt object and signal-slot mechanism. The constructor remains the same, initializing our private member to zero. Similarly, the accessor method value remains the same, returning the current value for the counter.

An object's slots must be public, and are declared using the Qt extension to C++ public slots. This code defines three slots: a setValue slot, which accepts a new value for the counter, and the increment and decrement slots, which increment and decrement the value of the counter. Slots may take arguments, but do not return them; the communication between a signal and its slots is one way, initiating with the signal and terminating with the slot(s) connected to the signal.

The counter offers a single signal. Like slots, signals are also declared using a Qt extension to C++, signals. In the example above, a Counter object emits the signal valueChanged with a single argument, which is the new value of the counter. A signal is a function signature, not a method; Qt's extensions to C++ use the type signature of signals and slots to ensure type safety between signal-slot connections, a key advantage signals and slots have over other decoupled messaging schemes.

As the developers, it's our responsibility to implement each slot in our class with whatever application logic makes sense. The Counter class's slots look like this:

void Counter::setValue(int newValue) { if (newValue != m_value) { m_value = newValue; emit valueChanged(newValue); } } void Counter::increment() { setValue(value() + 1); } void Counter::decrement() { setValue(value() – 1); }

We use the implementation of the setValue slot as a method, which is what all slots are at their heart. The setValue slot takes a new value and assigns the new value to the Counter class's private member variable if they aren't the same. Then, the signal emits the valueChanged signal, using the Qt extension emit, which triggers an invocation to the slots connected to the signal.

This is a common pattern for signals that handle object properties: testing the property to be set for equality with the new value, and only assigning and emitting a signal if the values are unequal.

If we had a button, say QPushButton, we could connect its clicked signal to the increment or decrement slot, so that a click on the button incremented or decremented the counter. I'd do that using the QObject::connect method, like this:

QPushButton* button = new QPushButton(tr("Increment"), this); Counter* counter = new Counter(this); QObject::connect(button, SIGNAL(clicked(void)), Counter, SLOT(increment(void));

We first create the QPushButton and Counter objects. The QPushButton constructor takes a string, the label for the button, which we denote to be the string Increment or its localized counterpart.

Why do we pass this to each constructor? Qt provides a parent-child memory management between QObjects and their descendants, easing clean-up when you're done using an object. When you free an object, Qt also frees any children of the parent object, so you don't have to. The parent-child relationship is set at construction time; I'm signaling to the constructors that when the object invoking |this code is freed, the push button and counter may be freed as well. (Of course, the invoking method must also be a subclass of QObject for this to work.)

Next, I call QObject::connect, passing first the source object and the signal to be connected, and then the receiver object and the slot to which the signal should be sent. The types of the signal and the slot must match, and the signals and slots must be wrapped in the SIGNAL and SLOT macros, respectively.

Signals can also be connected to signals, and when that happens, the signals are chained and trigger any slots connected to the downstream signals. For example, I could write:

Counter a, b; QObject::connect(&a, SIGNAL(valueChanged(int)), &b, SLOT(setValue(int)));

This connects the counter b with the counter a, so that any change in value to the counter a also changes the value of the counter b.

Signals and slots are used throughout Qt, both for user interface elements and to handle asynchronous operations, such as the presence of data on network sockets and HTTP transaction results. Under the hood, signals and slots are very efficient, boiling down to function dispatch operations, so you shouldn't hesitate to use the abstraction in your own designs. Qt provides a special build tool, the meta-object compiler, which compiles the extensions to C++ that signals and slots require and generates the additional code necessary to implement the mechanism.

Summary

In this article we learned the usage events for the purpose of coupling different objects; components offering data encapsulate that data in an event, and an event loop (or, more recently, an event listener) catches the event and performs some action.

Resources for Article:


Further resources on this subject:


Application Development with Qt Creator A fast-paced guide for building cross-platform applications using Qt and Qt Quick book and ebook.
Published: November 2013
eBook Price: $20.99
Book Price: $34.99
See more
Select your format and quantity:

About the Author :


Ray Rischpater

Ray Rischpater is an engineer and author with over 20 years' experience writing about and developing for computing platforms.

During this time, he has participated in the development of Internet technologies and custom applications for Java ME, Qualcomm BREW, Apple iPhone, Google Android, Palm OS, Newton, and Magic Cap, as well as several proprietary platforms. Presently, he's employed as a senior engineer at Microsoft in Mountain View, working on mapping and data visualization.

When not writing for or about mobile platforms, he enjoys hiking and photography with his family and friends in and around the San Lorenzo Valley in central California. When he's able, he also provides a public service through amateur radio as the licensed Amateur Extra station KF6GPE.

The books he's written so far include:

  • Microsoft Mapping: Geospatial Development with Bing Maps and C# (with Carmen Au, Apress, 2013)
  • Beginning Nokia Apps Development (with Daniel Zucker, Apress, 2010)
  • Beginning Java ME Platform (Apress, 2008)
  • Wireless Web Development, Second Edition (Apress, 2004)
  • eBay Application Development (Apress, 2004)
  • Software Development for the QUALCOMM BREW Platform (Apress, 2003)
  • Wireless Web Development, First Edition (Apress, 2002)
  • Internet Appliances: A Wiley Tech Brief (John Wiley & Sons, 2001)
  • Advanced Palm Programming (with Steve Mann, John Wiley & Sons, 2000)
  • Palm Enterprise Applications: A Wiley Tech Brief (John Wiley & Sons, 2000)

He holds a bachelor's degree in pure mathematics from the University of California, Santa Cruz and is a member of the IEEE, ACM, and ARRL.

Books From Packt


Yii Application Development Cookbook - Second Edition
Yii Application Development Cookbook - Second Edition

Windows Phone 8 Application Development Essentials
Windows Phone 8 Application Development Essentials

Learning Facebook Application Development
Learning Facebook Application Development

Advanced Express Web Application Development
Advanced Express Web Application Development

Android Studio Application Development
Android Studio Application Development

PhoneGap 2.x Mobile Application Development Hotshot
PhoneGap 2.x Mobile Application Development Hotshot

Boost C++ Application Development Cookbook
Boost C++ Application Development Cookbook

Express Web Application Development
Express Web Application Developmentk


No votes yet

Post new comment

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.
W
k
A
B
N
L
Enter the code without spaces and pay attention to upper/lower case.
Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software