Preferences allow a user to customize the application in certain areas. Preferences can be set in two different ways, either through a preferences dialog or through menu commands. Usually the preferences dialog sets them permanently while menu commands set them only for the current session. That means whenever you start an application it gets the preferences set by the last dialog while any changes through menu commands are lost.
The preference dialog is the usual place to specify any setting a user may configure to his liking. When the dialog is left with the OK button the current preferences are save and persists until they are changed again with this dialog. Any optional Apply button save the preferences as well but doesn't close the dialog.
It's getting more common that changes in the preferences get directly forwarded and applied to the main windows so an immediate feedback is given. While this is a nice feature it's not always easy to implement but if you plan this for your application do it either always or never.
#include "prefdlg.h" // Preferences dialog class AppFrame: public wxFrame { ... void OnPreferences (wxCommandEvent &event); ... } BEGIN_EVENT_TABLE (AppFrame, wxFrame) ... EVT_MENU (myID_PREFS, AppFrame::OnPreferences) ... END_EVENT_TABLE () void AppFrame::OnPreferences (wxCommandEvent &event) { PreferenceDlg (this); } ... BEGIN_EVENT_TABLE (PreferenceDlg, wxDialog) EVT_BUTTON (wxID_APPLY, PreferenceDlg::OnApply) EVT_BUTTON (wxID_CANCEL, PreferenceDlg::OnCancel) EVT_BUTTON (wxID_OK, PreferenceDlg::OnOkay) EVT_BUTTON (wxID_RESET, PreferenceDlg::OnReset) END_EVENT_TABLE() PreferenceDlg::PreferenceDlg (wxWindow *parent, long style) : wxDialog (parent, -1, _("Preferences"), wxDefaultPosition, wxDefaultSize) { // load configuration LoadValues (); // create preference panel wxPanel *panel = new wxPanel (this, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL|wxCLIP_CHILDREN|wxNO_BORDER); // lauout the buttons wxButton *resetButton = new wxButton (panel, wxID_RESET, _("Default")); wxButton *okButton = new wxButton (panel, wxID_OK, _("OK")); okButton->SetDefault(); wxButton *applyButton = new wxButton (panel, wxID_APPLY, _("Apply")); wxButton *cancelButton = new wxButton (panel, wxID_CANCEL, _("Cancel")); wxBoxSizer *buttonpane = new wxBoxSizer (wxHORIZONTAL); buttonpane->Add (resetButton, 0, wxALIGN_LEFT|wxALIGN_CENTER_VERTICAL); buttonpane->Add (16, 0, 1); buttonpane->Add (okButton, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL); buttonpane->Add (6, 0); buttonpane->Add (applyButton, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL); buttonpane->Add (6, 0); buttonpane->Add (cancelButton, 0, wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL); // set sizer wxBoxSizer *panelsizer = new wxBoxSizer (wxVERTICAL); panelsizer->Add (... panelsizer->Add (0, 6); panelsizer->Add (buttonpane, 0, wxEXPAND|wxLEFT|wxRIGHT|wxBOTTOM, 10); panel->SetSizer (panelsizer); panelsizer->Fit (this); Centre (wxBOTH); ShowModal(); } PreferenceDlg::~PreferenceDlg () { } //---------------------------------------------------------------------------- // event handlers void PreferenceDlg::OnApply (wxCommandEvent &WXUNUSED(event)) { ... SaveValues (); } void PreferenceDlg::OnCancel (wxCommandEvent &WXUNUSED(event)) { EndModal (wxID_CANCEL); } void PreferenceDlg::OnOkay (wxCommandEvent &WXUNUSED(event)) { ... SaveValues (); EndModal (wxID_OK); } void PreferenceDlg::OnReset (wxCommandEvent &WXUNUSED(event)) { ... } void PreferenceDlg::LoadValues () { wxString key = KEYNAME; key.Append (_T("/")); wxConfig *cfg = new wxConfig (wxTheApp->GetAppName()); cfg->Read (key + VALUENAME, ...); ... delete cfg; } void PreferenceDlg::SaveValues () { wxString key = KEYNAME; key.Append (_T("/")); wxConfig *cfg = new wxConfig (wxTheApp->GetAppName()); cfg->Write (key + VALUENAME, ...); ... delete cfg; }
Setting preferences via menu command allow changing them for the current session. When the application ends these settings are lost. Usually only the immediately necessary settings are available as menu commands.
class AppFrame: public wxFrame { ... // View menu wxMenu *menuView = new wxMenu; menuView->AppendCheckItem (myID_TOOLBARS, _("Tool &bar")); menuView->AppendCheckItem (myID_STATUSBAR, _("Status b&ar")); ... }
Preferences are usually stored with in the registry (Windows) or config file (Linux, etc.). wxWidgets supports this through wxConfig choosing the platform specific solution itself. Be carefully when keeping the preferences open over a longer time period. For safety reasons keep this period as small as possible.
One might use wxFileConfig instead to force the use of config file even on Windows. The default location of the config file is based on the $HOME variable on Linux, etc. and $HOMEDRIVE + HOMEPATH on Windows. The file will only be written back to disk when the config objected is deleted or the Flush() method is called.
#include <wx/config.h> // configuration support const wxString PAGE_COMMON = _T("Common"); ... const wxString NOSPLASH = _T("NoSplashScreen"); const wxString SHOWTOOLBAR = _T("ShowToolbar"); const wxString SHOWSTATUSBAR = _T("ShowStatusbar"); const wxString USEPAGES = _T("UsePages"); CommonPrefs g_CommonPrefs = { // application prefs false, // noSplash true, // showToolbar true, // showStatusbar false, // usePages }; ... void PreferenceDlg::LoadValuesPageCommon () { wxString key = PAGE_COMMON; key.Append (_T("/")); // common prefs wxConfig *cfg = new wxConfig (wxTheApp->GetAppName()); cfg->Read (key + NOSPLASH, &g_CommonPrefs.noSplash); cfg->Read (key + SHOWTOOLBAR, &g_CommonPrefs.showToolbar); cfg->Read (key + SHOWSTATUSBAR, &g_CommonPrefs.showStatusbar); cfg->Read (key + USEPAGES, &g_CommonPrefs.usePages); delete cfg; } void PreferenceDlg::SaveValuesPageCommon () { wxString key = PAGE_COMMON; key.Append (_T("/")); // common prefs wxConfig *cfg = new wxConfig (wxTheApp->GetAppName()); cfg->Write (key + NOSPLASH, g_CommonPrefs.noSplash); cfg->Write (key + SHOWTOOLBAR, g_CommonPrefs.showToolbar); cfg->Write (key + SHOWSTATUSBAR, g_CommonPrefs.showStatusbar); cfg->Write (key + USEPAGES, g_CommonPrefs.usePages); delete cfg; }