# 20.8 管理應用程序設置
大多數的應用程序都會給用戶一些選項,以便用戶自己決定一些應用程序的行為,比如是否顯示每日提示,文本應用什么字體,或者是否顯示啟動畫面等.而程序員需要作的決定是怎樣保存和顯示這些配置數據.關于怎樣存儲,通常我們需要使用wxConfig家族的類,這些類讓你可以直接處理類型化的配置數據.至于如何顯示,則是非常靈活的,我們將簡短的介紹一些可能的選項.
保存配置數據
所有wxWidgets提供的用于處理配置數據的類都是wxConfigBase的派生類,因此你可以在這個基類的手冊中找到相關的使用方法.而wxConfig則被定義為各個平臺上推薦使用的用于處理配置數據的類:在windows平臺,它被定義為wxRegConfig(這個類使用 windows的注冊表),在所有別的平臺上它被定義為wxFileConfig(它使用文本文件).另外還有wxIniConfig類,它使用一個 Windows 3.1風格的.ini配置文件,不過這個類很少被使用到.而wxFileConfig則可以支持各個平臺.
wxConfig類提供了各種Read和Write函數的重載函數,用來直接讀寫各種數據類型,包括wxString, long, double和bool類型等. 配置文件中的每個項目都需要提供一個路徑,這個路徑由"/"分割并且最后必須是一個名稱,比如"/General/UseTooltips".你可以使用 wxConfig::SetPath函數設置一個當前路徑,這樣的話,在后續的讀寫中,如果沒有指定絕對路徑(以"/"開頭),所有的路徑都被認為是相對于這個路徑的路徑. 使用路徑的目的是為了對配置項進行分組.
wxConfig的構造函數需要使用應用程序名和供應商名稱,這兩個名稱用來決定配置項的位置,比如:
```
#include "wx/config.h"
wxConfig config(wxT("MyApp"), wxT("Acme"));
```
wxRegConfig將會從應用程序名和供應商名稱構造一個注冊表項,比如前面的例子中將會導致注冊表項 HKEY_CURRENT_USER/Software/Acme/MyApp被創建.而如果是Unix系統上的wxFileConfig類,配置文件默認被保存在文件~/.MyApp中. 而在Mac OSX上,則保存在/Library/Preferences/MyApp/Preferences中.這些缺省位置可以通過給wxConfig傳遞第三個參數來改變:
下面是一些wxConfig的用法:
```
// 讀取
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));
// 寫入
config.Write(wxT("General/DataPath"), str))
config.Write(wxT("General/ToolTips"), useToolTips));
config.Write(wxT("General/Usage"), usageCount));
```
其它一些可以使用的操作包括比例組和選項條目,查詢某個組或者某個選項是否存在,刪除一個條目或者一個組等.
你可以臨時使用wxConfig來讀取一些存放在某個地方的數據,你也可以創建一個wxConfig的實例并且在應用程序的整個生命周期維持它.wxWidgets也有一個稱為默認wxConfig對象的機制,這個默認的對象可以通過wxConfig::Set函數設置.如果設置了這個默認對象,一些wxWidgets的內部實現將會使用這個對象,比如wxFontMapper類或者平臺通用的wxFileDialog實現.
編輯選項
如果你只有很少的選項,那么普通的對話框也許就足夠了.但是有時候,選項有很多,并且非常復雜,這時候,你可能需要很多對話框或者面板, 這種情況下最通常的作法是使用包含一個wxNotebook的模式對話框,這個對話框的底部應該有OK,Cancel或者Help按鈕.其中Help按鈕的處理函數將會查詢當前正在顯示的頁面并顯示一個相應的幫助文件主題.wxWidgets提供了一個叫做wxPropertySheetDialog的對話框來處理這種情形.wxWidgets自帶的samples/dialogs例子中演示了它的使用方法.在Pocket PC上,這個對話框里的notebook控件將顯示成屏幕底部標準的屬性頁面.
你也可以使用wxListbook和wxChoicebook來代替wxNotebook,它們是控制多頁控件的又一個選擇.尤其是 wxListbook,它的API和wxNotebook幾乎相同,但是它使用wxListCtrl而不是TAB來控制頁標簽,因此你可以使用圖標和標簽來代替TAB按鈕.這在你擁有很多頁面的時候也很有用.尤其是在Mac OSX平臺上,這個平臺的wxNotebook控件不能夠自己滾動標簽按鈕,因此標簽按鈕的數目受限于wxNotebook的寬度和標簽的寬度.另外你也可以下載第三方的awxOutbarDialog控件,它實現了一個類似Outlook外觀的那種多頁控件,使用圖標來在頁面間切換.
你也可以創建自定義的分頁管理對話框,比如你可以使用wxtreeCtrl控件,這可以讓你的各個頁面保持一種樹狀的繼承關系.要實現這個自定義控件,你可以維護一組面板列表,每一個都綁定一個名字.當用戶點擊樹狀控件上的某個子項的時候,隱藏當前正在顯示的面板,而顯示樹狀控件子項對應的面板.另外一個方案是使用Jorgen Bodde制作的wxTreeMultiCtrl控件,這個控件實現了上面所介紹的內容,因此你可以以更直觀的方法使用樹狀分頁控件,而不比自己處理每個單獨的頁面.
你也可以考慮使用一個屬性編輯框:這是一個擁有一系列子項,每個子項左邊擁有一個文本標簽,右邊擁有一個編輯框.這個控件的好處在于增加和刪除設置是非常容易的,并且不影響界面的布局.不好的地方在于,如果你要編輯多行文本或者編輯一個列表就比較困難,盡管你可以攔截子項的雙擊事件,使用定制的對話框來顯示其內容. 你可以實現自己的屬性編輯框,或者你可以考慮使用wxGrid.,或者使用第三方的屬性編輯控件比如Jaakko Salli的wxPropertyGrid.有些應用程序混合使用了對話框和屬性列表,比如DialogBlocks設置對話框的配置頁面.
你最好不要使用帶有滾動條的面板或者對話框來避免配置項控件超出范圍之外,因為這會是人感覺迷惑并且也是很丑陋的.
你應該考慮將你應用程序的所有設置保存在一個統一的類中,并且為這個類實現一個拷貝構造函數,一個等于操作以及一個賦值操作.通過這種方法,你可以很容易的創建一個所有配置項的副本,將其傳遞給你的配置對話框,并且僅僅在用戶點擊了配置對話框上的OK按鈕的時候,才將修改的數據保存回你的全局配置中.
如果你沒有單獨的保存各個配置項,你需要給你的用戶提供一種直接修改配置的方法.參考光盤中的 examples/chap20/valconfig例子.其中包含了一個類wxConfigValidator,這個類可以用來作為普通控件的驗證器, 它的參數包括配置項路徑,配置項類型以及一個指向wxConfig對象的指針.其中值類型可以是wxVAL_BOOL, wxVAL_STRING或者wxVAL_LONG.如下所示:
```
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));
}
```
第9章中介紹了更多關于驗證器的知識.本節提到的那些第三方控件可以在附錄E,"wxWidgets的三方控件"中找到.
- 第一章 介紹
- 1.1 為什么要使用wxWidgets?
- 1.2 wxWidgets的歷史
- 1.3 wxWidgets社區
- 1.4 wxWidgets和面向對象編程
- 1.5 wxWidgets的體系結構
- 1.6 許可協議
- 第一章小結
- 第二章 開始使用
- 2.1 一個小例子
- 2.2 應用程序類
- 2.3 Frame窗口類
- 2.4 事件處理函數
- 2.5 Frame窗口的構造函數
- 2.6 完整的例子
- 2.7 wxWidgets程序一般執行過程
- 2.8 編譯和運行程序
- 第二章小結
- 第三章 事件處理
- 3.1 事件驅動編程
- 3.2 事件表和事件處理過程
- 3.3 過濾某個事件
- 3.4 掛載事件表
- 3.5 動態事件處理方法
- 3.6 窗口標識符
- 3.7 自定義事件
- 第三章小結
- 第四章 窗口的基礎知識
- 4.1 窗口解析
- 4.2 窗口類概覽
- 4.3 基礎窗口類
- 4.4 頂層窗口
- 4.5 容器窗口
- 4.6 非靜態控件
- 4.7 靜態控件
- 4.8 菜單
- 4.9 控制條
- 第四章小結
- 第五章繪畫和打印
- 5.1 理解設備上下文
- 5.2 繪畫工具
- 5.3 設備上下文中的繪畫函數
- 5.4 使用打印框架
- 5.5 使用wxGLCanvas繪制三維圖形
- 第五章小節
- 第六章處理用戶輸入
- 6.1 鼠標輸入
- 6.2 處理鍵盤事件
- 6.3 處理游戲手柄事件
- 第六章小結
- 第七章使用布局控件進行窗口布局
- 7.1 窗口布局基礎
- 7.2 窗口布局控件
- 7.3 使用布局控件進行編程
- 7.4 更多關于布局的話題
- 第七章小結
- 第八章使用標準對話框
- 8.1信息對話框
- 8.2 文件和目錄對話框
- 8.3 選擇和選項對話框
- 8.4 輸入對話框
- 8.5 打印對話框
- 第八章小結
- 第九章創建定制的對話框
- 9.1 創建定制對話框的步驟
- 9.2 一個例子:PersonalRecordDialog
- 9.3 在小型設備上調整你的對話框
- 9.4 一些更深入的話題
- 9.5 使用wxWidgets資源文件
- 第九章小結
- 第十章使用圖像編程
- 10.1 wxWidgets中圖片相關的類
- 10.2 使用wxBitmap編程
- 10.3 使用wxIcon編程
- 10.4 使用wxCursor編程
- 10.5 使用wxImage編程
- 10.6 圖片列表和圖標集
- 10.7 自定義wxWidgets提供的小圖片
- 第十章小結
- 第十一章剪貼板和拖放操作
- 11.1 數據對象
- 11.2 使用剪貼板
- 11.3 實現拖放操作
- 第十一章小結
- 第十二章高級窗口控件
- 12.1 wxTreeCtrl
- 12.2 wxListCtrl
- 12.3 wxWizard
- 12.4 wxHtmlWindow
- 12.5 wxGrid
- 12.6 wxTaskBarIcon
- 12.7 編寫自定義的控件
- 第十二章小結
- 第十三章數據結構類
- 13.1 為什么沒有使用STL?
- 13.2 字符串類型
- 13.3 wxArray
- 13.4 wxList和wxNode
- 13.5 wxHashMap
- 13.6 存儲和使用日期和時間
- 13.7 其它常用的數據類型
- 第十三章小結
- 第十四章文件和流操作
- 14.1 文件類和函數
- 14.2 流操作相關類
- 第十四章小結
- 第十五章內存管理,調試和錯誤處理
- 15.1 內存管理基礎
- 15.2 檢測內存泄漏和其它錯誤
- 15.3 構建自防御的程序
- 15.4 錯誤報告
- 15.5 提供運行期類型信息
- 15.6 使用wxModule
- 15.7 加載動態鏈接庫
- 15.8 異常處理
- 15.9 調試提示
- 第十五章小結
- 第十六章編寫國際化程序
- 16.1 國際化介紹
- 16.2 從翻譯說起
- 16.3 字符編碼和Unicode
- 16.4 數字和日期
- 16.5 其它媒介
- 16.6 一個小例子
- 第十六章小結
- 第十七章編寫多線程程序
- 17.1 什么時候使用多線程,什么時候不要使用
- 17.2 使用wxThread
- 17.3 用于線程同步的對象
- 17.4 多線程的替代方案
- 第十七章小結
- 第十八章使用wxSocket編程
- 18.1 Socket類和功能概覽
- 18.2 Socket及其基本處理介紹
- 18.3 Socket標記
- 18.4 使用Socket流
- 18.5 替代wxSocket
- 第十八章小結
- 第十九章使用文檔/視圖框架
- 19.1 文檔/視圖基礎
- 19.2 文檔/視圖框架的其它能力
- 19.3 實現Undo/Redo的策略
- 第十九章小結
- 第二十章完善你的應用程序
- 20.1 單個實例和多個實例
- 20.2 更改事件處理機制
- 20.3 降低閃爍
- 20.4 實現聯機幫助
- 20.5 解析命令行參數
- 20.6 存儲應用程序資源
- 20.7 調用別的應用程序
- 20.8 管理應用程序設置
- 20.9 應用程序安裝
- 20.10 遵循用戶界面設計規范
- 20.11 全書小結