當(dāng)前位置:首頁(yè) > 芯聞號(hào) > 充電吧
[導(dǎo)讀]一、什么是虛擬列表控件虛擬列表控件是指帶有LVS_OWNERDATA風(fēng)格的列表控件。。二、為什么使用虛擬列表控件我們知道,通常使用列表控件CListCtrl,需要調(diào)用InsertItem把要顯示的數(shù)據(jù)

一、什么是虛擬列表控件虛擬列表控件是指帶有LVS_OWNERDATA風(fēng)格的列表控件。。

二、為什么使用虛擬列表控件

我們知道,通常使用列表控件CListCtrl,需要調(diào)用InsertItem把要顯示的數(shù)據(jù)插入列表中,之后我們就不必關(guān)心數(shù)據(jù)在哪里了,這是因?yàn)榭丶约洪_(kāi)辟了內(nèi)存空間來(lái)保存這些數(shù)據(jù)?,F(xiàn)在假設(shè)我們要顯示一個(gè)數(shù)據(jù)庫(kù),里面的信息量很大,有幾十萬(wàn)條記錄。通常有兩種方法解決這個(gè)問(wèn)題:1是僅僅在ListCtrl中插入少量的數(shù)據(jù),比如100個(gè),然后通過(guò)[上一頁(yè)][下一頁(yè)]兩個(gè)按鈕進(jìn)行控制,某一時(shí)刻顯示的只是從xxx到xxx+100之間的記錄。2是把所有數(shù)據(jù)全部插入到ListCtrl中,然后讓用戶通過(guò)滾動(dòng)來(lái)查看數(shù)據(jù)。無(wú)疑,很多用戶喜歡采用第二種方式,特別是對(duì)于已經(jīng)排序的數(shù)據(jù),用戶只需用鍵盤(pán)輸入某行的開(kāi)頭字符,就可以快速定位到某一行。但是,如果這樣做,InsertItem插入數(shù)據(jù)的過(guò)程將是很漫長(zhǎng)的,而且用戶會(huì)看到ListCtrl刷新速度也很慢,而且所有數(shù)據(jù)都位于內(nèi)存中消耗了大量的內(nèi)存,當(dāng)數(shù)據(jù)多達(dá)上萬(wàn)以后幾乎是不能忍受的。

為此,mfc特別提供了虛擬列表的支持。一個(gè)虛擬列表看起來(lái)和普通的ListCtrl一樣,但是不用通過(guò)InsertItem來(lái)插入數(shù)據(jù),它僅僅知道自己應(yīng)該顯示多少數(shù)據(jù)。但是它如何知道要顯示什么數(shù)據(jù)呢?秘密就在于當(dāng)列表控件需要顯示某個(gè)數(shù)據(jù)的時(shí)候,它向父窗口要。假設(shè)這個(gè)列表控件包含100個(gè)元素,第10到20個(gè)元素(行)是可見(jiàn)的。當(dāng)列表控件重畫(huà)的時(shí)候 ,它首先請(qǐng)求父窗口給它第10個(gè)元素的數(shù)據(jù),父窗口收到請(qǐng)求以后,把數(shù)據(jù)信息填充到列表提供的一個(gè)結(jié)構(gòu)中,列表就可以用來(lái)顯示了,顯示第10個(gè)數(shù)據(jù)后,列表會(huì)繼續(xù)請(qǐng)求下一個(gè)數(shù)據(jù)。

在虛擬的樣式下,ListCtrl可以支持多達(dá)DWORD個(gè)數(shù)據(jù)項(xiàng)。(缺省的listctrl控件最多支持int個(gè)數(shù)據(jù)項(xiàng))。但是,虛擬列表的最大優(yōu)點(diǎn)不在于此,而是它僅僅需要在內(nèi)存中保持極少量的數(shù)據(jù),從而加快了顯示的速度。所以,在使用列表控件顯示一個(gè)很大的數(shù)據(jù)庫(kù)的情況下,采用虛擬列表最好不過(guò)了。

不僅CListCtrl提供虛擬列表的功能, MFC的CListView類(lèi)也有同樣的功能。

三、虛擬列表控件的消息


虛擬列表總共發(fā)送三個(gè)消息給父窗口:當(dāng)它需要數(shù)據(jù)的時(shí)候,它發(fā)送LVN_GETDISPINFO消息。這是最重要的消息。當(dāng)用戶試圖查找某個(gè)元素的時(shí)候,它發(fā)送LVN_ODFINDITEM消息;還有一個(gè)消息是LVN_ODCACHEHINT,用來(lái)緩沖數(shù)據(jù),基本上很少用到這個(gè)消息。

虛擬列表控件使用起來(lái)非常簡(jiǎn)單。它總共只有三個(gè)相關(guān)的消息,如果你直接使用CListCtrl,應(yīng)該在對(duì)話框中響應(yīng)這三個(gè)消息。如果你使用CListCtrl派生類(lèi),可以在派生類(lèi)中響應(yīng)這三個(gè)消息的反射消息。這三個(gè)消息分別是:

(1)LVN_GETDISPINFO 控件請(qǐng)求某個(gè)數(shù)據(jù)
(2)LVN_ODFINDITEM 查找某個(gè)數(shù)據(jù)
(3)LVN_ODCACHEHINT 緩沖某一部分?jǐn)?shù)據(jù)

我們必須響應(yīng)的消息是(1),多數(shù)情況下要響應(yīng)(2),極少數(shù)的情況下需要響應(yīng)(3)

四、如何使用虛擬列表控件

1、首先要?jiǎng)?chuàng)建控件,創(chuàng)建一個(gè)虛擬列表和創(chuàng)建一個(gè)正常的 CListCtrl差不多。先在資源編輯器里面添加一個(gè)list control資源。然后選中"Owner data"屬性,然后給它捆綁一個(gè)CListCtrl變量。添加列,添加imagelist等都和使用正常的listctrl一樣。

2、給虛擬列表添加元素。假設(shè) m_list 是這個(gè)列表的控制變量。通常的情況下這樣添加數(shù)據(jù):

m_list.InsertItem(0, _T("Hello world"));

但是對(duì)于虛擬列表,不能這么做。只需告訴列表有多少個(gè)數(shù)據(jù):

//總共顯示100行
m_list.SetItemCount(100);

3、處理它的通知消息。

五、如何響應(yīng)虛擬列表的消息(http://www.pudn.com/downloads72/sourcecode/windows/control/listview/detail261310.html#)

1、處理 LVN_GETDISPINFO 通知消息

當(dāng)虛擬列表控件需要某個(gè)數(shù)據(jù)的時(shí)候,它給父窗口發(fā)送一個(gè) LVN_GETDISPINFO通知消息,表示請(qǐng)求某個(gè)數(shù)據(jù)。因此列表的所有者窗口(或者它自己)必須處理這個(gè)消息。例如派生類(lèi)的情況 (CMyListCtrl是一個(gè)虛擬列表類(lèi)對(duì)象):

//這里處理的是反射消息
BEGIN_MESSAGE_MAP(CMyListCtrl, CListCtrl)
???//{{AFX_MSG_MAP(CMyListCtrl)
??? ON_NOTIFY_REFLECT(LVN_GETDISPINFO, OnGetdispinfo)
???//}}AFX_MSG_MAP
END_MESSAGE_MAP()

在LVN_GETDISPINFO的處理函數(shù)中,必須首先檢查列表請(qǐng)求的是什么數(shù)據(jù),可能的值包括:

(1)LVIF_TEXT??? 必須填充 pszText
(2)LVIF_IMAGE 必須填充 iImage?
(3)LVIF_INDENT 必須填充 iIndent
(4)LVIF_PARAM 必須填充 lParam?
(5)LVIF_STATE 必須填充 state

根據(jù)它的請(qǐng)求,填充所需的數(shù)據(jù)即可。

//================= 例子代碼=====================================

下面的給出一個(gè)例子,填充的是列表所需的某個(gè)數(shù)據(jù)項(xiàng)的文字以及圖像信息:

LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
LV_ITEM* pItem= &(pDispInfo)->item;

int?iItemIndx= pItem->iItem;

if?(pItem->mask & LVIF_TEXT)?//字符串緩沖區(qū)有效
{
????switch(pItem->iSubItem){
????????case?0:?//填充數(shù)據(jù)項(xiàng)的名字
???????????? lstrcpy(pItem->pszText,m_Items[iItemIndx].m_strItemText);
????????????break;
????????case?1:?//填充子項(xiàng)1
???????????? lstrcpy(pItem->pszText,m_Items[iItemIndx].m_strSubItem1Text);
????????????break;
????????case?2:?//填充子項(xiàng)2
???????????? lstrcpy(pItem->pszText,m_Items[iItemIndx].m_strSubItem2Text);
????????????break;
???? }
}
/*注意,多數(shù)情況下要使用lstrcpyn ,因?yàn)樽疃鄰?fù)制字符的個(gè)數(shù)由pItem->cchTextMax給出:
???????? lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
*/

if?(pItem->mask & LVIF_IMAGE)?//是否請(qǐng)求圖像
???????? pItem->iImage= m_Items[iItemIndx].m_iImageIndex;

甚至連某行數(shù)據(jù)是否選中(當(dāng)有checkbox的情況下)的信息也需要由用戶自己來(lái)維護(hù),例如:
//是否顯示該行的選擇信息?
if(IsCheckBoxesVisible())?//自定義函數(shù)
{
???? pItem->mask |= LVIF_STATE;
???? pItem->stateMask = LVIS_STATEIMAGEMASK;

????if(m_database[itemid].m_checked)
???? {
????????? pItem->state = INDEXTOSTATEIMAGEMASK(2);
???? }
????else
???? {
????????? pItem->state = INDEXTOSTATEIMAGEMASK(1);
????? }
}


2、處理 LVN_ODFINDITEM 消息

在資源管理器里面,定位到某個(gè)文件夾,會(huì)顯示很多文件,如果按下鍵盤(pán)的'A',則資源管理器會(huì)自動(dòng)找到名字以 'A'打頭的文件夾或者文件, 并選擇該文件。繼續(xù)按 A,如果還有其它名字以'A'打頭的文件,則下一個(gè)文件被選中。如果輸入?"AB",則 'A''?頭的文件被選中。這就是列表控件的自動(dòng)查找功能。

當(dāng)虛擬列表收到一個(gè)LVM_FINDITEM消息,它也會(huì)發(fā)送這個(gè)消息通知父窗口查找目標(biāo)元素。要搜索的信息通過(guò) LVFINDINFO 結(jié)構(gòu)給出。它是 NMLVFINDITEM 結(jié)構(gòu)的一個(gè)成員。當(dāng)找到要搜索的數(shù)據(jù)后,應(yīng)該把該數(shù)據(jù)的索引(行號(hào))返回,如果沒(méi)有找到,則返回-1。

以對(duì)話框?yàn)槔憫?yīng)函數(shù)大致如下:

