基于MFC的CListCtrl实现虚拟列表控件

1. 在建立的工程的对话框里拖入一个ListCtrl控件,然后将控件的属性View改成“Report”,“所有者数据”改成True。如下图所示:

2. 在我们的程序中需要在ListCtrl的父窗口的类里面响应CListCtrl的跟虚拟控件相关的几个消息事件,在父窗口的消息宏里面加入下面几个宏:

ON_NOTIFY(LVN_ODCACHEHINT,IDC_LIST1, OnOwnerDataHint)
ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST1, OnGetDispInfo)
ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST1, OnCustomDraw)

关于这几个消息的说明:

LVN_ODCACHEHINT:该消息在拖动ListCtrl滚动条或翻页的时候会触发,消息的参数携带了当前页的记录范围(当前页记录是从第i到第j个,其中i,j是记录的行号),用户可以在这个消息函数里完成一些比较耗时的加载数据操作,对未加载的数据(翻页时新显示的Line项)读出来放到内存进行缓冲,以便到后面要回调的时候就可以快速读内存。

LVN_GETDISPINFO:该消息的响应函数用于对每行记录的内容进行赋值,消息带的参数为一个LV_ITEM结构体:

typedef struct tagLVITEMA
{
    UINT mask;
    int iItem;
    int iSubItem;
    UINT state;
    UINT stateMask;
    LPSTR pszText;
    int cchTextMax;
    int iImage;
    LPARAM lParam;
#if (_WIN32_IE >= 0x0300)
    int iIndent;
#endif
#if (_WIN32_WINNT >= 0x0501)
    int iGroupId;
    UINT cColumns; // tile view columns
    PUINT puColumns;
#endif
#if _WIN32_WINNT >= 0x0600 // Will be unused downlevel, but sizeof(LVITEMA) must be equal to sizeof(LVITEMW)
    int* piColFmt;
    int iGroup; // readonly. only valid for owner data.
#endif
} LVITEMA, *LPLVITEMA;

上面这个结构体里面的一些成员变量意义,iItem:Line项行号;iSubItem:列号;pszTest:该列的字符串内容;iImage:图标索引;mask:跟项相关的风格属性。

在 LVN_GETDISPINFO 通知消息的处理程序中,必须检查正在请求的信息的类型。可能值是:

  • LVIF_TEXT   必须填写 pszText 成员。
  • LVIF_IMAGE   必须填写 iImage 成员。
  • LVIF_INDENT   必须填写 iIndent 成员。
  • LVIF_PARAM   必须填写 lParam 成员。
  • LVIF_STATE   必须填写 state 成员。

然后应将所有请求的信息提供给框架。

NM_CUSTOMDRAW:该消息处理函数用于定义每行Line项的文字颜色和背景的颜色属性。

 

3. 实现消息处理函数,下面代码是我的例程中的实现方式:

创建列表列
m_LstCtr.InsertColumn(0, L"列1", LVCFMT_CENTER, 40);
m_LstCtr.InsertColumn(1, L"列2", LVCFMT_CENTER, 80);
m_LstCtr.InsertColumn(2, L"列3", LVCFMT_CENTER, 0);	//列宽为零, 标识隐藏该列
m_LstCtr.InsertColumn(3, L"列4", LVCFMT_CENTER, 45);
m_LstCtr.InsertColumn(4, L"列5", LVCFMT_CENTER, 40);
m_LstCtr.InsertColumn(5, L"列6", LVCFMT_CENTER, 80);
//扩展属性 LVS_EX_DOUBLEBUFFER 用来防闪烁
m_LstCtr.SetExtendedStyle(LVS_EX_GRIDLINES | LVS_EX_FLATSB | LVS_EX_FULLROWSELECT | LVS_EX_DOUBLEBUFFER );  
 
 
//--触发LVN_GETDISPINFO消息
 
//dwCount, 表示当前记录数
m_LstCtr.SetItemCountEx(dwCount, LVSICF_NOSCROLL|LVSICF_NOINVALIDATEALL);
//Invalidate必须加, 窗口失去焦点时, 不会实时显示数据
m_LstCtr.Invalidate();	
 
 
 
//--LVN_GETDISPINFO
void CSLConsoleDlg::OnLvnGetdispinfoList(NMHDR *pNMHDR, LRESULT *pResult)
{
	//--MyData我的自定义数据集, 大家可以根据实际情况取自己的数据
	NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);			
	LV_ITEM* pItem= &(pDispInfo)->item;
	
	if ( pItem->mask & LVIF_TEXT )
	{		
		//m_LstCtr.SetRedraw(FALSE);
		CString text;		
		switch (pItem->iSubItem)
		{
		case 0:
			{
				text.Format(L"%d", itemid + 1);
				lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
				break;
			}
		case 1:
			{
				text = MyData[pItem->iItem].Col1;
				lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
				break;
			}
		case 2:
			{
				text = text = MyData[pItem->iItem].Col1;
				lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
				break;
			}
		case 3:
			{
				text.Format(L"%d", MyData[pItem->iItem].Col1;);
				lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
				break;
			}
		case 4:
			{
				text = MyData[pItem->iItem].Col1;
				lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
				break;
			}
		case 5:
			{
				text = MyData[pItem->iItem].Col1;
				lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
				break;
			}						
		default:
			break;
		}   
	}
}

