?? 031.txt
字號:
第三十一課 列表視圖控件
--------------------------------------------------------------------------------
本課中我們將學習如何創建和使用列表視圖控件。
理論:
列表視圖控件和樹型視圖、豐富文本編輯控件一樣是通用控件的一種。可能您都已經知道了列表視圖控件,只不過是不知道它的確切名字而已。列表視圖控件可以用來很好地顯示項目。在這方面它和列表框相同,只不過它的性能更強。
有兩種方法創建一個列表視圖控件。第一種也是最簡單的方法是:用資源編輯器來創建它。用該種方法只是不要忘記在您的代碼(的任何位置處)加入對InitCommonControls函數的調用(記得嗎,調用該函數只是為了隱式地加載包含通用控件的DLL)。另一種方法是調用CreateWindowEx函數,這里您必須指定合適的類名,譬如:SysListView32,WC_LISTVIEW不是正確的類名
在列表視圖種有四種方法來顯示數據:大圖標,小圖標,列表和報告方式。這些方法和在資源管理器種選擇View->Large Icons,Small Icons , List 和 Details 相對應。各種不同的顯示方式只是顯示了不同的外觀而已。譬如,您可能有許多的數據,只是并不想全部顯示。報告方式提供的消息最完全,其它的方式則要少得多。在剛創建一個列表視圖時您可以選擇一種初始顯示方法,隨后您可以調用SetWinodwLong函數并設置GWL_STYLE標志位來改變顯示方式
既然我們已經知道了如何創建列表控件,接下來我們學習如何使用它們。我們將主要集中在報告方式的顯示上,因為該種方式演示了最多的列表控制的特性。使用列表控制的步驟如下:
調用CreateWindowEx函數來創建一個列表控件,指定它的類名為SysListView32。您還可以在此處指定控件初次顯示時的方式。
創建和初始化用在列表控件中顯示項目的圖象列表(如果存在)。
向列表控件中插入列,如果顯示的方式是報告方式這一步是必須的。
向控件中插入項目和自項目。
列:
在報告方式中,有不止一個列。您可以把放入到列表控件中的數據看作是一張表單:這時數據是按行列排列的。在控件中至少有一列。在其它的顯示方式中則無所謂,因為這些顯示方式有僅有一列。
加入列要通過向列表控件發送LVM_INSERTCOLUMN消息來實現。
LVM_INSERTCOLUMN
wParam = iCol
lParam =指向LV_COLUMN型結構體變量的指針
iCol 列數,從0開始編號。
LV_COLUMN 包含了將插入的列的信息。它的定義如下:
LV_COLUMN STRUCT
imask dd ?
fmt dd ?
lx dd ?
pszText dd ?
cchTextMax dd ?
iSubItem dd ?
iImage dd ?
iOrder dd ?
LV_COLUMN ENDS
Field name Meanings
imask 一組標志位,它指示了該結構體中的那些成員變量是有效的。該結構體中的成員變量并不是同時有效的。在某些時候,可能只有某些成員變量是有效的。結構體可以用來輸入和輸出。這樣讓WINDOWS知道那些成員變量是有效的是非常重要的。可能的標志有:
LVCF_FMT = fmt有效
LVCF_SUBITEM = iSubItem有效
LVCF_TEXT = pszText有效.
LVCF_WIDTH = lx有效
您可以一次使用幾個標志。譬如,如果您向指定列的文本標簽(列名),您必須在pszText成員變量中提供列名,然后指定標志LVCF_TEXT告訴WINDOWS成員變量pszText中的值是有效的,否則WINDOWS將忽略掉pszText中的值。
fmt 指定了項目/子項目的對齊方式。可能的值有:
LVCFMT_CENTER = 文本居中
LVCFMT_LEFT = 文本左對齊
LVCFMT_RIGHT = 文本右對齊
lx lx 是列的寬度(以像素點為單位)。以后您可以發送消息LVM_SETCOLUMNWIDTH來改變列的寬度。
pszText 如果用來設定列的屬性時,該成員變量為指向列名的指針。如果是查詢列名,該成員變量指向一個足夠大的緩沖區,用來接收返回的列名,這是您必須在成員cchTextMax中指定緩沖區的大小。如果是設定列名時,可以忽略該變量,因為該指針指向的是一個ASCII碼的字符串,而WINDOWS可以解析出ASCII串的長度。
cchTextMax cchTextMax 以字節計的上面一個成員變量指向的緩沖區的小。該成員變量只在您查詢列的屬性時使用。如果是設定列的屬性,那該變量將被忽略。
iSubItem 指定和該列相連的子項目的索引號。該成員變量的值用來標識和列相連系的子項目。該列的使用最好地說明了如何把列號和子項目相連。要查詢列的屬性時可以發送LVM_GETCOLUMN消息,并在成員變量imask中指定LVCF_SUBITEM標志,列表控件將在iSubItem中返回插入時設定的iSubItem值。為了使用該辦法,您需要在該成員變量中放入正確的值。
iImage and iOrder 為了和IE3.0以上版本兼容。目前我沒有這方面的資料。
在列表視圖控件創建后,您必須至少向其中插入一列。當然如果不打算使用報告方式顯示,那倒是沒有必要插入列。為了插入列,您需要定義一個LV_COLUMN型的結構體變量,給其成員變量賦上正確的值,指定列號,然后向列表視圖控件發送LVM_INSERTCOLUMN消息并把該結構體變量的值傳過去。
LOCAL lvc:LV_COLUMN
mov lvc.imask,LVCF_TEXT+LVCF_WIDTH
mov lvc.pszText,offset Heading1
mov lvc.lx,150
invoke SendMessage,hList, LVM_INSERTCOLUMN,0,addr lvc
上面的代碼段顯示了該過程。當發送LVM_INSERTCOLUMN消息時,他指定了列的標題條文本和它的寬度。
項目和子項目
項目是列表視圖中主要的內容。除報告方式顯示的外,在列表視圖您只能看到項目。子項目是項目的詳細信息。一個項目可能有不止一個相關的子項目。舉個例子,譬如項目是文件名,那其相關的子項目可能有文件屬性、大小、創建日期等。在報告方式的視圖中,最左邊一列是項目,其它列是子項目。從數據庫記錄的角度看,項目類似主鍵,子項目類似記錄。
至少您的列表視圖需要一些項目:子項目是可選的。如果您想要給用戶提供更多的信息,可以把子項目和項目相連,然后放到列表視圖中以報告的方式顯示。
您可以通過向列表視圖發送LVM_INSERTITEM消息來向其中添加項目,這時還需要把一個指向LV_ITEM型的結構體的變量的指針放到lParam一同傳給列表視圖。LV_ITEM的定義如下:
LV_ITEM STRUCT
imask dd ?
iItem dd ?
iSubItem dd ?
state dd ?
stateMask dd ?
pszText dd ?
cchTextMax dd ?
iImage dd ?
lParam dd ?
iIndent dd ?
LV_ITEM ENDS
Field name Meanings
imask 一組標志位標明該結構體中那些成員變量中的值有效。它的意義和上面我們提到的LV_COLUMN型結構體中向對應的成員變量基本相同。更詳細的信息,可以查詢WIN32 API 手冊。
iItem 該結構體代表的項目的索引號。索引號是從0開始編號的。該值和表單的“行”類似。
iSubItem 和上一個成員變量指定的項目相連的子項目的索引號。您可以把它當作表單的“列”。譬如您想要把一個項目插入到新創建的列表視圖控件,iItem的值應為0(因為該項目是第一個項目),iSubItem的值也應當為0(我們想把該項目插到第一列)。如果你想指定一個子項目和該項目相連,iItem中應該是您想要相連的項目的索引號,iSubItem的值應當是大于0的值,具體的值取決于您想把該子項目插在那一列。如果你的列表視圖控件一共有4列的化,第一列包含了項目,其余3列是留給子項目的。如果您想把子項目插在第四列,應當指定該值為3。
state 該成員變量包含的標志位反應了項目的狀態。狀態的改變可能是由用戶的操作引起的或是程序改變的。這些狀態包括:是否有焦點/高亮度顯示/被選中(由于被剪切)/被選中等。另外還包括,以1為基數的索引用來代表是否處使用重疊/狀態圖標。
stateMask 由于上面的成員變量包含狀態標志位、重疊的位圖索引號、和狀態位圖的索引號,我們需要告訴WINDOWS我們到底需要設定或查詢那一個值。該成員變量就是用來做這項工作的。
pszText 當我們想設定項目的屬性時,它包含項目名稱的ASCII碼的字符串的地址。當查詢項目的屬性時,該成員變量將用來接收查詢返回的項目的名稱。
cchTextMax 僅當您用來查詢項目的屬性時才需要使用該值,這時它包含上一個成員變量的大小。
iImage 圖標在列表視圖中的圖象鏈表中的索引號。
lParam 用戶定義的值,當您給項目排序時使用。當您告訴列表視圖對項目排序時,列表視圖將成對地比較項目。 它將會把兩個項目的lParam的值傳給您,這樣您就可以進行比較先列出那一個了。如果您現在還不太明白的話,沒有系,我們稍后還要講關于排序的問題。
現在讓我們來總結想列表控件中插入項目/子項目的步驟:
定義一個LV_ITEM型的結構體變量。
給該變量賦給合適的值
如果要插入一個項目,就向列表視圖控件發送LVM_INSERTITEM值。 如果要插入一個子項目,發送LVM_SETITEM。如果您不明白項目和子項目之間的關系的話,可能會有一些疑惑。子項目僅是項目的屬性而已,也就是說您可以插入一個項目但是不能插入一個子項目。所以添加一個子項目十只能發送LVM_SETITEM消息而不能發送LVM_INSERTITEM消息。
列表視圖控件的消息/通知
既然您知道了如何創建和往其中添加內容,下一步就是如何和它通訊。列表視圖控件和它的父窗口之間的通訊是通過消息/通知來進行的。父窗口通過發送消息來控制列表視圖控件,列表視圖控件通過發送WM_NOTIFY消息來通知它的父窗口。這一點和其它的通用控件沒有什么不同。
排序項目/子項目
您可以在調用CreateWindowEx函數時指定LVS_SORTASCENDING 或 LVS_SORTDESCENDING風格來指定缺省的排序方式。這兩種風格僅僅排序項目的名稱。如果想要排序項目的其它屬性,您可以通過發送LVM_SORTITEMS消息來完成
LVM_SORTITEMS
wParam = lParamSort
lParam = pCompareFunction
lParamSort 用戶定義的值,該值將傳遞給用來比較的函數。
pCompareFunction 用戶定義的用來比較排序的函數的地址。該函數的原型如下:
CompareFunc proto lParam1:DWORD, lParam2:DWORD, lParamSort:DWORD
lParam1 和 lParam2 是 LV_ITEM型的結構體中的成員變量lParam的值。
lParamSort 是發送LVM_SORTITEMS消息時參數wParam中的值
當列表視圖控件接收到LVM_SORTITEMS消息時,當需要比較項目時它會調用在lParam中指定的比較函數。比較函數將決定那一個項目排在前面。方法很簡單:如果函數返回一個負值,由(lParam代表的)第一個項目排在前,如果返回正值,第二個項目排在前。如果相等,必須返回0 。
真正使得該方法能夠運行的是LV_ITEM型結構體中的成員變量lParam值。當您需要排序時(譬如當您點擊列的標題條時),您需要考慮好排序方案。在本例中,我們把項目的索引放到該成員變量中,這樣我們可以通過發送LVM_GETITEM消息來得到項目的其它信息。注意:當項目重排序后,它們的索引也就變了。所以當重排序后,我需要在lParam參數中反應出新的索引。如果您想在用戶點擊列的標題條時重新排序,您需要在您的窗口過程函數中處理LVN_COLUMNCLICK通知消息。LVN_COLUMNCLICK消息是隨同WM_NOTIFY消息一起發送的。
例子:
該例子創建了一個列表視圖控件,并在其中顯示了當前文件夾中的文件大小和文件名。缺省的視圖是報告方式的,如果您點擊列標題條,標題將按升/降序重新排列。您可以通過菜單選擇不同的顯示方式(大圖標、小圖標等)。當您雙擊一個項目時,項目的名稱將顯示在一個對話框中。
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comctl32.inc
includelib \masm32\lib\comctl32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
IDM_MAINMENU equ 10000
IDM_ICON equ LVS_ICON
IDM_SMALLICON equ LVS_SMALLICON
IDM_LIST equ LVS_LIST
IDM_REPORT equ LVS_REPORT
RGB macro red,green,blue
xor eax,eax
mov ah,blue
shl eax,8
mov ah,green
mov al,red
endm
.data
ClassName db "ListViewWinClass",0
AppName db "Testing a ListView Control",0
ListViewClassName db "SysListView32",0
Heading1 db "Filename",0
Heading2 db "Size",0
FileNamePattern db "*.*",0
FileNameSortOrder dd 0
SizeSortOrder dd 0
template db "%lu",0
.data?
hInstance HINSTANCE ?
hList dd ?
hMenu dd ?
.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke WinMain, hInstance,NULL, NULL, SW_SHOWDEFAULT
invoke ExitProcess,eax
invoke InitCommonControls
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, NULL
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.lpszMenuName,IDM_MAINMENU
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.while TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.break .if (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.endw
mov eax,msg.wParam
ret
WinMain endp
InsertColumn proc
LOCAL lvc:LV_COLUMN
mov lvc.imask,LVCF_TEXT+LVCF_WIDTH
mov lvc.pszText,offset Heading1
mov lvc.lx,150
invoke SendMessage,hList, LVM_INSERTCOLUMN, 0, addr lvc
or lvc.imask,LVCF_FMT
mov lvc.fmt,LVCFMT_RIGHT
mov lvc.pszText,offset Heading2
mov lvc.lx,100
invoke SendMessage,hList, LVM_INSERTCOLUMN, 1 ,addr lvc
ret
InsertColumn endp
ShowFileInfo proc uses edi row:DWORD, lpFind:DWORD
LOCAL lvi:LV_ITEM
LOCAL buffer[20]:BYTE
mov edi,lpFind
assume edi:ptr WIN32_FIND_DATA
mov lvi.imask,LVIF_TEXT+LVIF_PARAM
push row
pop lvi.iItem
mov lvi.iSubItem,0
lea eax,[edi].cFileName
mov lvi.pszText,eax
push row
pop lvi.lParam
invoke SendMessage,hList, LVM_INSERTITEM,0, addr lvi
mov lvi.imask,LVIF_TEXT
inc lvi.iSubItem
invoke wsprintf,addr buffer, addr template,[edi].nFileSizeLow
lea eax,buffer
mov lvi.pszText,eax
invoke SendMessage,hList,LVM_SETITEM, 0,addr lvi
assume edi:nothing
ret
ShowFileInfo endp
FillFileInfo proc uses edi
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -