# 13.3 wxArray
wxWidgets使用wxArray提供了一種動態的數組結構.和C語言的數組結構類似,對于其數組項的訪問時間為一個常量.對然這樣,其內存仍然是動態分配的,換句話說,如果其內存不夠再增加子項的時候,它將動態分配內存.在提前分配內存的前提下,其增加數組項的時間也大體上是一個常量. wxArray類型還提供了邊界檢查的功能,在調試版本中,越界訪問將會導致斷言錯誤,而在正式版本中,越界訪問將不會出現任何提示,而這種訪問的結果可能會是一個隨機值.
數組類型
wxWidgets提供了三種不同類型的數組.它們都是wxBaseArray的派生類,在它們的數值類型未定義之前是不能直接使用的. 換句話說,你必須使用WX_DEFINE_ARRAY, WX_DEFINE_SORTED_ARRAY和WX_DEFINE_OBJARRAY宏來定義一個它們的派生類才可以使用它們.這種基類的名稱分別為 wxArray,wxSortedArray和wxObjArray,但是你應該有這個概念:這三個類其實是不存在的,并沒有這樣的類,這個名稱只是為了用來說明問題用的.
wxArray這種類型,它的派生類可以用來存儲整數類型以及指針類型,這種類型永遠不會將它的成員按照對象來對待,也就是說:數組中的元素(無論是整數還是指針)從數組移除的時候并不會被釋放.還應該提到的是:wxArray類型的成員函數都是內聯函數,因此程序的大小和運行效率完全不受其派生類個數的影響.這種類型最大的限制在于,它只能存儲整形數據,比如bool,char,int,long和它們的無符號變體或者任何類型的指針.而浮點行或者double型的數據是不可以用wxArray來存儲的.
wxSortedArray和wxArray比較,區別在于,當你需要很頻繁的數組進行查找操作時,你應該使用前者.它需要你定義一個比較函數,通過這個比較函數,它將把其內部的元素始終按順序排列,如果你擁有大量數據并且需要頻繁查找,那么使用它性能比使用wxArray要好的多.其它方面兩者擁有同樣的限制,wxSortedArray也只能存儲整形數據.
wxObjArray類則將其內部存儲的元素按照對象來對待.它知道在元素從數組中移除的時候釋放相應的內存(通過調用其析構函數), 并且使用用于拷貝的構造函數實現拷貝.要定義一個這種類型的派生對象需要兩個步驟.首先,使用WX_DECLARE_OBJARRAY宏來聲明一個 wxObjArray,然后包含其實現文件<wx/arrimpl.cpp>并且在完整聲明了其數據元素對象的地方調用 WX_DEFINE_OBJARRAY宏.讀起來有些繞口,不過我們很快會舉一個簡單的例子.
wxArrayString
wxArrayString是存儲wxString類型的一個很經濟有效的類,它擁有和wxArray類完全一致的功能.它占用的空間也要比直接使用C數組類型wxString[]占用的空間要小的多(這是因為它使用了一些直接對wxString類內部進行操作的方法).所有在 wxArray中可以使用的函數都可以在wxArrayString中使用.
這個類使用上也和其它類差別不大,唯一的區別在于不需要象別的類那樣使用WX_DEFINE_ARRAY宏,而可以直接在代碼中使用. 當一個wxString實例被插入這個數組時,wxArrayString將創建一份這個字符串的拷貝,應該在成功插入以后,你可以放心的釋放原來的字符串.一般情況下,你也不需要關心wxArrayString的內存分配問題,它可以自己釋放它所占用的所有的內存.
另外注意Item, Last和操作符[]返回的只是引用而不是拷貝,因此,對它們返回值的操作將導致數組內部數據的改變,如下所示:
```
array.Last().MakeUpper();
```
對應的也有一個wxSortedArrayString對象,這個對象中的字符串總是按照子母順序排序的.在得到對應字符串的Index 時,wxSortedArrayString使用二進制搜索方式,性能很高.因此如果你的程序中插入字符串的操作很少,而對其進行搜索的操作很多,你可以考慮使用這個類.需要注意的是不要調用這個類的Insert和Sort函數,這兩個函數可能會攪亂wxSortedArrayString的內部排序.
數組的構造,析構和內存管理
數組對象也是通用的C++對象,也有對應的構造和賦值操作.拷貝一個wxArray對象意味著其內部元素的拷貝而拷貝一個 wxObjArray對象則是直接拷貝這個數組的子項.不過,出于內存效率的考慮,這兩個類都沒有虛的析構函數.對于wxArray來說這并不是很重要, 因為其析構函數不需要作什么太多的事情,而對于wxObjArray來說,絕對不要通過刪除一個指向wxBaseArray類型的指針來釋放相應的數組 (譯者注:這將導致對應的析構函數不被調用),并且也永遠不要從你自己的數組類再派生新的類型(譯者注:同樣的原因,新類型的釋放將導致使用宏定義的類型的析構函數不被調用).
數組的內存自動管理機制也是很簡單的:它在開始的時候會預分配一塊小的內存(由宏 WX_ARRAY_DEFAULT_INITIAL_SIZE指定).當發現不夠用的時候,就增加當前內存的50%(但是不超過 ARRAY_MAXSIZE_INCREMENT).Shrink函數可以用來在沒有新數據插入的時候釋放多余的內存.而Alloc函數可以在你知道總共需要多少內存的時候被調用以便數組對象不那么頻繁的進行分配內存的操作.
數組示例:
下面的例子演示了使用數組最復雜的情況,定義和使用針對自定義類型的wxObjArray數組.使用wxArray的基本原則和例子中演示的是相似的,只不過wxArray類永遠不需要和自己內部存儲的數據發生什么關系.
```
// 我們自定義的數據類型
class Customer
{
public:
int CustID;
wxString CustName;
};
// 這一部分的代碼可以位于頭文件或者源文件(.cpp)文件中
// 用于聲明我們的自定義數組:
WX_DECLARE_OBJARRAY(Customer, CustomerArray);
// 增加下面語句的唯一的要求是,自定義的Customer類型已經完全聲明
// (對于WX_DECLARE_OBJARRAY來說,前面的聲明已經足夠了)
// 而且通常它應該被放在源文件中而不是頭文件中.
#include <wx/arrimpl.cpp>
WX_DEFINE_OBJARRAY(CustomerArray);
// 用于排序的時候對兩個對象進行比較
int arraycompare(Customer** arg1, Customer** arg2)
{
return ((*arg1)->CustID < (*arg2)->CustID);
}
// 數組測試例子
void ArrayTest()
{
// 定義一個我們數組的實例
CustomerArray MyArray;
bool IsEmpty = MyArray.IsEmpty(); // will be true
// 創建一些自定義對象實例
Customer CustA;
CustA.CustID = 10;
CustA.CustName = wxT("Bob");
Customer CustB;
CustB.CustID = 20;
CustB.CustName = wxT("Sally");
Customer* CustC = new Customer();
CustC->CustID = 5;
CustC->CustName = wxT("Dmitri");
// 將其中兩個增加到數組中
MyArray.Add(CustA);
MyArray.Add(CustB);
// 將最后一個插入到數組的任意位置.
// 數組將會產生一個自定義對象的拷貝
MyArray.Insert(*CustC, (size_t)0);
int Count = MyArray.GetCount(); // will be 3
// 如果找不到將返回wxNOT_FOUND
int Index = MyArray.Index(CustB); // will be 2
// 依次處理數組中的對象
for (unsigned int i = 0; i < MyArray.GetCount(); i++)
{
Customer Cust = MyArray[i]; // 或者使用MyArray.Item(i);
// 進行一些處理
}
// 按照自己提供的比較函數進行排序
MyArray.Sort(arraycompare);
// 移除但不釋放A對象
Customer* pCustA = MyArray.Detach(1);
// 如果使用Detach函數,我們需要自己釋放對象
delete pCustA;
// 如果使用Remove函數,就不需要了
MyArray.RemoveAt(1);
// Clear函數也不需要
MyArray.Clear();
// 數組從來就不會理會我們自己產生的C對象,要自己釋放它
delete CustC;
}
```
- 第一章 介紹
- 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 全書小結