在上一個例子中,我們只用到了ListView的Report視圖,也就是詳細視圖。本文我們再把上一篇文 章中所用的例子進行一下擴展,例子源碼可以到俺的資源區下載。
我們為ListView中顯示的數 據加上圖標,並且允許用戶選擇顯示哪種視圖,如大圖標,小圖標,詳細信息等。
因為代碼還 比較長,我也不希望把代碼全部放出來,在寫完本文後,我會將源碼上傳到資源中。當然了,我也不可 能說每一行代碼都解釋一遍,那也不現實,而且,這樣也不好,我不能主觀地去懷疑讀者的領悟能力。
一、准備圖標
既然要用到圖標,為了簡單方便,就用VS的資源編輯器隨便畫幾下就有圖 標了,我們要准備兩個圖標,為什麼呢?第一個圖標是給EXE文件用的,而第二個圖標是用在ListView 中的。因為在生成的.exe文件的圖標是選用我們最先添加到資源中的圖標,為了使.EXE文件的圖標和我 們在ListView中用的圖標不要一樣(這樣不好看),所以我們還是准備兩個圖標好一點。
圖標 中具備兩個尺寸就夠了——16*16和32*32,如果可能盡量用24位圖,這樣你能用更多的顏色。
二、如何切換視圖
改變ListView的視圖,可以使用ListView_SetView宏,發送LVM_SETVIEW消息 也可以,不過使用宏更方便。它的第一個參數指定LV控件的句柄,第二個參數是設置用哪個視圖。
LV_VIEW_DETAILS——詳細視圖。
LV_VIEW_ICON——大圖標列表。
LV_VIEW_LIST ——列表視圖。
LV_VIEW_SMALLICON——小圖標。
LV_VIEW_TILE——平鋪,如果我沒記 錯的話,這個視圖是在XP時引入的。
三、ComboBox控件使用
為了可以讓用戶選擇一個視 圖,自然要提供對應的操作界面,這是一種多選一的方式,用單選按鈕和下拉拉表框都可以,不過,單 選按鈕要占用更多地方而且處理的消息更多,相對麻煩,所以,還是ComboBox好一些。
用 ComboBox_AddString宏就可以向ComboBox中添加項,比如本例。
// 初始化ComboBox,以選擇 視圖 hcbb = GetDlgItem(hDlg, IDC_CBVIEW); ComboBox_AddString(hcbb, L"大圖標"); ComboBox_AddString(hcbb, L"小圖標"); ComboBox_AddString(hcbb, L"列表"); ComboBox_AddString(hcbb, L"詳細");
當用戶操作了ComboBox,它同樣會發送一條 WM_COMMAND消息,而我們之前已經響應過這條消息,看看例子,我們前面有一個“添加”按鈕和一個“ 清除”按鈕,它被點擊後也會發送WM_COMMAND消息。因此,我們要做更詳細的處理。
還記得吧 ,WM_COMMAND的wParam參數的低字節位表示發送該消息的控件的ID,高字節位表示“通知碼”。lParam 是控件的句柄。我們判斷ID知道用戶操作的是ComboBox控件還不夠,因為我不知道用戶對這個控件做了 哪些操作,是彈出下拉列表?還是收起下拉列表?或者選擇了另一個項?
而我們這裡要做的是 ,看用戶選擇了哪個視圖,我們的ListView控件就顯示哪種視圖,顯然,在通知碼中,我們是對 CBN_SELCHANGE感興趣,因為選擇的索引值一旦改變,就會收到這個通知碼。
case IDC_CBVIEW: if (HIWORD(wParam) == CBN_SELCHANGE) { // 當前選擇項的索引 int index = SendMessage((HWND)lParam, CB_GETCURSEL, 0, 0); // 根據選擇設置視圖 DWORD lvView; switch (index) { case 0: lvView = LV_VIEW_ICON; break; case 1: lvView = LV_VIEW_SMALLICON; break; case 2: lvView = LV_VIEW_LIST; break; case 3: lvView = LV_VIEW_DETAILS; break; default: lvView = LV_VIEW_DETAILS; break; } ListView_SetView(GetDlgItem(hDlg, IDC_LV), lvView); } break; }
發送CB_GETCURSEL消息,可以得到ComboBox中當前選定項的索引值。
四、向 ListView添加圖標
先用ImageList_Create創建圖像列表,然後用ImageList_AddIcon宏向列表中 添加圖標。因為我們要用大圖標和小圖標,所以要創建兩個圖像列表,一個放置大圖標,另一種放置小 圖標,因為同一個Image List中放置的所有圖像的尺寸必須相同。
// 初始化ImageList hImgListSm = ImageList_Create(GetSystemMetrics(SM_CXSMICON),GetSystemMetrics (SM_CYSMICON),ILC_MASK,1,0); hImgListLg = ImageList_Create(GetSystemMetrics(SM_CXICON),GetSystemMetrics (SM_CYICON),ILC_MASK,1,0); hicon = LoadIcon(hgAppInst,MAKEINTRESOURCE(IDI_ITE)); // 添加圖標 ImageList_AddIcon(hImgListSm, hicon); ImageList_AddIcon(hImgListLg, hicon); DestroyIcon(hicon);
接著,用ListView_SetImageList把Image List和ListView關聯起來。
// 將ListView與ImageList關聯 ListView_SetImageList(hListview, hImgListLg, LVSIL_NORMAL); ListView_SetImageList(hListview, hImgListSm, LVSIL_SMALL);
在向ListView添加項時, 設置LVITEM結構體的iImage字段為圖像列表中對應圖像的索引,因為我們只添加了一個圖標,所以,索 引是0.
LVITEM vitem; vitem.mask = LVIF_TEXT | LVIF_IMAGE; vitem.iImage = 0;
ImageList_Create返回的是一個句柄,它也是一種資源,所以,在不需要 它了,就得記得把它銷毀。在我們的對話框發生WM_DESTROY的同時將其銷毀。
case WM_SYSCOMMAND: if (wParam == SC_CLOSE) { // 銷毀ImageList ImageList_Destroy(hImgListLg); ImageList_Destroy(hImgListSm); DestroyWindow(hListview);//不再需要 DestroyWindow(hDlg); } return 0;
另外,補充一個小知識,要得到對話框中某個控件的句柄,可以調用 GetDlgItem函數,這也是我們為什麼要為控件設置ID值的原因。
程序運行後,就可以通過選擇 下拉列表來動態改變ListView的視圖了。
好了,要過年了,這是新年前最後一篇博文,過完年後,我們繼續。我也希望,後 續能與大家一起分享更多的知識和編程技巧。