note

  • 虚拟列表可有效加载大量数据
  • 需要处理listctrl的 LVN_GETDISPINFO 消息
  • 使用虚拟列表 不能 使用 insert的方法插入数据,而是告诉listctrl 当前要显示多少行
  • 使用SetItemCount函数告诉listctrl当前显示多少行
  • 使用虚拟列表需要自己维护数据源

使用

  • 添加list ctrl 控件
  • 将其Owner Data 属性 设置为 True

  • 添加listctrl的 LVN_GETDISPINFO 的消息

范例

  • 初始化 listctrl, list_ctrl是自己添加的控件变量
		LONG lStyle;
lStyle = GetWindowLong(list_ctrl.m_hWnd , GWL_STYLE);//获取当前窗口style
lStyle &= ~LVS_TYPEMASK; //清除显示方式位
lStyle |= LVS_REPORT; //设置style
SetWindowLong(list_ctrl.m_hWnd , GWL_STYLE , lStyle);//设置style
DWORD dwStyle = list_ctrl.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl)
dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl)
dwStyle |= LVS_EX_CHECKBOXES;//item前生成checkbox控件
dwStyle |= LVS_EX_DOUBLEBUFFER;
list_ctrl.SetExtendedStyle(dwStyle); //设置扩展风格
  • 这里创建了2列
		list_ctrl.InsertColumn(0 , L"ID" , LVCFMT_LEFT , 40);//插入列
list_ctrl.InsertColumn(1 , L"NAME" , LVCFMT_LEFT , 50);
  • 添加LVN_GETDISPINFO消息处理函数
void CMFCApplication1Dlg::OnLvnGetdispinfoList1(NMHDR *pNMHDR , LRESULT *pResult)
{
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR); *pResult = 0;
}
  • 该函数用于显示 行的每一列,函数体实现如下
void CMFCApplication1Dlg::OnLvnGetdispinfoList1(NMHDR *pNMHDR , LRESULT *pResult)
{
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
if (nullptr == pDispInfo)
{
*pResult = 0;
return;
} LV_ITEM* pItem= &(pDispInfo)->item;
if (nullptr == pItem)
{
*pResult = 0;
return;
} /// 自己维护的数据源中没有数据
if (0 >= map_list_item_.size())
{
*pResult = 0;
return;
} /// 当前请求显示的是第几行
int cur_row_index = pItem->iItem; if (LVIF_TEXT & pItem->mask) //字符串缓冲区有效
{
/// 当前请求显示的是第几列
int cur_column_index = pItem->iSubItem; switch (cur_column_index)
{
/// 第一列
case 0:
{ CString str_id;
/// 将id转为字符串
str_id.Format(L"%d", map_list_item_[cur_row_index].id_);
/// 显示第一列
lstrcpy(pItem->pszText, str_id); }
break; /// 第二列
case 1:
{
/// 显示第二列
lstrcpy(pItem->pszText, map_list_item_[cur_row_index].name_);
}
break; default:
break;
} } *pResult = 0;
}

其中,map_list_item_是我自己维护的数据源,其定义如下

	/// <id列,name列>
std::map<int, list_ctrl_item> map_list_item_;

用作测试使用,list_ctrl_item的定义如下:

struct st_list_item_
{
int id_ = 0;
CString name_ = _T(""); void zero_()
{
id_ = 0;
name_ = _T("");
}
st_list_item_()
{
zero_();
}
}; using list_ctrl_item = st_list_item_;
  • OnInitDialog() 函数中对数据源做了添加
		/// 插入数据
auto insert_item = [&](int index)
{
list_ctrl_item item;
item.id_ = index;
item.name_.Format(L"%d", index); map_list_item_.insert(std::make_pair(index, item));
}; insert_item(0);
insert_item(1);
insert_item(2);
insert_item(3);
  • 自己用了定时器, 定时告诉list_ctrl刷新数据
void CMFCApplication1Dlg::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == ktimer_id)
{
list_ctrl.SetItemCount(map_list_item_.size());
list_ctrl.Invalidate();
} CDialogEx::OnTimer(nIDEvent);
}

效果

完整源码

头文件


