C++ GUI Libraries, QT and the Signals/Slots Paradigm

It’s a while since I last posted anything as I’ve been tied up with uni work (and I should really be doing a 3000-4000 word report now, but I’m hoping it’ll write itself). I was planning to blog about something a little more general, perhaps related to user interfaces, but for now you’ll have to deal with an esoteric and mercilessly long post. Skip the rambling about our project and migration to QT if you want – the second half about Signals/Slots is the (more) interesting part 😀

I’m working with a fellow classmate at uni on a year long project centered around algorithm visualisation which I may blog about in the future. Up until recently, we’d been using OpenGL for graphics and SFML for basic windowing and events. We required some scrollbar, menu and button functionality, so short of writing widgets ourselves, we opted to go for a GUI library. Now before that, I’d never developed a GUI in C++, and for good reason. Having been spoiled by the well documented and designed Swing, the rapid prototyping of TCL/TK, and the superlative .NET WinForms/WPF, most C++ GUI code strikes me as being a little close to the metal when I want to whip up a quick interface (*cough* Win32 *cough* MFC). On the other hand, based on my experiences with TCL/TK, prototyping is quite rapid until you want to do something the library designer never thought of, and you spend hours tearing your hair out trying to figure out how. C++ GUI libs are arguably less likely to suffer from this problem. Incidentally, I am learning a bit of WTL for developing a Foobar plugin as a personal project.

Migration from OpenGL/SFML to QT

A bit of preliminary research into GUI libraries led us to this, a seemingly promising way to quickly integrate our SFML code into QT widgets. However, that solution was short-lived as we soon discovered that the WA_PaintOnScreen attribute used to inform QT that we want to take care of the widget drawing, is not a cross-platform feature. After some deliberation, we decided that we didn’t really need OpenGL/SFML for now and that our project should undergo a full migration to QT… painting would be performed by the QPainter class but there is also a QGLWidget class available, should we require it. The migration was time-consuming but smooth for the most part. The main obstacle was finding an easy way to allow a QWidget to draw on top of its child widgets, a requirement for our graphical model. In Swing, one can simply override paint() with a version which calls paintChildren() before paintComponent() (and throw paintBorder() in the mix somewhere). We employed the quick hacky solution of delegating the parent drawing to a child widget with a different z-order to its sibling widgets. If anyone knows of a better solution, please let me know 🙂

QT and Signals/Slots

On the whole, QT is an excellent framework. It is well-designed and documented, portable, performant, versatile and it offers a wide range of features. Not to mention, it introduced the innovative signals and slots paradigm as an implementation of the Observer pattern. Whereas many languages use callbacks and .NET uses events/delegates (not so different), QT uses the signals/slots mechanism – and you know it must be good if it inspired the Boost devs to create their own version. The basis of signals/slots is that widgets (or other entities) declare a signal for each type of event they can raise, and various slots as event-handlers. Communication between objects is easily accomplished by connecting signals and slots together. As an example, our AwesomeWidget is updated periodically by simply encapsulating a QTimer and, during construction, wiring its timeout() signal to a slot method in the AwesomeWidget class like so:

class AwesomeWidget : public QWidget
{
     Q_OBJECT
public:
     AwesomeWidget() 
     { 
          connect(&timer, SIGNAL(timeout()), this, SLOT(updateMe())); 
          // set interval, start timer etc...
     }
private:
     QTimer timer;
private slots:
     void updateMe();
};

Pretty simple, huh? The QTimer class similarly includes the Q_OBJECT macro and declares a timeout() signal with the same signature as updateMe(), which is fired by calling “emit timeout();”. Note:

  • The lack of boilerplate bloat, Observable/Observer coupling or intermediate Event/Action classes.
  • Despite the fact that the updateMe() slot is declared with a private access modifier, it can actually be connected to any signal with a consistent signature, regardless of location. This yields the advantage that updateMe() cannot be inadvertently invoked by code outside the AwesomeWidget class.
  • The cardinality constraint between signals and slots is many-to-many, and signals can in fact be triggered by other signals.
  • QT’s signal/slots implementation can be threadsafe, provided you follow a few basic rules. How a signal emission operates depends on the optional arguments passed to connect(). Emit calls can operate synchronously and execute signals on the same thread, returning once they complete. Or they can have signals executed on the receiver’s event-thread, in either a blocking or non-blocking fashion.

The only drawback (and it’s a pretty small one really), is that this code must be passed through QT’s meta-object compiler which interprets and verifies the signal/slot annotations, and generates the required runtime reflection code. I use a QT MSVC plugin which handles that part of it anyway.

And that’s me for another undefined stretch of time. Happy coding 🙂

This entry was posted in C++ and tagged , , , , , , , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *