On Mac and Gnome, native applications use an application preferences dialog that immediately applies the chosen settings as they are selected. On Windows and (I think) KDE, preferences are applied only when an "Apply" or "OK" button is pressed.
Are there any built-in Qt goodies to do this for you, or do you have to include several #ifdef
's in the dialog code to handle this (Q_WS_WIN
, Q_WS_MAC
, Q_WS_X11
)?
If you have done something like this before (even using #ifdef
's), could you share skeleton code as to how you pulled it off?
Looks like you have to spin your own. Here are the important parts of our solution. This could probably be generalized if someone is so inclined. I'm also able to assume certain things because of our business rules that may break other applications. The toggle is a macro that can be defined at compile-time: YOUR_APP_APPLY_PREFERENCES_IMMEDIATELY
preferences_dialog.h
class PreferencesDialog : public QDialog {
Q_OBJECT
public:
explicit PreferencesDialog(... various arguments ...,
QWidget *parent);
private slots:
void ModifyMapLanguages();
private:
void ApplyLanguageChanges(const QList<Language> &languages,
const QHash<LanguageKey, LanguageKey> &renames);
void Initialize();
#ifndef YOUR_APP_APPLY_PREFERENCES_IMMEDIATELY
public slots:
void accept();
private slots:
void ApplyDialog();
private:
QList<Language> pending_languages_;
QHash<LanguageKey, LanguageKey> pending_language_renames_;
#endif
};
preferences_dialog.cpp
#include "forms/preferences_dialog.h"
#include "ui_preferences_dialog.h"
PreferencesDialog::PreferencesDialog(... various arguments ...,
QWidget *parent) :
QDialog(parent),
... various initializers ... {
ui->setupUi(this);
Initialize();
}
void PreferencesDialog::ApplyLanguageChanges(
const QList<Language> &languages,
const QHash<LanguageKey, LanguageKey> &renames) {
// Do the actual changes here, whether immediate or postponed
}
void PreferencesDialog::Initialize() {
// Disable the minimize and maximize buttons.
Qt::WindowFlags flags = this->windowFlags();
flags |= Qt::CustomizeWindowHint;
flags &= ~Qt::WindowMinMaxButtonsHint;
setWindowFlags(flags);
// buttons is the QDialogButtonBox with Ok, Cancel, and Apply buttons
#ifdef YOUR_APP_APPLY_PREFERENCES_IMMEDIATELY
ui->buttons->setVisible(false);
#else
QPushButton *apply_button = ui->buttons->button(QDialogButtonBox::Apply);
connect(apply_button, SIGNAL(clicked()), SLOT(ApplyDialog()));
#endif
}
void PreferencesDialog::ModifyMapLanguages() {
// Get the changes; in my case, they are coming from a dialog wizard
LanguageSetupWizard wizard(map_->languages(), true, this);
wizard.setWindowModality(Qt::WindowModal);
if (QDialog::Accepted == wizard.exec()) {
#ifdef YOUR_APP_APPLY_PREFERENCES_IMMEDIATELY
ApplyLanguageChanges(wizard.languages(), wizard.language_renames());
#else
pending_languages_ = wizard.languages();
pending_language_renames_ = wizard.language_renames();
#endif
}
}
#ifndef YOUR_APP_APPLY_PREFERENCES_IMMEDIATELY
void PreferencesDialog::ApplyDialog() {
if (!pending_languages_.isEmpty()) {
ApplyLanguageChanges(pending_languages_, pending_language_renames_);
}
}
void PreferencesDialog::accept() {
ApplyDialog();
QDialog::accept();
}
#endif
QSettings is a cross-platform abstraction that can be used for saving preferences, so hopefully that obviates the use of #IFDEFs
I also found that it has really good performance. So good, in fact, that I just installed an event listener and called save()
upon every single event.
The form's class contains an event filter like this:
def __init__(self, *args, **kwargs):
# ....
self.installEventFilter(self)
# ....
def eventFilter(self, obj, event):
self.save()
return False
And my save()
method looks like this:
self.app.settings.setValue(self.state_key, self.header.saveState())
self.app.settings.setValue(self.geometry_key, self.header.saveGeometry())
self.app.settings.setValue("connect_timeout_spinBox_value", self.connect_timeout_spinBox.value())
self.app.settings.setValue("reveal_downloads_checkbox_checked", self.reveal_downloads_checkbox.checkState())
So, yes, you have to do some leg-work yourself to get your prefs saved immediately - but I didn't find it too arduous.
And although it (still) feels a bit ham-fisted to spray out save()s on every event, QSettings
fine performance made this operation undetectable to the user.
Writing a small class which enumerates every widget on a form and saves/restores each of its properties in QSettings
would also be neat. This might be appropriate if you have some some tens/hundreds of preferences. I'll post back here when I've done it.