// MFCApplication1Dlg.h : 头文件
// #pragma once
#include "afxcmn.h" #include "list_ctrl_ex.h" #include <map> struct st_list_item_
{
int id_ = 0;
CString name_ = _T(""); void zero_()
{
id_ = 0;
name_ = _T("");
}
st_list_item_()
{
zero_();
}
}; using list_ctrl_item = st_list_item_; // CMFCApplication1Dlg 对话框
class CMFCApplication1Dlg : public CDialogEx
{ enum
{
ktimer_id = 1000,
kinterval = 500,
}; // 构造
public:
CMFCApplication1Dlg(CWnd* pParent = NULL); // 标准构造函数 // 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_MFCAPPLICATION1_DIALOG };
#endif protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 UINT_PTR timer_id = 0; void uninit_(); /// <id列,name列>
std::map<int, list_ctrl_item> map_list_item_; // 实现
protected:
HICON m_hIcon; // 生成的消息映射函数
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
list_ctrl_ex list_ctrl;
afx_msg void OnLvnGetdispinfoList1(NMHDR *pNMHDR , LRESULT *pResult);
afx_msg void OnLvnOdfinditemList1(NMHDR *pNMHDR , LRESULT *pResult);
afx_msg void OnLvnOdcachehintList1(NMHDR *pNMHDR , LRESULT *pResult);
};

cpp


