1. 程式人生 > >[Win32SDK基本]ListView Controls(1)Report (details) View 詳解

[Win32SDK基本]ListView Controls(1)Report (details) View 詳解

其實還是子視窗,static那節說的很明白了,就不重複了 ,這個控制元件的類名是SysListView32

需要包含CommCtrl.h標頭檔案和連結comctl32.lib

listview是非常實用的控制元件,先看幾張來自MSDN的圖,飽飽眼福:

分類:listview分好幾類,今天說說Report (details) View報表列表控制元件

報表列表控制元件的風格是:LVS_REPORT

一。listview常用風格(其實很多,這裡只說最常用的,其他的看MSDN)

1。LVS_SINGLESEL
只能同時選擇一項。預設情況下,可以選擇多個項。

2。LVS_NOSORTHEADER
列標題按鈕不工作。即如果單擊在報表頭中的列標題不進行操作。

3。LVS_SHOWSELALWAYS
如果有的話,總是顯示所選內容,即使該控制元件沒有焦點。

二。listview常用擴充套件風格(其實很多,這裡只說最常用的,其他的看MSDN)

1。LVS_EX_FULLROWSELECT
當選定一項,則該專案及其所有子項全部突出顯示(就是說選中時高亮一行)。這種風格是僅在 LVS_REPORT 樣式中可用。

2。LVS_EX_SUBITEMIMAGES
允許子項顯示影象。這種風格是僅在 LVS_REPORT 樣式中可用。

3。LVS_EX_GRIDLINES
顯示網格線。這種風格是僅在 LVS_REPORT 樣式中可用。

使用擴充套件風格,必須用LVM_SETEXTENDEDLISTVIEWSTYLE 訊息新增擴充套件風格,直接在CreateWindowEx裡面新增是無效的。
或者用ListView_SetExtendedListViewStyle函式
引數1:控制代碼
引數2:擴充套件風格

三。控制訊息:

1。LVM_INSERTCOLUMN 插入新列
wParam:新列的索引
lParam:指向包含新列的屬性的 LVCOLUMN 結構的指標。
返回值:成功返回新列的索引,失敗返回-1

LVCOLUMN 結構:

typedef struct _LVCOLUMN {
  UINT   mask;
  int    fmt;
  int    cx;
  LPTSTR pszText;
  int    cchTextMax;
  int    iSubItem;
#if (_WIN32_IE >= 0x0300)
  int    iImage;
  int    iOrder;
#endif 
#if (_WIN32_WINNT >= 0x0600)
  int    cxMin;
  int    cxDefault;
  int    cxIdeal;
#endif 
} LVCOLUMN, *LPLVCOLUMN;

mask:
LVCF_FMT:Fmt 成員是有效的。
LVCF_WIDTH:Cx 成員是有效的。
LVCF_TEXT:PszText 成員是有效的。
LVCF_SUBITEM:ISubItem 成員是有效的。
LVCF_IMAGE:4.70 版本。iImage成員是有效的。
LVCF_ORDER:4.70 版本。iOrder的成員是有效的。
LVCF_MINWIDTH:版本 6.00 和 Windows Vista.The cxMin 成員是有效。
LVCF_DEFAULTWIDTH:版本 6.00 和 Windows Vista.The cxDefault 成員是有效。
LVCF_IDEALWIDTH:版本 6.00 和 Windows Vista.The cxIdeal 成員是有效。