//================= 例子代碼=====================================
void?CVirtualListDlg::OnOdfinditemList(NMHDR* pNMHDR, LRESULT* pResult)?
{
????// pNMHDR 里面是要查找的元素的信息
????// 要選中的目標(biāo)元素的行號(hào)最后要保存在 pResult 中, 這是關(guān)鍵!

???? NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)pNMHDR;

????/* pFindInfo->iStart 是查找的起始位置,一直到最后,然后從頭開(kāi)始,如果沒(méi)有找到合適的,最終停留在iStart*/

???? *pResult = -1;

????//是否按照文字查找?
????if( (pFindInfo->lvfi.flags & LVFI_STRING) == 0 )
???? {
????????return;
???? }

????//這是我們要找的字符串
???? CString searchstr = pFindInfo->lvfi.psz;

????int?startPos = pFindInfo->iStart;//保存起始位置

????//判斷是否最后一行
????if(startPos >= m_list.GetItemCount())
???????? startPos = 0;

????int?currentPos=startPos;
????
????//開(kāi)始查找
????do
???? {????????
????????if( _tcsnicmp(m_database[currentPos].m_name,?
????????????????? searchstr, searchstr.GetLength()) == 0)
???????? {
????????????//選中這個(gè)元素,停止查找
???????????? *pResult = currentPos;
????????????break;
???????? }

???????? currentPos++;

????????//從頭開(kāi)始
????????if(currentPos >= m_list.GetItemCount())
???????????? currentPos = 0;

???? }while(currentPos != startPos);????????
}

顯然,如果數(shù)據(jù)很多,必須實(shí)現(xiàn)一個(gè)快速查找的方法。

關(guān)于pFindInfo->lvfi里面的信息的詳細(xì)說(shuō)明可以參考 MSDN。

3、處理 LVN_ODCACHEHINT 消息。

假如我們從數(shù)據(jù)庫(kù)或者其它地方讀取數(shù)據(jù)的速度比較慢,則可以利用這個(gè)消息,批量讀取一些數(shù)據(jù),然后根據(jù)請(qǐng)求,逐個(gè)提供給虛擬列表。LVN_ODCACHEHINT消息的用途就是給程序一個(gè)緩沖數(shù)據(jù)的機(jī)會(huì)。以提高程序的性能。

//================= 例子代碼=====================================
使用 ClassWizard 重載 OnChildNotify 函數(shù),檢查是否 LVN_ODCACHEHINT 消息,然后準(zhǔn)備緩沖數(shù)據(jù):

NMLVCACHEHINT* pcachehint=NULL;

NMHDR* phdr = (NMHDR*)lParam;

if(phdr->code == LVN_ODCACHEHINT)
{
????? pcachehint= (NMLVCACHEHINT*) phdr;
?????//自定義函數(shù),準(zhǔn)備指定范圍的數(shù)據(jù)到緩沖區(qū)
????? PrepCache(pcachehint->iFrom, pcachehint->iTo);
}
else?...

