PDA

View Full Version : Restoring Widget State--"Best Practices"?



davethomaspilot
14th January 2013, 13:08
I use QSettings to save and restore the state of things like checkboxes, radioboxes and the currentIndex of comboboxes.

I set the state of these in an owning widgets constructor, using QSetting::getValue(). I connect a signal like toggled(bool) from each widget to a private slot with code that does nothing other than a QSetting::setValue, based on the boolean passed by the toggled(bool) value.

So, I end up having to create a trivial member function for each widget, that does nothing other than keep the QSetting consistent with the current state of the widget.

I could only save the settings on application exit, but it's very nice to be able to get all the widgets back to a saved state when things like exceptions occur (during code development). So, I've fallen into the habit of keeping the QSetting updated every time the widget changes.

Is this a bad practice? Also, saving the state of something simple like a checkbox involves:

1) Connect statement in constructor (toggled(bool) to trivial slot function.
2) Header file update for the private slot.
3) cpp file update for slot implementation.

Is there an easier/better way?

Thanks,

Dave Thomas

ChrisW67
14th January 2013, 22:37
For a couple of checks/radio buttons this is probably the most obvious way. For a larger number you could make use of the QObject object name to hold the name of the settings key for the check box and then use that in a single servicing slot. Here is an example with generated keys but you can set them manually (in Designer for example):



#include <QtGui>

class LotsOfChecks: public QWidget {
Q_OBJECT
public:
LotsOfChecks(QWidget *p = 0): QWidget(p) {

QVBoxLayout *layout = new QVBoxLayout(this);
setLayout(layout);
for (int i = 0; i < 10; ++i) {
QCheckBox *cb = new QCheckBox("Some cool label", this);
cb->setObjectName(QString("Check_%1").arg(i));
connect(cb, SIGNAL(toggled(bool)), SLOT(storeCheck(bool)));
layout->addWidget(cb);
}
restoreChecks();
}
private:
void restoreChecks() {
QSettings settings;
foreach(const QString &key, settings.childKeys()) {
QCheckBox *cb = findChild<QCheckBox*>(key);
if (cb)
cb->setChecked(settings.value(key).toBool());
}
}

private slots:
void storeCheck(bool checked) {
QString key = sender()->objectName();

QSettings settings;
settings.setValue(key, checked);
}
};

int main(int argc, char **argv)
{
QApplication app(argc, argv);
app.setApplicationName("thisapp");
app.setOrganizationName("com.example");

LotsOfChecks w;
w.show();

return app.exec();
}
#include "main.moc"

wysota
15th January 2013, 09:00
I would suggest a generic approach that involves querying each widget for the user property, connecting to that property changes and storing them in settings.

It can all be done with QMetaObject, QMetaProperty and QMetaMethod. Pseudocode:

1. check widget's USER property by asking QMetaObject::userProperty()
2. check the notify method for this property using QMetaProperty::notifySignal()
3. chek the signal signature with QMetaMethod::signature()
4. connect to that signal with a custom slot taking no arguments
5. recursively do the same for all child widgets you want to service

In the custom slot simply ask the sender() for its USER property again, read its value and store along the object name of the widget.

For restoring the state, do the same just adding a step to set the property value before step 4.

davethomaspilot
15th January 2013, 12:10
Thanks for taking the time for this reply, complete with example code! This seems much better than what I've been doing.

Is this a common way of doing this, or do most developers do it in the more straight forward (but a bit tedious) way?

Added after 11 minutes:

Previous reply was to ChrisW67.

Wysota, if I understand correctly, use of the "Meta" classes with this technique will restore the state of ALL widget types?

Same question I had for Chris. Is this a commonly used techinque? If so, are there example code fragments somewhere?

Thank you both for taking the time to reply. This forum has saved me many hours of time and is helping get on board with Qt, and inspiring me to invest in learning how to "do it right" instead of "just getting it done".

wysota
15th January 2013, 12:28
Wysota, if I understand correctly, use of the "Meta" classes with this technique will restore the state of ALL widget types?
Yes, all that have a USER property defined (I think all built-in widgets do). You just have to be aware not to overdo it -- e.g. if you have a QCalendarWidget then it consists of a number of other widgets. You don't want to recurse from QCalendarWidget to its children, it's enough to use the USER property QCalendarWidget defines. Hence you have to provide stop conditions for complex widgets.