fmt:列標題和列中的子項文字的對齊方式。
此成員可以是下列值的組合。請注意,並非所有組合都都有效。
LVCFMT_LEFT:文字是左對齊的。
LVCFMT_RIGHT:文字為右對齊。
LVCFMT_CENTER:文字居中。
LVCFMT_JUSTIFYMASK:用於選擇控制領域的理由的那些 fmt 的位掩碼。若要檢查某一列的格式,請使用邏輯","LCFMT_JUSTIFYMASK 結合裂變材料條約。然後可以使用 switch 語句來確定是否已設定 LVCFMT_LEFT,LVCFMT_RIGHT 或 LVCFMT_CENTER 位。
LVCFMT_IMAGE:4.70 版本。該項顯示的影象列表中的影象。
LVCFMT_BITMAP_ON_RIGHT:4.70 版本。該點陣圖顯示在右側的文字。這並不影響影象列表中的影象分配到的標頭項。
LVCFMT_COL_HAS_IMAGES:4.70 版本。標頭項包含影象列表中的影象。
LVCFMT_FIXED_WIDTH:版本 6.00 和 Windows Vista。不能調整大小的列;就像 HDF_FIXEDWIDTH 一樣。
LVCFMT_NO_DPI_SCALE:版本 6.00 和 Windows Vista。如果不設定,CCM_DPISCALE 將治理加大固定寬度。
LVCFMT_FIXED_RATIO:版本 6.00 和 Windows Vista。與行的高度,寬度會增加。
LVCFMT_SPLITBUTTON:版本 6.00 和 Windows Vista。列是一個拆分按鈕 (與 HDF_SPLITBUTTON 相同)。列的標題顯示拆分按鈕 (與 HDF_SPLITBUTTON 相同)。

cx:列的寬度,以畫素為單位。

pszText:如果設定的列資訊,則此成員是字串的一個 null 終止的字串指標。如果結構接收有關列的資訊,該成員指定的接收列標頭文字的緩衝區的地址。

cchTextMax:在 TCHARs 的 pszText 成員所指向的緩衝區的大小。如果結構不接收有關列的資訊,此成員將被忽略。
iSubItem:與該列關聯的子項的索引。iImage:4.70 版本。影象在影象列表內的從零開始的索引。指定的影象將出現在列。
iOrder:4.70 版本。零開始的列偏移量。列偏移是左到右的順序。例如,0 表示最左邊的列。cxMin:Windows Vista。以畫素為單位的列的最小寬度。
cxDefault:Windows Vista。應用程式定義的值,通常用來儲存列的預設寬度。通過該列表檢視控制元件,此成員將被忽略。
cxIdeal:Windows Vista。只讀。以畫素為單位,作為列的列的理想寬度目前可能指示到較小的寬度。

2。LVM_INSERTITEM 在列表檢視控制元件中插入一個新的專案
wParam:必須為0
lParam:指標,指向 LVITEM 結構,它指定列表檢視項的屬性。使用代理權成員指定的從零開始的索引,應在其中插入新的專案。如果此值大於 listview 中當前包含的項數,新專案將追加到列表的末尾,並分配正確的索引。檢查訊息的返回值來確定分配給物料的實際索引。
返回值:成功返回新專案的索引,失敗返回-1

LVITEM 結構:

typedef struct {
  UINT   mask;
  int    iItem;
  int    iSubItem;
  UINT   state;
  UINT   stateMask;
  LPTSTR pszText;
  int    cchTextMax;
  int    iImage;
  LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
  int    iIndent;
#endif 
#if (_WIN32_WINNT >= 0x0501)
  int    iGroupId;
  UINT   cColumns;
  PUINT  puColumns;
#endif 
#if (_WIN32_WINNT >= 0x0600)
  int    *piColFmt;
  int    iGroup;
#endif 
} LVITEM, *LPLVITEM;

mask:
LVIF_COLFMT:Windows Vista 及更高版本。PiColFmt 成員是有效的或者必須設定。如果使用此標誌,則分欄成員是有效的或必須設定。
LVIF_COLUMNS:分欄成員是有效的或者必須設定。
LVIF_DI_SETITEM:作業系統應該儲存請求的列表專案資訊並沒有再問了。此標誌僅用於 LVN_GETDISPINFO 通知程式碼。
LVIF_GROUPID:IGroupId 成員是有效的或者必須設定。如果未設定此標誌,當傳送 LVM_INSERTITEM 訊息,iGroupId 的值被假定為 I_GROUPIDCALLBACK。
LVIF_IMAGE:iImage成員是有效的或者必須設定。
LVIF_INDENT:IIndent 成員是有效的或者必須設定。
LVIF_NORECOMPUTE:該控制元件將不生成 LVN_GETDISPINFO 來檢索文字資訊,如果它收到一條 LVM_GETITEM 訊息。相反,pszText 成員將包含 LPSTR_TEXTCALLBACK。
LVIF_PARAM:LParam 成員是有效的或者必須設定。
LVIF_STATE:state成員是有效的或必須設定。
LVIF_TEXT:PszText 成員是有效的或者必須設定。