注意,如果消息不是 LVN_ODCACHEHINT,則要傳遞給基類(lèi)進(jìn)行處理。

五、如何修改ListCtrl顯示的數(shù)據(jù)。

由于是程序自己維護(hù)數(shù)據(jù),所以只需修改數(shù)據(jù)庫(kù)中的數(shù)據(jù),然后調(diào)用CListCtrl::RedrawItems函數(shù)進(jìn)行重畫(huà)即可。

六、數(shù)據(jù)的選擇狀態(tài)和選擇框

CListCtrl可以顯示checkbox選擇框。有些情況下是很有用的。對(duì)于正常的listctrl,用戶可以用鼠標(biāo)來(lái)修改某個(gè)元素的選擇狀態(tài),但是對(duì)于虛擬列表就不行了。必須自己處理一些消息,然后自己保存數(shù)據(jù)的選中狀態(tài):

void?CVirtualListDlg::ToggleCheckBox(int?item)
{
???? m_database[item].m_checked = !m_database[item].m_checked;
???? m_list.RedrawItems(item, item);
}

處理 LVN_KEYDOWN消息,添加對(duì)空格鍵 的響應(yīng),用于切換選擇狀態(tài):

void?CVirtualListDlg::OnKeydownList(NMHDR* pNMHDR, LRESULT* pResult)?
{
???? LV_KEYDOWN* pLVKeyDown = (LV_KEYDOWN*)pNMHDR;

????if( pLVKeyDown->wVKey == VK_SPACE )
???? {
???????int?item = m_list.GetSelectionMark();
????????if(item != -1)
???????????? ToggleCheckBox(item);
???? }

???? *pResult = 0;
}

然后處理 NM_CLICK 消息:

void?CVirtualListDlg::OnClickList(NMHDR* pNMHDR, LRESULT* pResult)?
{
???? NMLISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

???? LVHITTESTINFO hitinfo;
???? hitinfo.pt = pNMListView->ptAction;

????int?item = m_list.HitTest(&hitinfo);

????if(item != -1)
???? {
????????//看看鼠標(biāo)是否單擊在 check box上面了?
????????if( (hitinfo.flags & LVHT_ONITEMSTATEICON) != 0)
???????? {
???????????? ToggleCheckBox(item);
???????? }
???? }
????
???? *pResult = 0;
}

七、備注:

???? 1、虛擬列表無(wú)法進(jìn)行排序。

???? 2、虛表的一個(gè)優(yōu)點(diǎn)是容易保持和數(shù)據(jù)庫(kù)的同步。修改數(shù)據(jù)庫(kù)中的數(shù)據(jù),然后重畫(huà)list十分容易而且高效。

???? 3、虛表的另一個(gè)優(yōu)點(diǎn)是可以根據(jù)需要產(chǎn)生數(shù)據(jù)。比如在某一列加上行號(hào)。


本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車(chē)的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

倫敦2024年8月29日 /美通社/ -- 英國(guó)汽車(chē)技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車(chē)工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車(chē)。 SODA V工具的開(kāi)發(fā)耗時(shí)1.5...

關(guān)鍵字: 汽車(chē) 人工智能 智能驅(qū)動(dòng) BSP

北京2024年8月28日 /美通社/ -- 越來(lái)越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時(shí)企業(yè)卻面臨越來(lái)越多業(yè)務(wù)中斷的風(fēng)險(xiǎn),如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報(bào)道,騰訊和網(wǎng)易近期正在縮減他們對(duì)日本游戲市場(chǎng)的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)開(kāi)幕式在貴陽(yáng)舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國(guó)國(guó)際大數(shù)據(jù)產(chǎn)業(yè)博覽會(huì)上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語(yǔ)權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對(duì)環(huán)境變化,經(jīng)營(yíng)業(yè)績(jī)穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤(rùn)率延續(xù)升勢(shì) 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長(zhǎng) 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競(jìng)爭(zhēng)力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競(jìng)爭(zhēng)優(yōu)勢(shì)...

關(guān)鍵字: 通信 BSP 電信運(yùn)營(yíng)商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺(tái)與中國(guó)電影電視技術(shù)學(xué)會(huì)聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會(huì)上宣布正式成立。 活動(dòng)現(xiàn)場(chǎng) NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長(zhǎng)三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會(huì)上,軟通動(dòng)力信息技術(shù)(集團(tuán))股份有限公司(以下簡(jiǎn)稱"軟通動(dòng)力")與長(zhǎng)三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