Диалоговое окно настроек платформы с Qt на Mac, Gnome, KDE и Windows
На Mac и Gnome нативные приложения используют диалог настроек приложения, который сразу же применяет выбранные параметры по мере их выбора. В Windows и (я думаю) KDE настройки применяются только при нажатии кнопки "Применить" или "ОК".
Есть ли в Qt встроенные вкусности, чтобы сделать это для вас, или вам нужно включить несколько #ifdef
в коде диалога, чтобы справиться с этим (Q_WS_WIN
, Q_WS_MAC
, Q_WS_X11
)?
Если вы сделали что-то подобное раньше (даже используя #ifdef
s), не могли бы вы поделиться скелетным кодом относительно того, как вы это сделали?
2 ответа
Похоже, ты должен раскрутить свой собственный. Вот важные части нашего решения. Это, вероятно, можно обобщить, если кто-то так склонен. Я также могу предположить определенные вещи из-за наших бизнес-правил, которые могут нарушить другие приложения. Переключатель - это макрос, который можно определить во время компиляции: 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 - это кроссплатформенная абстракция, которую можно использовать для сохранения предпочтений, поэтому мы надеемся, что это позволит избежать использования #IFDEFs
Я также обнаружил, что у него действительно хорошая производительность. Настолько хорошо, что я просто установил прослушиватель событий и позвонил save()
на каждое событие.
Класс формы содержит фильтр событий, подобный этому:
def __init__(self, *args, **kwargs):
# ....
self.installEventFilter(self)
# ....
def eventFilter(self, obj, event):
self.save()
return False
И мой save()
Метод выглядит так:
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())
Так что, да, вы должны самостоятельно выполнить некоторую работу, чтобы сразу сохранить ваши настройки - но я не нашел это слишком трудным.
И хотя он (все еще) чувствует себя немного измотанным, чтобы распылять save() на каждом событии, QSettings
прекрасная производительность сделала эту операцию незаметной для пользователя.
Написание небольшого класса, который перечисляет каждый виджет в форме и сохраняет / восстанавливает каждое из его свойств в QSettings
также будет аккуратным. Это может быть уместно, если у вас есть несколько десятков / сотен предпочтений. Я отправлю сюда, когда я это сделаю.