iItem:此結構引用的項的從零開始的索引。

iSubItem:一開始的索引,這種結構所指,該子項或零如果這種結構是指一個專案,而不是一個子項。

state:指示項的狀態、 狀態影象和覆蓋影象。StateMask 成員指示此成員的有效位。位 0 到 7 的此成員包含專案狀態標誌。這可以是一個或多個專案狀態的值。通過此成員 11 8 位指定一個基於疊加影象索引。全尺寸的圖示影象列表和小圖示影象列表可以有覆蓋影象。覆蓋影象疊加到此項的圖示影象。如果這些位均為零,該專案已經沒有覆蓋影象。若要隔離這些位,請使用 LVIS_OVERLAYMASK 掩碼。若要在此成員設定覆蓋影象索引,您應該使用 INDEXTOOVERLAYMASK 巨集。用 ImageList_SetOverlayImage 函式設定影象列表覆蓋影象。
通過此成員 15 12 位指定狀態影象索引。狀態影象顯示在專案的圖示來指示應用程式定義的狀態旁邊。如果這些位均為零,該專案已經沒有國家形象。若要隔離這些位,請使用 LVIS_STATEIMAGEMASK 掩碼。若要設定狀態影象索引,請使用 INDEXTOSTATEIMAGEMASK 巨集。狀態影象索引應繪製狀態影象列表中指定的影象的索引。與 LVM_SETIMAGELIST 訊息指定狀態影象列表。

stateMask:該值指定哪些位國家成員將檢索或修改。例如,將此成員設定為 LVIS_SELECTED 將導致只狀態的專案的選擇要檢索。
此成員允許您修改一個或多個項狀態而無需首先檢索所有項的狀態。例如,將此成員設定為 LVIS_SELECTED 和狀態為零將導致專案的選擇狀態被清除,但沒有一個其他國家會受影響。
若要檢索或修改的所有國家,請設定此成員到 (UINT)-1。
您可以使用巨集 ListView_SetItemState 來設定,清除位。

pszText:如果結構指定專案屬性,pszText 是一個指向以 null 結尾的字串的指標。當響應 LVN_GETDISPINFO 通知,是確保此指標保持有效直到後下通知已收到。
如果結構接收物料屬性,pszText 是指向接收專案的文字緩衝區的指標。請注意,雖然該列表檢視控制元件允許任何長度字串儲存為專案文字,只有首先 260 TCHARs 顯示。

如果 pszText 的值為 LPSTR_TEXTCALLBACK,該專案是一個回撥項。如果回撥文字發生更改,您必須顯式將 pszText 設定為 LPSTR_TEXTCALLBACK 並通過傳送 LVM_SETITEM 或 LVM_SETITEMTEXT 的訊息通知列表檢視控制元件的更改。
不要設定 pszText LPSTR_TEXTCALLBACK 如果列表檢視控制元件具有的 LVS_SORTASCENDING 或 LVS_SORTDESCENDING 的風格。

cchTextMax:TCHARs 中 pszText,包括終止 NULL 所指向的緩衝區數。
當結構接收專案屬性時,只使用此成員。當結構指定專案屬性時,它將被忽略。例如,cchTextMax 在 LVM_SETITEM 和 LVM_INSERTITEM 的過程中將被忽略。它在只讀 LVN_GETDISPINFO 和其他 LVN_ 通知。永遠不會注意複製超過 cchTextMax TCHARs — — 凡 cchTextMax 包括終止 NULL — — 成 pszText LVN_ 通知期間,否則您的程式可能會失敗。

