# 12.2 wxListCtrl
列表控件使用四種形式中的一種來顯示子項:多列視圖,多列報告視圖,大圖標方式以及小圖標方式.下圖分別對齊進行了演示.每一個子項使用一個長整型的索引來表示的,隨著子項的增加,刪除以及排序,這個索引可能發生變化.和樹狀控件不同,列表框默認采用允許多選的方式,不過你還是可以在創建窗口的時候通過類型指定只允許單選.如果你需要對所有子項進行排序,你可以提供一個排序函數.在多列報告視圖中,可以給每一列增加一個標題,點過攔截標題單擊事件可以實現一些附加操作比如按當前列進行排序.每一列的寬度既可以通過代碼改變,也可以通過用戶使用鼠標拖拽來改變.




列表控件的每個子項同樣可以綁定一些客戶區數據,但是和樹狀控件不同,每一個列表框的子項只能綁定一個長整型數據.如果你希望給每一個子項綁定一個特定對象,你需要自己實現一個從長整型到特定數據對象之間的隱射,并且自己負責那些數據對象的創建和釋放.
wxListCtrl的窗口類型
| wxLC_LIST | 使用可選的小圖標進行多列顯示.列數是自動計算的,不需要設置象wxLC_REPORT那樣設置列數,換句話說,這只是一個自動換行的排列. |
|:--- |:--- |
| wxLC_REPORT | 單列或者多列報告方式,并且可以設置可選的標題. |
| wxLC_VIRTUAL | 指定顯示的文本由應用程序動態提供; 只能用于wxLC_REPORT方式. |
| wxLC_ICON | 大圖標方式顯示,可選顯示文本標簽. |
| wxLC_SMALL_ICON | 小圖標方式顯示,可選顯示文本標簽 |
| wxLC_ALIGN_TOP | 圖標頂端對齊. 僅適用于Windows. |
| wxLC_ALIGN_LEFT | 圖標左對齊. |
| wxLC_AUTO_ARRANGE | 圖標自動排列.僅適用于Windows. |
| wxLC_EDIT_LABELS | 標簽可編輯; 當編輯動作開始時應用程序將收到通知. |
| wxLC_NO_HEADER | 在報告模式下不顯示標題. |
| wxLC_SINGLE_SEL | 指定單選模式; 默認為多選模式. |
| wxLC_SORT_ASCENDING | 從小到大排序. 應用程序需要在SortItems中提供自己的排序函數. |
| wxLC_SORT_DESCENDING | 從大到小排序. 應用程序需要在SortItems中提供自己的排序函數. |
| wxLC_HRULES | 在報告模式中顯示每行之間的標尺. |
| wxLC_VRULES | 在報告模式中顯示每列之間的標尺. |
wxListCtrl事件
wxListCtrl產生wxListEvent類型的事件,如下表所示,事件可以父子窗口之間傳遞,wxListEvent::GetIndex可以用來返回針對單個子項的事件中的子項索引.
| EVT_LIST_BEGIN_DRAG(id, func) EVT_LIST_BEGIN_RDRAG(id, func) | 這個事件在拖放開始的時候產生,如果要實現拖放,你需要提供拖放操作的剩下的部分.通過wxListEvent::GetPoint函數獲取當前的鼠標位置. |
|:--- |:--- |
| EVT_LIST_BEGIN_LABEL_EDIT(id, func) EVT_LIST_END_LABEL_EDIT(id, func) | 用戶正準備編輯標簽或者結束編輯的時候產生,使用Veto函數可禁止這種編輯行為.wxListEvent::GetText則返回當前的標簽. |
| EVT_LIST_DELETE_ITEM(id, func) EVT_LIST_DELETE_ALL_ITEMS(id, func) | 事件在某個子項被刪除或者所有的子項都被刪除的時候產生. |
| EVT_LIST_ITEM_SELECTED(id, func) EVT_LIST_ITEM_DESELECTED(id, func) | 在子項的選中狀態發生改變的時候產生. |
| EVT_LIST_ITEM_ACTIVATED(id, func) | 在某個子項被激活(鼠標雙擊或者通過鍵盤)的時候產生. |
| EVT_LIST_ITEM_FOCUSED(id, func) | 當當前焦點子項發生改變的時候產生. |
| EVT_LIST_ITEM_MIDDLE_CLICK(id, func) EVT_LIST_ITEM_RIGHT_CLICK(id, func) | 在子項被鼠標以中鍵或者右鍵單擊的時候產生. |
| EVT_LIST_KEY_DOWN(id, func) | 在有針對列表控件的按鍵事件的時候產生. 使用wxListEvent::GetKeyCode函數來得到當前按鍵的編碼. |
| EVT_LIST_INSERT_ITEM(id, func) | 新的子項插入的時候產生. |
| EVT_LIST_COL_CLICK(id, func) EVT_LIST_COL_RIGHT_CLICK(id, func) | 某一列被單擊的時候產生.使用wxListEvent::GetColumn函數獲得被單擊的列索引. |
| EVT_LIST_COL_BEGIN_DRAG(id, func) EVT_LIST_COL_DRAGGING(id, func) EVT_LIST_COL_END_DRAG(id, func) | 列大小發生改變的時候或者結束改變的時候產生.你可以使用Veto函數來禁止這種改變.使用wxListEvent::GetColumn獲得關聯的列索引. |
| EVT_LIST_CACHE_HINT(id, func) | 如果你正在實現一個續列表控件,你可能想在某一組子項被顯示之前更新其內部數據.這個事件通知你進行這個操作的最合適的時機.使用wxListEvent::GetCacheFrom函數和 wxListEvent::GetCacheTo函數來獲得即將更新的子項的索引范圍. |
wxListItem
你需要使用wxListItem這個類在列表控件中進行插入,設置子項屬性或者獲取子項屬性的操作.
SetMask函數用來指示你希望使用的列表子項屬性,如下表所示:
| wxLIST_MASK_STATE | state屬性有效. |
|:--- |:--- |
| wxLIST_MASK_TEXT | text屬性有效. |
| wxLIST_MASK_IMAGE | image屬性有效. |
| wxLIST_MASK_DATA | data屬性有效. |
| wxLIST_MASK_WIDTH | width屬性有效. |
| wxLIST_MASK_FORMAT | format屬性有效. |
使用SetId函數設置子項基于0的索引值,使用SetColumn函數設置當控件在報告模式時基于0的列索引.
SetState函數則用來設置下表所示的子項狀態:
| wxLIST_STATE_DONTCARE | 不關心子項狀態. |
|:--- |:--- |
| wxLIST_STATE_DROPHILITED | 子項正被高亮顯示以便接受一個拖放中的放置事件(僅適用于Windows). |
| wxLIST_STATE_FOCUSED | 子項正擁有焦點. |
| wxLIST_STATE_SELECTED | 子項正被顯示. |
| wxLIST_STATE_CUT | 子項已被剪切(僅適用于Windows). |
SetStateMask則用來設置當前正在更改的狀態,參數和上表中的值相同.
SetText函數用來設置標簽或者標題文本.SetImage函數用來設置子項的圖片在圖片列表中的索引.
SetData函數則用來設置和子項綁定的長整型客戶區數據.
SetFormat函數用來設置列表模式時的對齊模式,其值為wxLIST_FORMAT_LEFT, wxLIST_FORMAT_RIGHT或wxLIST_FORMAT_CENTRE(或者wxLIST_FORMAT_CENTER), SetColumnWidth函數則可以用來設置列寬.
還有一些其它的可視屬性可以通過下面的這些函數設置:SetAlign, SetBackgroundColour, SetTextColour和SetFont.這些屬性不需要設置掩碼標記.并且所有Set函數都擁有一個對應的Get函數來獲取相應的設置.
下面的代碼用wxListItem來選擇第二個子項,并且設置其文本標簽以及字體顏色.
```
wxListItem item;
item.SetId(1);
item.SetMask(wxLIST_MASK_STATE|wxLIST_MASK_TEXT);
item.SetStateMask(wxLIST_STATE_SELECTED);
item.SetState(wxLIST_STATE_SELECTED);
item.SetTextColour(*wxRED);
item.SetText(wxT("Red thing"));
listCtrl->SetItem(item);
```
你也可以直接通過另外的函數來設置這些屬性.比如SetItemText, SetItemImage, SetItemState, GetItemText, GetItemImage, GetItemState等等,我們馬上就會談到這些函數.
wxListCtrl成員函數
在windows平臺上可以調用Arrange函數在大圖標或者小圖標的方式下進行排列圖標.
AssignImageList給列表控件綁定一個圖標列表,圖形列表的釋放由列表控件負責,SetImageList也可以實現同樣的功能,不過圖片列表的釋放由應用程序自己負責,使用wxIMAGE_LIST_NORMAL或wxIMAGE_LIST_SMALL來指定用于哪種顯示形式,GetImageList則用來獲取對應的圖片列表指針.
InsertItem函數用來在控件的特定位置中插入一個子項.可以傳遞的參數包括幾種形式:直接傳遞已經設置了成員變量的 wxListItem對象.或者一個索引和一個字符串,一個索引和一個圖片索引以及一個索引,一個標簽和一個圖片索引等. InsertColumn函數則用來在報告視圖中插入一列.
ClearAll函數刪除所有的子項以及報告視圖中的列信息,并產生一個所有子項被刪除的事件.DeleteAllItems刪除所有的子項并產生所有的子項被刪除的事件.DeleteItem刪除某一個子項并產生子項被刪除事件.DeleteColumn則用來刪除報告視圖中的某一列.
SetItem函數通過傳遞一個wxListItem變量來設置某個子項的屬性,就象前面例子中的那樣,或者你還可以傳遞一個索引,一個列,一個標簽以及圖片索引參數.GetItem則用來查詢那些經由wxListItem::SetId函數設置的子項索引的信息.
SetItemData函數用來給某個子項綁定一個長整數.在絕大多數的平臺上,都可以將一個指針強制轉換成長整數,以便這里可以設置一個指針,但是某些平臺上,這樣作是不適合的,這時候你可以通過一個哈希映射來將一個長整數和某個對象對應.GetItemData則返回某個子項綁定的長整數.需要注意的是,子項的位置隨著其它子項的插入或者刪除以及排序操作,將會發生改變,因此不適合用來索引一個子項,但是子項綁定的客戶數據是不會隨子項位置的變化而變化的,可以用來唯一標識一個子項.
SetItemImage函數采用子項索引和圖片索引兩個參數給某個子項指定一個圖標.
SetItemState用來設置子項的某個狀態值,必須通過一個掩碼來指定哪個狀態的值將改變,參考前面介紹wxListItem的部分.GetItemState則用來返回某個給定子項的狀態.
SetItemText函數和GetItemText函數用來設置和獲取某個子項的文本標簽.
SetTextColour用來設置所有子項的文本標簽的顏色,SetBackgroundColour則用來設置控件的背景顏色. SetItemTextColour和SetItemBackgroundColour用來設置在報告模式下某個單獨子項的文本前景色和背景色.以上函數都由對應的Get函數.
使用EditLabel函數開始編輯某個子項的標簽,這將會導致一個wxEVT_LIST_BEGIN_LABEL_EDIT事件.你可以通過這個事件的GetEditControl函數獲得對應編輯控件的指針(僅適用于windows).
EnsureVisible將使得指定的子項處于可見區域.ScrollList用來在某個方向上滾動指定的象素(僅適用于 windows),RefreshItem用來刷新某個子項的顯示,RefreshItems則用來刷新一系列子項的顯示,這兩個函數主要用在使用虛列表控件而子項的內部數據已經改變時.GetTopItem用于在列表或者報告視圖中返回第一個可見的子項.
FindItem可以被用來查找指定標簽,客戶區數據或者位置的子項.GetNextItem則用來查找某些指定狀態的子項(比如所有正被選中的子項).HitTest函數用來返回給定位置的子項.GetItemPosition返回大圖標或者小圖標視圖中某個子項的相對于客戶區的起始座標.GetItemRect則返回相對于客戶區的座標以及子項所占的大小.
你可以動態改變列表控件的顯示類型而不需要先釋放再重新創建它:使用SetSingleStyle函數指定一個類型,比如wxLC_REPORT.指定false參數來移除某一個顯示類型.
在報告模式中使用SetColumn函數來設置某列的信息,比如標題或者寬度,參考前面的wxListItem的相關介紹,作為一個簡單的替代版本,SetColumnWidth用來直接設置某個列的寬度.使用GetColumn和GetColumnWidth來獲取對應的設置.而 GetColumnCount則用來獲取當前的列數.
GetItemCount函數用來返回列表控件中子項的數目,GetSelectedItemCount函數則用來返回選中的子項的數目.GetCountPerPage函數在大小圖標方式中返回所有子項的數目,而在列表和報告模式中返回可見區域可以容納的子項的數目.
最后,SortItems函數可以被用來對列表控件中的子項進行排序.這個函數的參數為比較函數wxListCtrlCompare的地址,這個比較函數使用的參數包括兩個子項對應的客戶區數據,另外一個更深入的整數,然會另外一個整數,如果兩個子項比較的結果為相等,則返回0,前一個大于后一個則返回正數,前一個小于后一個則返回負數.當然,為了排序功能更好的工作,你需要給每個子項指定一個長整型的客戶區數據(可以通過 wxListItem::SetData函數).這些客戶區數據被傳遞給比較函數以實現比較.
使用wxListCtrl
下面的代碼創建和顯示了一個報告模式的列表控件,這個列表控件公有三列10個子項,每一行開始的地方都會顯示一個16x16的文件圖標:
```
#include "wx/listctrl.h"
// 報告模式中的圖片
#include "file.xpm"
#include "folder.xpm"
// 創建一個報告模式的列表控件
wxListCtrl* listCtrlReport = new wxListCtrl(
this, wxID_ANY, wxDefaultPosition, wxSize(400, 400),
wxLC_REPORT|wxLC_SINGLE_SEL);
// 綁定一個圖片列表
wxImageList* imageList = new wxImageList(16, 16);
imageList->Add(wxIcon(folder_xpm));
imageList->Add(wxIcon(file_xpm));
listCtrlReport->AssignImageList(imageList, wxIMAGE_LIST_SMALL);
// 插入三列
wxListItem itemCol;
itemCol.SetText(wxT("Column 1"));
itemCol.SetImage(-1);
listCtrlReport->InsertColumn(0, itemCol);
listCtrlReport->SetColumnWidth(0, wxLIST_AUTOSIZE );
itemCol.SetText(wxT("Column 2"));
itemCol.SetAlign(wxLIST_FORMAT_CENTRE);
listCtrlReport->InsertColumn(1, itemCol);
listCtrlReport->SetColumnWidth(1, wxLIST_AUTOSIZE );
itemCol.SetText(wxT("Column 3"));
itemCol.SetAlign(wxLIST_FORMAT_RIGHT);
listCtrlReport->InsertColumn(2, itemCol);
listCtrlReport->SetColumnWidth(2, wxLIST_AUTOSIZE );
// 插入10個子項
for ( int i = 0; i < 10; i++ )
{
int imageIndex = 0;
wxString buf;
// 插入一個子項,字符串用于第1欄,
// 圖片索引為0
buf.Printf(wxT("This is item %d"), i);
listCtrlReport->InsertItem(i, buf, imageIndex);
// 子項可能由于各種原因(比如:排序)改變索引,
// 因此將現在的索引保存為客戶區數據
listCtrlReport->SetItemData(i, i);
// 為第2欄設置一個文本
buf.Printf(wxT("Col 1, item %d"), i);
listCtrlReport->SetItem(i, 1, buf);
// 為第三欄設置一個文本
buf.Printf(wxT("Item %d in column 2"), i);
listCtrlReport->SetItem(i, 2, buf);
}
```
虛列表控件
通常,列表控件自己保存所有子項相關的文本標簽,圖片以及其它可見屬性的信息,對于小量數據來說,這是不成問題的,但是如果你有成千上萬的子項,你可能需要實現一個虛的列表控件. 虛列表控件由應用程序保存子項的數據,你需要重載它的三個虛函數OnGetItemLabel,OnGetItemImage和 OnGetItemAttr,列表控件會在需要的時候調用它們.你必須調用SetItemCount函數來設置當前的子項個數,因為你將不會實際增加任何子項.你還可以處理EVT_LIST_CACHE_HINT事件以便在某一部分子項即將被顯示直接更新相關的內部數據,下面是重載三個函數的一個簡單的例子:
```
wxString MyListCtrl::OnGetItemText(long item, long column) const
{
return wxString::Format(wxT("Column %ld of item %ld"), column, item);
}
int MyListCtrl::OnGetItemImage(long WXUNUSED(item)) const
{
// 全部的子項都返回0號索引的圖片
return 0;
}
wxListItemAttr *MyListCtrl::OnGetItemAttr(long item) const
{
// 這個成員是內部使用用來為每一個子項保存相關屬性信息
return item % 2 ? NULL : (wxListItemAttr *)&m_attr;
}
```
下面演示怎樣創建一個虛列表控件,我們不用增加任何子項,并且故意將它的子項個數設置為一個略顯夸張的值:
```
virtualListCtrl = new MyListCtrl(parent, wxID_ANY,
wxDefaultPosition, wxDefaultSize, wxLC_REPORT|wxLC_VIRTUAL);
virtualListCtrl->SetImageList(imageListSmall, wxIMAGE_LIST_SMALL);
virtualListCtrl->InsertColumn(0, wxT("First Column"));
virtualListCtrl->InsertColumn(1, wxT("Second Column"));
virtualListCtrl->SetColumnWidth(0, 150);
virtualListCtrl->SetColumnWidth(1, 150);
virtualListCtrl->SetItemCount(1000000);
```
當控件內部數據改變時,如果子項總數改變,你需要重新設置其數目,然后調用wxListCtrl::RefreshItem或者wxListCtrl::RefreshItems來刷新子項的顯示.
參考samples/listctrl目錄中的完整的例子.
- 第一章 介紹
- 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 全書小結