// MFCApplication1Dlg.cpp : 实现文件
// #include "stdafx.h"
#include "MFCApplication1.h"
#include "MFCApplication1Dlg.h"
#include "afxdialogex.h"
#include <windowsx.h> #ifdef _DEBUG
#define new DEBUG_NEW
#endif // 用于应用程序“关于”菜单项的 CAboutDlg 对话框 class CAboutDlg : public CDialogEx
{
public:
CAboutDlg(); // 对话框数据
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持 // 实现
protected:
DECLARE_MESSAGE_MAP()
}; CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
} void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
} BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP() // CMFCApplication1Dlg 对话框 CMFCApplication1Dlg::CMFCApplication1Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_MFCAPPLICATION1_DIALOG, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
} void CMFCApplication1Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX , IDC_LIST1 , list_ctrl);
} /// ----------------------------------------------------------------
/// @brief:
/// ----------------------------------------------------------------
void CMFCApplication1Dlg::uninit_()
{
if (0 != timer_id)
{
KillTimer(timer_id);
timer_id = 0;
}
} BEGIN_MESSAGE_MAP(CMFCApplication1Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_WM_TIMER()
ON_NOTIFY(LVN_GETDISPINFO , IDC_LIST1 , &CMFCApplication1Dlg::OnLvnGetdispinfoList1)
ON_NOTIFY(LVN_ODFINDITEM , IDC_LIST1 , &CMFCApplication1Dlg::OnLvnOdfinditemList1)
ON_NOTIFY(LVN_ODCACHEHINT , IDC_LIST1 , &CMFCApplication1Dlg::OnLvnOdcachehintList1)
END_MESSAGE_MAP() // CMFCApplication1Dlg 消息处理程序 BOOL CMFCApplication1Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog(); // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动
// 执行此操作
SetIcon(m_hIcon, TRUE); // 设置大图标
SetIcon(m_hIcon, FALSE); // 设置小图标 {
LONG lStyle;
lStyle = GetWindowLong(list_ctrl.m_hWnd , GWL_STYLE);//获取当前窗口style
lStyle &= ~LVS_TYPEMASK; //清除显示方式位
lStyle |= LVS_REPORT; //设置style
SetWindowLong(list_ctrl.m_hWnd , GWL_STYLE , lStyle);//设置style
DWORD dwStyle = list_ctrl.GetExtendedStyle();
dwStyle |= LVS_EX_FULLROWSELECT;//选中某行使整行高亮(只适用与report风格的listctrl)
dwStyle |= LVS_EX_GRIDLINES;//网格线(只适用与report风格的listctrl)
dwStyle |= LVS_EX_CHECKBOXES;//item前生成checkbox控件
dwStyle |= LVS_EX_DOUBLEBUFFER;
list_ctrl.SetExtendedStyle(dwStyle); //设置扩展风格
}
{
list_ctrl.InsertColumn(0 , L"ID" , LVCFMT_LEFT , 40);//插入列
list_ctrl.InsertColumn(1 , L"NAME" , LVCFMT_LEFT , 50);
} {
/// 插入数据
auto insert_item = [&](int index)
{
list_ctrl_item item;
item.id_ = index;
item.name_.Format(L"%d", index); map_list_item_.insert(std::make_pair(index, item));
}; insert_item(0);
insert_item(1);
insert_item(2);
insert_item(3); } {
timer_id = SetTimer(ktimer_id, kinterval, NULL);
} return TRUE; // 除非将焦点设置到控件,否则返回 TRUE
} void CMFCApplication1Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
} // 如果向对话框添加最小化按钮,则需要下面的代码
// 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序,
// 这将由框架自动完成。 void CMFCApplication1Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0); // 使图标在工作区矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2; // 绘制图标
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
} /// ----------------------------------------------------------------
/// @brief:
/// ----------------------------------------------------------------
void CMFCApplication1Dlg::OnTimer(UINT_PTR nIDEvent)
{
if (nIDEvent == ktimer_id)
{
list_ctrl.SetItemCount(map_list_item_.size());
list_ctrl.Invalidate();
} CDialogEx::OnTimer(nIDEvent);
} //当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CMFCApplication1Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
} void CMFCApplication1Dlg::OnLvnGetdispinfoList1(NMHDR *pNMHDR , LRESULT *pResult)
{
NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
if (nullptr == pDispInfo)
{
*pResult = 0;
return;
} LV_ITEM* pItem= &(pDispInfo)->item;
if (nullptr == pItem)
{
*pResult = 0;
return;
} /// 自己维护的数据源中没有数据
if (0 >= map_list_item_.size())
{
*pResult = 0;
return;
} /// 当前请求显示的是第几行
int cur_row_index = pItem->iItem; if (LVIF_TEXT & pItem->mask) //字符串缓冲区有效
{
/// 当前请求显示的是第几列
int cur_column_index = pItem->iSubItem; switch (cur_column_index)
{
/// 第一列
case 0:
{ CString str_id;
/// 将id转为字符串
str_id.Format(L"%d", map_list_item_[cur_row_index].id_);
/// 显示第一列
lstrcpy(pItem->pszText, str_id); }
break; /// 第二列
case 1:
{
/// 显示第二列
lstrcpy(pItem->pszText, map_list_item_[cur_row_index].name_);
}
break; default:
break;
} } *pResult = 0;
} void CMFCApplication1Dlg::OnLvnOdfinditemList1(NMHDR *pNMHDR , LRESULT *pResult)
{
LPNMLVFINDITEM pFindInfo = reinterpret_cast<LPNMLVFINDITEM>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
} void CMFCApplication1Dlg::OnLvnOdcachehintList1(NMHDR *pNMHDR , LRESULT *pResult)
{
LPNMLVCACHEHINT pCacheHint = reinterpret_cast<LPNMLVCACHEHINT>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
*pResult = 0;
}

