Cross-Platform GUI Programming with wxWidgets
|
Most applications have options to let the user to change the program's behavior, such as toggling tooltips on and off, changing text fonts, or suppressing a splash screen. The developer must make choices about how these settings will be stored and displayed. For storage, the usual solution is to use the wxConfig family of classes, which is especially intended to store typed application settings. The choice of user interface is much more varied, and we'll explore some possibilities shortly. Storing Settings
The configuration classes that wxWidgets provides are derived from wxConfigBase, which is where you'll find the documentation in the reference manual. On each platform, wxConfig is an alias for an appropriate class: on Windows it's wxRegConfig (using the Windows Registry), and on all other platforms it's wxFileConfig (using text files). wxIniConfig is available, using Windows 3.1-style .ini files, but this is rarely needed. wxFileConfig is available on all platforms. wxConfig provides the overloaded functions Read and Write to read and store items of type wxString, long, double, and bool. Each item is referenced by a name comprising a list of slash-separated pathsfor example, "/General/UseTooltips". By using wxConfig::SetPath, you can set the current position in the hierarchy, and subsequent references will be relative to that position if they do not have a leading slash. You can use paths to group your settings. wxConfig constructors take an application name and vendor name, which are used to determine the location of the settings. For example: #include "wx/config.h" wxConfig config(wxT("MyApp"), wxT("Acme")); wxRegConfig constructs a location from the vendor name and application name, and in the previous example, the settings will be stored under HKEY_CURRENT_USER/Software/Acme/MyApp in the Registry. Using wxFileConfig on Unix, the settings are stored by default in a file called ~/.MyApp. On Mac OS X, they are stored in Here are some examples of wxConfig usage: // Read some values wxString str; if (config.Read(wxT("General/DataPath"), & str)) { ... } bool useToolTips = false; config.Read(wxT("General/ToolTips"), & useToolTips)); long usageCount = 0; config.Read(wxT("General/Usage"), & usageCount)); // Write some values config.Write(wxT("General/DataPath"), str)) config.Write(wxT("General/ToolTips"), useToolTips)); config.Write(wxT("General/Usage"), usageCount));
You can also iterate through groups and entries, query whether a group or entry exists, and delete an entry or group, among other operations. wxConfig can be used as a temporary way of reading and writing data that you store elsewhere in your application, or you can create an instance of wxConfig that is not deleted until the application exits. wxWidgets has the concept of a default wxConfig object, which you can set with wxConfig::Set. If present, the default wxConfig object may be used internallyfor example, by the wxFontMapper class and the generic wxFileDialog implementation. Editing Settings
If you only have a few settings to edit, an ordinary dialog may be sufficient. For a more complex application, you will need to use a number of dialogs or panels, and the most common method is to use a wxNotebook on a modal dialog, with OK, Cancel, and Help buttons underneath the notebook. The handler for the Help button will query the notebook for the current page in order to determine the appropriate help topic to display. wxWidgets provides wxPropertySheetDialog for this purpose, as illustrated in samples/dialogs in your wxWidgets distribution. On Pocket PC, the notebook in this dialog is displayed as a standard property sheet with tabs along the bottom. You might want to use wxListbook or wxChoicebook instead of wxNotebook, which are alternative methods of controlling pages. In particular, wxListbook has an identical API to wxNotebook but makes use of a wxListCtrl, so you can use icons and labels instead of tabs. This makes sense if you have a lot of pages, particularly because on Mac OS X, notebook tabs don't scroll as they do on other platforms, and therefore the number of tabs is limited by the width of the settings dialog. You can download a third-party class called awxOutbarDialog, which implements an Outlook-like settings dialog using icons to switch pages. You can also create your own paged settings dialog using a wxtreeCtrl, for example, so that your pages can be grouped in a hierarchy. To implement this, keep a list of panels, each associated with a path name, and when the user clicks on a tree item, hide the current panel and show the new panel. Another solution is to use Jorgen Bodde's wxtreeMultiCtrl, which manages a hierarchy of controlsa more direct method than separating out the tree control from the settings controls. You might also consider using a property list: a scrolling list of items with a label on the left and editable value on the right. An advantage of this concise approach is that it's very easy to add or remove settings because the layout is not dependent on the number of settings. A disadvantage is that it's harder to edit larger multi-line text or a list of items, although you can arrange for specialized editors to be shown when you double-click the item. You can write your own implementation, perhaps using wxGrid, or you could look at third-party implementations such as Jaakko Salli's wxPropertyGrid Some applications mix a paged settings dialog approach with property lists, for example the Configuration panel in the DialogBlocks Settings dialog. It is recommended that you don't use scrolling panels or dialogs if you are running out of space, because this can be confusing and awkward to navigate. Consider storing all your application settings in a separate class and implementing a copy constructor, equality operator, and assignment operator. This way, you can easily make a temporary copy of your global settings object, pass it to the Settings dialog, and only copy the modified settings back to the global object if the dialog was dismissed using the OK button. If you're not storing the settings separately, you need a way for the user to modify these settings directly. See examples/chap20/valconfig for a class wxConfigValidator that you can use with commonly used controls. The validator takes the setting path, the setting type, and a pointer to the wxConfig object. The type can be wxVAL_BOOL, wxVAL_STRING, or wxVAL_LONG. For example: void MyDialog::SetValidators(wxConfig* config) { FindWindow( ID_LOAD_LAST_DOCUMENT )->SetValidator( wxConfigValidator(wxT("LoadLastDoc"), wxVAL_BOOL, config)); FindWindow( ID_LAST_DOCUMENT )->SetValidator( wxConfigValidator(wxT("LastDoc"), wxVAL_STRING, config)); FindWindow( ID_MAX_DOCUMENTS)->SetValidator( wxConfigValidator(wxT("MaxDocs"), wxVAL_LONG, config)); }
You can find more on validators in Chapter 9. The third-party classes mentioned in this section are listed in Appendix E, "Third-Party Tools for wxWidgets." |
|