January 21th 2015, UI Simplification

December 27th 2014 APK Size Reduction | | January 25th 2015 Track Rendering

In an effort to make the programmatical construction of Qt user interfaces more simple, I developed a couple of ui classes that define new widgets, that automatically connect to a given slot and save their actual state.

First, I did not want to connect the signals of a widget manually all the time for all of the created instances. I’d rather like to specify the connection in the ctor of a widget. For example, for a new line edit widget class CommonLineEdit I’d rather write:

CommonLineEdit *edit = new CommonLineEdit("Title", "Preset", "slot", this);

This would construct a LineEdit with title “Title” and initial value “Preset” and automatically connect its changed signal to a slot “slot” of the actual widget “this”. Of course, the slot needs to be present in the widget class having the signature “protected slots: void slot(QString text);”. This way any changed value of the line edit ui element gets delivered to the slot via its parameter “text”.

That’s a nice improvement over standard Qt behavior, because adding another ui element is just a one liner. But how is the connection done, since the connection scheme usually needs to be defined as string literal at compile time and cannot be specified at run-time via string parameter?

The solution is to use the QObject::invokeMethod(…) method of any QWidget derived class.

Suppose we would like to pass a QString parameter “arg” to an existing slot “void slot(QString arg)”. Then we invoke the slot via Qt introspection:

QObject *object = ... slot container object ...
QString method = ... slot method name ...
QString arg = ... slot argument ...

QMetaObject::invokeMethod(object, method.toStdString().c_str(), Q_ARG(QString, arg));

As a nice side effect Qt introspection also enables us to automatically store the last edited contents of the new widget class. We simply store its last contents in the widget’s dtor by saving it to a corresponding QPreferences entry.

Question is, how do we distinguish the contents of multiple ui elements? For that we need to automatically construct a unique key. The combination of the slot’s method name and the slot’s widget class name is unique for each widget and does the trick:

QString key = (QString(object->metaObject()->className()) + "." + method);

With that unique key we can automatically store the contents of each instantiated line edit in its dtor (and read it back in the ctor, if present):

QSettings settings(orgName, appName);

settings.setValue(key, text());

Now, creating another auto-saving and auto-connecting line edit is a one liner ;-)

December 27th 2014 APK Size Reduction | | January 25th 2015 Track Rendering