一、什麼是虛擬列表控制項
虛擬列表控制項是指帶有lvs_ownerdata風格的列表控制項。。
二、為什麼使用虛擬列表控制項
為此,mfc特別提供了虛擬列表的支援。乙個虛擬列表看起來和普通的listctrl一樣,但是不用通過insertitem來插入資料,它僅僅知道自己應該顯示多少資料。但是它如何知道要顯示什麼資料呢?秘密就在於當列表控制項需要顯示某個資料的時候,它向父視窗要。假設這個列表控制項包含100個元素,第10到20個元素(行)是可見的。當列表控制項重畫的時候,它首先請求父視窗給它第10個元素的資料,父視窗收到請求以後,把資料資訊填充到列表提供的乙個結構中,列表就可以用來顯示了,顯示第10個資料後,列表會繼續請求下乙個資料。
在虛擬的樣式下,listctrl可以支援多達dword個資料項。(預設的listctrl控制項最多支援int個資料項)。但是,虛擬列表的最大優點不在於此,而是它僅僅需要在記憶體中保持極少量的資料,從而加快了顯示的速度。所以,在使用列表控制項顯示乙個很大的資料庫的情況下,採用虛擬列表最好不過了。
不僅clistctrl提供虛擬列表的功能, mfc的clistview類也有同樣的功能。
三、虛擬列表控制項的訊息
虛擬列表總共傳送三個訊息給父視窗:當它需要資料的時候,它傳送lvn_getdispinfo訊息。這是最重要的訊息。當使用者試圖查詢某個元素的時候,它傳送lvn_odfinditem訊息;還有乙個訊息是lvn_odcachehint,用來緩衝資料,基本上很少用到這個訊息。
虛擬列表控制項使用起來非常簡單。它總共只有三個相關的訊息,如果你直接使用clistctrl,應該在對話方塊中響應這三個訊息。如果你使用clistctrl派生類,可以在派生類中響應這三個訊息的反射訊息。這三個訊息分別是:
(1)lvn_getdispinfo 控制項請求某個資料
(2)lvn_odfinditem 查詢某個資料
(3)lvn_odcachehint 緩衝某一部分資料
我們必須響應的訊息是(1),多數情況下要響應(2),極少數的情況下需要響應(3)
四、如何使用虛擬列表控制項
1、首先要建立控制項,建立乙個虛擬列表和建立乙個正常的 clistctrl差不多。先在資源編輯器裡面新增乙個list control資源。然後選中"owner data"屬性,然後給它**乙個clistctrl變數。新增列,新增imagelist等都和使用正常的listctrl一樣。
2、給虛擬列表新增元素。假設 m_list 是這個列表的控制變數。通常的情況下這樣新增資料:
m_list.insertitem(0, _t("hello world"));
但是對於虛擬列表,不能這麼做。只需告訴列表有多少個資料:
//總共顯示100行
m_list.setitemcount(100);
3、處理它的通知訊息。
五、如何響應虛擬列表的訊息
1、處理 lvn_getdispinfo 通知訊息
當虛擬列表控制項需要某個資料的時候,它給父視窗傳送乙個 lvn_getdispinfo通知訊息,表示請求某個資料。因此列表的所有者視窗(或者它自己)必須處理這個訊息。例如派生類的情況 (cmylistctrl是乙個虛擬列表類物件):
//這裡處理的是反射訊息
begin_message_map(cmylistctrl, clistctrl)
//}afx_msg_map
end_message_map()
在lvn_getdispinfo的處理函式中,必須首先檢查列表請求的是什麼資料,可能的值包括:
(1)lvif_text 必須填充 psztext
(2)lvif_image 必須填充 iimage
(3)lvif_indent 必須填充 iindent
(4)lvif_param 必須填充 lparam
(5)lvif_state 必須填充 state
根據它的請求,填充所需的資料即可。
//***************== 例子*************************************==
下面的給出乙個例子,填充的是列表所需的某個資料項的文字以及影象資訊:
lv_dispinfo* pdispinfo = (lv_dispinfo*)pnmhdr;
lv_item* pitem= &(pdispinfo)->item;
int iitemindx= pitem->iitem;
if (pitem->mask & lvif_text) //字串緩衝區有效
}if (pitem->mask & lvif_image) //是否請求影象
pitem->iimage= m_items[iitemindx].m_iimageindex;
甚至連某行資料是否選中(當有checkbox的情況下)的資訊也需要由使用者自己來維護,例如:
//是否顯示該行的選擇資訊?
if(ischeckboxesvisible()) //自定義函式
else
}2、處理 lvn_odfinditem 訊息
在資源管理器裡面,定位到某個資料夾,會顯示很多檔案,如果按下鍵盤的『a』,則資源管理器會自動找到名字以 'a'打頭的資料夾或者檔案, 並選擇該檔案。繼續按 a,如果還有其它名字以'a'打頭的檔案,則下乙個檔案被選中。如果輸入 "ab",則 'ab'打頭的檔案被選中。這就是列表控制項的自動查詢功能。
當虛擬列表收到乙個lvm_finditem訊息,它也會傳送這個訊息通知父視窗查詢目標元素。要搜尋的資訊通過 lvfindinfo 結構給出。它是 nmlvfinditem 結構的乙個成員。當找到要搜尋的資料後,應該把該資料的索引(行號)返回,如果沒有找到,則返回-1。
以對話方塊為例,響應函式大致如下:
//***************== 例子*************************************==
void cvirtuallistdlg::onodfinditemlist(nmhdr* pnmhdr, lresult* presult)
//這是我們要找的字串
cstring searchstr = pfindinfo->lvfi.psz;
int startpos = pfindinfo->istart;//儲存起始位置
//判斷是否最後一行
if(startpos >= m_list.getitemcount())
startpos = 0;
int currentpos=startpos;
//開始查詢
docurrentpos++;
//從頭開始
if(currentpos >= m_list.getitemcount())
currentpos = 0;
}while(currentpos != startpos);
}顯然,如果資料很多,必須實現乙個快速查詢的方法。
關於pfindinfo->lvfi裡面的資訊的詳細說明可以參考 msdn。
3、處理 lvn_odcachehint 訊息。
假如我們從資料庫或者其它地方讀取資料的速度比較慢,則可以利用這個訊息,批量讀取一些資料,然後根據請求,逐個提供給虛擬列表。lvn_odcachehint訊息的用途就是給程式乙個緩衝資料的機會。以提高程式的效能。
//***************== 例子*************************************==
使用 classwizard 過載 onchildnotify 函式,檢查是否 lvn_odcachehint 訊息,然後準備緩衝資料:
nmlvcachehint* pcachehint=null;
nmhdr* phdr = (nmhdr*)lparam;
if(phdr->code == lvn_odcachehint)
else ...
注意,如果訊息不是 lvn_odcachehint,則要傳遞給基類進行處理。
五、如何修改listctrl顯示的資料。
由於是程式自己維護資料,所以只需修改資料庫中的資料,然後呼叫clistctrl::redrawitems函式進行重畫即可。
六、資料的選擇狀態和選擇框
clistctrl可以顯示checkbox選擇框。有些情況下是很有用的。對於正常的listctrl,使用者可以用滑鼠來修改某個元素的選擇狀態,但是對於虛擬列表就不行了。必須自己處理一些訊息,然後自己儲存資料的選中狀態:
void cvirtuallistdlg::togglecheckbox(int item)
處理 lvn_keydown訊息,新增對空格鍵 的響應,用於切換選擇狀態:
void cvirtuallistdlg::onkeydownlist(nmhdr* pnmhdr, lresult* presult)
*presult = 0;
}然後處理 nm_click 訊息:
void cvirtuallistdlg::onclicklist(nmhdr* pnmhdr, lresult* presult)
}*presult = 0;
}七、備註:
1、虛擬列表無法進行排序。
2、虛表的乙個優點是容易保持和資料庫的同步。修改資料庫中的資料,然後重畫list十分容易而且高效。
3、虛表的另乙個優點是可以根據需要產生資料。比如在某一列加上行號。
clistctrl 虛擬列表
一 什麼是虛擬列表控制項 虛擬列表控制項是指帶有lvs ownerdata風格的列表控制項。二 為什麼使用虛擬列表控制項 為此,mfc特別提供了虛擬列表的支援。乙個虛擬列表看起來和普通的listctrl一樣,但是不用通過insertitem來插入資料,它僅僅知道自己應該顯示多少資料。但是它如何知道要...
虛擬列表控制項(CListCtrl)
m list.setitemcount 100 3 處理它的通知訊息。五 如何響應虛擬列表的訊息 1 處理 lvn getdispinfo 通知訊息 當虛擬列表控制項需要某個資料的時候,它給父視窗傳送乙個 lvn getdispinfo通知訊息,表示請求某個資料。因此列表的所有者視窗 或者它自己 必...
虛擬列表控制項(CListCtrl)
虛擬列表控制項 clistctrl 2011年02月16日 星期三 下午 02 02 m list.setitemcount 100 3 處理它的通知訊息。五 如何響應虛擬列表的訊息 http www.pudn.com downloads72 sourcecode windows control l...