vc mfc listctrl使用虚拟列表 虚拟列表用法的更多相关文章

  1. VC/MFC ListCtrl 控件功能使用汇总(转)

    以下未经说明,listctrl默认view 风格为report 相关类及处理函数 MFC:CListCtrl类 SDK:以 “ListView_”开头的一些宏.如 ListView_InsertCol ...

  2. VC++ 中ListCtrl经验总结

    先注明一下,这里,我们用m_listctrl来表示一个CListCtrl的类对象,然后这里我们的ListCtrl都是report形式,至于其他的如什么大图标,小图标的暂时不讲,毕竟report是大众话 ...

  3. 邮件服务配置(虚拟域&虚拟用户)

    邮件服务配置(虚拟域&虚拟用户) 现在我做的是: Linux + httpd + php + mariadb + postfix + dovecot + phpMyAdmin + postfi ...

  4. VC/MFC如何添加启动界面

    2015-05 转自 香远益清原文VC/MFC如何添加启动界面 1.基于框架类的应用程序添加启动画面的步骤(利用组件库中的Splash Screen组件生成Splash1.cpp 和Splash1.h ...

  5. VC++/MFC(VC6)开发技术精品学习资料下载汇总

    工欲善其事,必先利其器,VC开发MFC Windows程序,Visual C++或Visual Studio是必须的,恩,这里都给你总结好了,拿去吧:VC/MFC开发必备Visual C++.Visu ...

  6. VC ++ MFC activex 控件获取连接的VPN 信息

    vc++  MFC 进行activex  控件的开发步骤就不用多写了,只是简单的说明一下方法,以及具体的代码: 使用的类库是 windows 系统的 rasapi32.dll 记住需要添加的头文件如下 ...

  7. vc/mfc获取rgb图像数据后动态显示及保存图片的方法

    vc/mfc获取rgb图像数据后动态显示及保存图片的方法 该情况可用于视频通信中获取的位图数据回放显示或显示摄像头捕获的本地图像 第一种方法 #include<vfw.h> 加载 vfw3 ...

  8. 《Python CookBook2》 第四章 Python技巧 - 若列表中某元素存在则返回之 && 在无须共享引用的条件下创建列表的列表

    若列表中某元素存在则返回之 任务: 你有一个列表L,还有一个索引号i,若i是有效索引时,返回L[i],若不是,则返回默认值v 解决方案: 列表支持双向索引,所以i可以为负数 >>> ...

  9. Excel列表部分列表隐藏与取消隐藏

    Excel列表部分列表隐藏与取消隐藏 2014-2-19 隐藏:选中需要隐藏的列(选中A.B.C....),右键单击所选部分,选择"隐藏"即可. 取消隐藏:从A选中至所见表格最后的 ...

随机推荐

  1. Codeforces 1368H - Breadboard Capacity(最小割+线段树维护矩阵乘法)

    Easy version:Codeforces 题面传送门 & 洛谷题面传送门 Hard version:Codeforces 题面传送门 & 洛谷题面传送门 首先看到这种从某一种颜色 ...

  2. Linux图片查看软件ImageMagick安装

    在Linux中查看图片,这个需求是非常常见的.总不至于在集群中生成个图片,随便看下效果,也要用filezilla.winscp之类的远程文件传输工具导过来导过去吧,这样效率太低. Linux图片查看常 ...

  3. 数据库(database)介绍

    0.数据定义:除了文本类型的数据,图像.音乐.声音都是数据. 数据分类:结构化数据.非结构化数据.1.数据库定义:"电子化的文件柜","数据仓库".数据库是一个 ...

  4. Ubuntu apt代理apt-cacher-ng配置及使用

    apt-cacher-ng是更强大的apt代理服务器的替代方案,例如squid-deb-proxy.如果您正在运行小型家庭或办公室网络,那就别无所求.它可能缺少一些更高级的功能,但是可以立即进行配置, ...

  5. Hadoop入门 集群崩溃的处理方法

    目录 集群崩溃的处理方法 搞崩集群 错误示范 正确处理方法 1 回到hadoop的家目录 2 杀死进程 3 删除每个集群的data和logs 4 格式化 5 启动集群 总结 原因分析 集群崩溃的处理方 ...

  6. Spark Stage 的划分

    Spark作业调度 对RDD的操作分为transformation和action两类,真正的作业提交运行发生在action之后,调用action之后会将对原始输入数据的所有transformation ...

  7. Spark(十六)【SparkStreaming基本使用】

    目录 一. SparkStreaming简介 1. 相关术语 2. SparkStreaming概念 3. SparkStreaming架构 4. 背压机制 二. Dstream入门 1. WordC ...

  8. Flume(一)【概述】

    目录 一.Flume定义 二.Flume基础架构 1.Agent 2.Source 3.Sink 4.Channel 5.Event 一.Flume定义 ​ Flume是Cloudera公司提供的一个 ...

  9. 关于vue-cli中-webkit-flex-direction: column失效问题

    我最近在用vue-cli更新项目,在我引入layer.css后会报错并且使用弹性盒时查看元素的时候没有-webkit-flex-direction: column这个属性会失效 这个本身就不打算给di ...

  10. Angular @ViewChild,Angular 中的 dom 操作

    Angular 中的 dom 操作(原生 js) ngAfterViewInit(){ var boxDom:any=document.getElementById('box'); boxDom.st ...