由于这种类型的列表控件 (List Control) 是提供给大的数据集的,因此建议您缓存请求的项数据以提高检索性能。框架提供缓存提示机制,通过发送LVN_ODCACHEHINT 通知消息来帮助优化缓存。但是,您必须使用一种稍有不同的方法来处理该通知。使用“属性”窗口,重写列表控件 (List Control) 对象的 OnChildNotify 函数。

在处理程序体中检查 LVN_ODCACHEHINT 消息,如果找到,则准备缓存。

NMLVCACHEHINT* pcachehint=NULL;

if (message == WM_NOTIFY)
    {
        NMHDR* phdr = (NMHDR*)lParam;

        switch(phdr->code)
        {
        case LVN_ODCACHEHINT:
            pcachehint= (NMLVCACHEHINT*) phdr;
// Load the cache with the recommended range.
            PrepCache(pcachehint->iFrom, pcachehint->iTo);
            break;
        default:
            return CListCtrl::OnChildNotify(message, wParam, lParam, pLResult);
        }
        return FALSE;
    }
    else
        return CListCtrl::OnChildNotify(message, wParam, lParam, pLResult);

当需要查找特定的列表控件项时,虚拟列表控件发送 LVN_ODFINDITEM 通知消息。列表视图 (ListView) 控件接收快捷键访问或接收LVM_FINDITEM 消息时发送该通知消息。搜索信息以 LVFINDINFO 结构的格式发送,该结构是 NMLVFINDITEM 结构的成员。通过重写列表控件 (List Control) 对象的 OnChildNotify 函数来处理该消息,并在处理程序体中检查 LVN_ODFINDITEM 消息。如果找到此消息,则执行相应的操作。

您应该准备好搜索与列表视图 (ListView) 控件给定的信息匹配的项。如果成功,则应返回项的索引;如果没有找到匹配项,则返回 -1。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MFC CListCtrl控件可以响应多种事件,以下是常见的事件及其处理函数: 1. LVN_ITEMCHANGED:当列表项的选状态改变时触发。可以使用以下代码处理: ``` void CMyDialog::OnItemChangedListCtrl(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; if ((pNMListView->uChanged & LVIF_STATE) && (pNMListView->uNewState & LVIS_SELECTED)) { // 处理选项改变事件 } *pResult = 0; } ``` 2. LVN_COLUMNCLICK:当列表头的某一列被单击时触发。可以使用以下代码处理: ``` void CMyDialog::OnColumnClickListCtrl(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; int nColumn = pNMListView->iSubItem; // 处理列单击事件 *pResult = 0; } ``` 3. LVN_BEGINLABELEDIT:当用户开始编辑某一项时触发。可以使用以下代码处理: ``` void CMyDialog::OnBeginLabelEditListCtrl(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLvdi = (LV_DISPINFO*)pNMHDR; LVITEM* pItem = &(pLvdi->item); *pResult = FALSE; // 设置为TRUE表示禁止编辑 } ``` 4. LVN_ENDLABELEDIT:当用户完成编辑某一项时触发。可以使用以下代码处理: ``` void CMyDialog::OnEndLabelEditListCtrl(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pLvdi = (LV_DISPINFO*)pNMHDR; LVITEM* pItem = &(pLvdi->item); // 处理编辑完成事件 *pResult = 0; } ``` 5. LVN_ITEMACTIVATE:当用户双击某一项或按下回车键时触发。可以使用以下代码处理: ``` void CMyDialog::OnItemActivateListCtrl(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // 处理项激活事件 *pResult = 0; } ``` 6. LVN_GETDISPINFO:当控件需要获取某一项的信息时触发。可以使用以下代码处理: ``` void CMyDialog::OnGetDispInfoListCtrl(NMHDR* pNMHDR, LRESULT* pResult) { NMLVDISPINFO* pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR); LVITEM& lvItem = pDispInfo->item; // 设置项的信息 *pResult = 0; } ``` 7. LVN_DELETEITEM:当某一项被删除时触发。可以使用以下代码处理: ``` void CMyDialog::OnDeleteItemListCtrl(NMHDR* pNMHDR, LRESULT* pResult) { NMLISTVIEW* pNMLV = reinterpret_cast<NMLISTVIEW*>(pNMHDR); // 处理删除项事件 *pResult = 0; } ``` 以上是常见的事件及其处理函数,开发者可以根据实际需求选择相应的事件进行处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值