iImage:該專案的圖示控制元件的影象列表中的索引。這適用於大型和小型的影象列表中。如果此成員是 I_IMAGECALLBACK 值,父視窗是負責儲存索引。在這種情況下,列表檢視控制元件傳送父 LVN_GETDISPINFO 通知程式碼,需要時,它顯示的影象檢索的索引。

lParam:特定於專案的價值。如果你使用 LVM_SORTITEMS 訊息,列表檢視控制元件將此值傳遞到應用程式定義的比較函式。您還可以使用 LVM_FINDITEM 訊息來搜尋具有指定需要 lParam 的值的項的列表檢視控制元件。

iIndent:4.70 版本。以影象寬度計算,要縮排的專案數。一個單一的壓痕等於專案影象的寬度。因此,值 1 通過一個影象,由兩個影象,等等值 2 縮排的寬度縮排的專案。請注意,此欄位僅為專案支援。嘗試設定子項縮排會導致呼叫函式失敗。

iGroupId:版本 6.0 識別符號的組,該專案屬於,或為下列值之一。
I_GROUPIDCALLBACK:Listview 控制元件傳送父 LVN_GETDISPINFO 通知程式碼以檢索組的索引。
I_GROUPIDNONE:該專案不屬於組。

cColumns:版本 6.0 的資料列 (子項) 為此項平鋪檢視中顯示的數目。最大值為 20。如果此值為 I_COLUMNSCALLBACK,列陣列和陣列本身 (puColumns) 的大小被通過傳送一個 LVN_GETDISPINFO 通知。

puColumns:版本 6.0 為這一專案和這些列的順序顯示指定的列的列索引陣列的指標。

piColFmt:Windows Vista: 不執行。Windows 7 和以後: 指向陣列的以下標誌 (單獨或組合),指定在每個子項的格式擴充套件平鋪檢視。
LVCFMT_LINE_BREAK:部隊要換到頂部的下一列的列表中的列。
LVCFMT_FILL:填充圖塊區域的其餘部分。可能有一個標題。
LVCFMT_WRAP:允許在其列表中的列的剩餘空間內換行的列。
LVCFMT_NO_TITLE:從子項中刪除標題。
LVCFMT_TILE_PLACEMENTMASK:相當於 LVCFMT_LINE_BREAK 和 LVCFMT_FILL 的組合。

iGroup:Windows Vista: 組的項的索引。僅對所有者資料/回撥 (多個組中的單個項) 有效。

3.LVM_SETITEM 設定設定子項的文字。
wParam:必須為0
lParam:指向包含新的專案屬性的 LVITEM 結構的指標。如果掩碼成員指定的 LVIF_TEXT 值,pszText 成員是以 null 結尾的字串的地址,cchTextMax 成員將被忽略。
返回值:成功TRUE,失敗FALSE

4。LVM_DELETEITEM 移除一項
wParam:要刪除項的序號
lParam:必須為0
返回值:成功TRUE,失敗FALSE

5。LVM_DELETECOLUMN 移除列
wParam:要刪除列的序號
lParam:必須為0
返回值:成功TRUE,失敗FALSE

6。LVM_GETITEMCOUNT 獲取專案數
wParam:必須為0
lParam:必須為0
返回值:返回專案的數量

7。LVM_GETITEM 獲取指定項
wParam:必須為0
lParam:指向 LVITEM 結構的指標
返回值:成功返回TRUE,失敗返回FALSE

注:關於獲取指定項文字:
在 LVITEM 結構中的掩碼成員設定 LVIF_TEXT 標誌,iItem和iSubItem指定專案序號和子項。pszText 成員必須指向一個有效的緩衝區;cchTextMax 成員必須設定為該緩衝區中的字元數。應用程式不應假設文字一定將放置在指定的緩衝區。結果是可能改變結構中的 pszText 成員,以指向新的文字,而不是將它放在緩衝區中。

8。LVM_GETCOLUMN 獲取指定列
wParam:列的序號
lParam:指向 LVCOLUMN 結構的指標
返回值:成功返回TRUE,失敗返回FALSE

9。LVM_GETHOTITEM 獲取當前選中項
wParam:必須為0
lParam:必須為0
返回值:返回選中項的序號

10。顏色:
文字顏色:獲取:LVM_GETTEXTCOLOR 設定:LVM_SETTEXTCOLOR 
文字背景色:獲取:LVM_GETTEXTBKCOLOR 設定:LVM_SETTEXTBKCOLOR 
背景色:獲取:LVM_GETBKCOLOR 設定:LVM_SETBKCOLOR 
獲取顏色的三個訊息 wParam和 lParam 都必須為0,返回值都是顏色
設定顏色的三個訊息 wParam 都必須為0,為顏色(RGB顏色),其中設定背景顏色的那兩個訊息顏色可以為 CLR_NONE,表示沒有顏色。

四。通知訊息:

1。NM_CLICK 專案被單擊
通過 WM_NOTIFY 傳送給父視窗
wParam:控制元件識別符號
lParam:指向 NMHDR 結構的指標,從4.71版本開始,是指向NMITEMACTIVATE 結構的指標
返回值:不使用

typedef struct tagNMITEMACTIVATE {
  NMHDR  hdr;
  int    iItem;
  int    iSubItem;
  UINT   uNewState;
  UINT   uOldState;
  UINT   uChanged;
  POINT  ptAction;
  LPARAM lParam;
  UINT   uKeyFlags;
} NMITEMACTIVATE, *LPNMITEMACTIVATE;

hdr:指向 NMHDR 結構的指標
iItem:專案的序號,如果沒有使用則為-1

typedef struct tagNMHDR {
  HWND     hwndFrom;
  UINT_PTR idFrom;
  UINT     code;
} NMHDR;
hwndFrom:控制元件控制代碼
idFrom:控制元件id
code:通知碼

2。NM_DBLCLK 專案被雙擊
同上

3。NM_RCLICK 專案被右擊
wParam和 lParam同上
返回值:非0表示不允許預設處理,0表示允許.

五。圖片列表:
ImageList_Create 建立一個圖片列表

HIMAGELIST ImageList_Create(
   int  cx,
   int  cy,
   UINT flags,
   int  cInitial,
   int  cGrow
);
cx:寬度
cy:高度
flags:置ILC_MASK
cInitial:影象列表最初包含的映像數目。
cGrow:影象的影象列表可以增長時,系統需要騰出新的影象數。此引數表示新的影象調整大小後的影象列表可以包含的數。

ImageList_Add新增點陣圖
ImageList_AddIcon新增圖示

ListView_SetImageList為listview設定圖片列表

程式碼: 全域性變數
HWND listview1;
LVCOLUMN list1;
LVITEM item1;
HIMAGELIST imglist1;
程式碼:
LRESULT CALLBACK WndProc2(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg){
	case WM_CREATE:

		//建立listview
		listview1 = CreateWindowEx(WS_EX_STATICEDGE, TEXT("SysListView32"), NULL, WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SINGLESEL, 10, 10, 400, 400, hwnd, (HMENU)1, (HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), NULL);
		ListView_SetExtendedListViewStyle(listview1, LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES);//設定listview擴充套件風格
		SendMessage(listview1, WM_SETFONT, (WPARAM)GetStockObject(17), 0);

		//SetWindowTheme(listview1, L"Explorer", NULL);

		//建立圖片列表
		imglist1 = ImageList_Create(20, 20, ILC_MASK, 1, 1);
		ImageList_AddIcon(imglist1, LoadIcon((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), TEXT("ICON_2")));
		ImageList_AddIcon(imglist1, LoadIcon((HINSTANCE)GetWindowLong(hwnd, GWL_HINSTANCE), TEXT("ICON_1")));
		ListView_SetImageList(listview1, imglist1, LVSIL_SMALL);

		//記憶體清零
		RtlZeroMemory(&list1, sizeof(LVCOLUMN));
		RtlZeroMemory(&item1, sizeof(LVITEM));

		//建立列
		list1.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT;//掩碼
		list1.fmt = LVCFMT_LEFT;//左對齊
		list1.cx = 100;//列寬
		list1.pszText = TEXT("醉時空歡");
		SendMessage(listview1, LVM_INSERTCOLUMN, 0, (LPARAM)&list1);//建立列
		list1.pszText = TEXT("Win32");
		list1.cx = 200;
		SendMessage(listview1, LVM_INSERTCOLUMN, 1, (LPARAM)&list1);
		list1.pszText = TEXT("MSDN");
		SendMessage(listview1, LVM_INSERTCOLUMN, 2, (LPARAM)&list1);
		list1.pszText = TEXT("happy");
		SendMessage(listview1, LVM_INSERTCOLUMN, 3, (LPARAM)&list1);

		//建立專案
		item1.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_INDENT;
		item1.pszText = TEXT("專案");
		item1.iItem = 0;//專案號
		item1.iImage = 0;//圖片號
		item1.iIndent = 0;
		SendMessage(listview1, LVM_INSERTITEM, 0, (LPARAM)&item1);
		item1.iItem = 1;
		item1.iImage = 0;
		SendMessage(listview1, LVM_INSERTITEM, 0, (LPARAM)&item1);
		item1.pszText = TEXT("3");
		item1.iItem = 2;
		item1.iImage = 1;
		item1.iIndent = 1;//縮排一個影象單位
		SendMessage(listview1, LVM_INSERTITEM, 0, (LPARAM)&item1);

		//建立子項
		item1.mask = LVIF_TEXT | LVIF_IMAGE;
		item1.iItem = 1;
		item1.iSubItem = 1;
		item1.iImage = -1;
		item1.pszText = TEXT("子項");
		SendMessage(listview1, LVM_SETITEM, 0, (LPARAM)&item1);
		item1.iItem = 1;
		item1.iSubItem = 2;
		item1.pszText = TEXT("子項");
		SendMessage(listview1, LVM_SETITEM, 0, (LPARAM)&item1);
		item1.iItem = 1;
		item1.iSubItem = 3;
		item1.pszText = TEXT("子項");
		SendMessage(listview1, LVM_SETITEM, 0, (LPARAM)&item1);


		break;
	case WM_NOTIFY:
		switch (wParam){
		case 1://ID為listview的ID
			LPNMITEMACTIVATE now;
			now = (LPNMITEMACTIVATE)lParam;//得到NMITEMACTIVATE結構指標
			char a[50];
			_itoa(now->iItem, a, 10);//now->iItem專案序號
			switch (now->hdr.code){//判斷通知碼
			case NM_CLICK:
				//MessageBoxA(hwnd, a, "單擊", 0);
				break;
			case NM_DBLCLK:
				//MessageBoxA(hwnd, a, "雙擊", 0);
				break;
			case NM_RCLICK:
				//MessageBoxA(hwnd, a, "右擊", 0);
				break;
			}
			break;
		}
		break;
	case WM_DESTROY:
		ImageList_Destroy(imglist1);//銷燬圖片列表
		PostQuitMessage(0);
		return 0;
	}
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

效果圖:

選中一項時:

將上面程式碼中的SetWindowTheme(listview1, L"Explorer", NULL);取消註釋之後再執行:

有個虛線礙眼,挺難看的,其實這個問題困擾了我好長時間,MSDN和百度上也沒有找到解決方法,用ControlSpy和Spy++倒騰了半天也沒有結果,但經過我的不懈努力,終於研究出來了兩個方法:

方法1.使用對話方塊,在對話方塊裡建立的listview就沒有虛線框

方法2.在NM_CLICK通知裡面使listview失去焦點,在NM_CLICK裡面加入:

SendMessage(now->hdr.hwndFrom, WM_KILLFOCUS, 0, 0);

不過這種方法可能會有一些隱患,目前尚不明確,不能加上LVS_SHOWSELALWAYS風格。

效果: