尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
[Win32/WTL]_[虚拟列表]_[如何避免添加行数据时频繁刷新]
场景在使用Win32/WTL虚拟列表时有时候底层短时间内接收到批量的数据之后需要更新到列表。这时如果只用SetItemCount更新列表时更新的越频繁列表就会越闪烁。这样给用户的体验就会比较差怎么解决闪烁的问题说明虚拟列表[5]主要是用来大数据的显示卡顿问题。 但现在使用SetItemCount增加行数时会频繁刷新列表可见区域如果可见区域有自定义的图片区域那么刷新图片会有明显的闪烁问题。 这个虚拟列表已经有解决方案使用SetItemCountEx或者ListView_SetItemCountEx函数并传递LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL参数。LVSICF_NOINVALIDATEALL:除非受影响的项目当前处于视图中否则列表视图控件不会重新绘出。 即当前通过SetItemCountEx添加的行数刚好在列表的可见区域中,那么就会刷新。LVSICF_NOSCROLL: 当项计数发生更改时列表视图控件不会更改滚动位置。 即当前你滚动到4-10行调用SetItemCountEx会影响当前的列表可见的行数4-10行, 只会滑块变小。因此项目中把SetItemCount替换为SetItemCountEx, 即不会闪烁也提供性能。listview_.SetItemCountEx(photos_.size(),LVSICF_NOINVALIDATEALL|LVSICF_NOSCROLL);listview_.SetItemCountEx(photos_.size(),LVSICF_NOINVALIDATEALL|LVSICF_NOSCROLL);例子View.h// View.h : interface of the CView class///////////////////////////////////////////////////////////////////////////////#pragmaonce#includeutility#includestring#includevector#includememory#includeatlmisc.h#includeatlctrls.h#includeatlctrlx.h#includeGdiPlus.husingnamespacestd;enum{kMyButtonIdWM_USER1,kMyButtonId2,kMyButtonId3,kMyListViewId};classPhoto{public:wstring name;wstring createDate;wstring path;wstring format;};classCView:publicCWindowImplCView{public:DECLARE_WND_CLASS(NULL)BOOLPreTranslateMessage(MSG*pMsg);BEGIN_MSG_MAP_EX(CView)MSG_WM_CREATE(OnCreate)MESSAGE_HANDLER(WM_PAINT,OnPaint)NOTIFY_HANDLER(kMyListViewId,NM_CLICK,OnNMClickListResult)NOTIFY_HANDLER(kMyListViewId,LVN_GETDISPINFO,OnGetListViewData)NOTIFY_HANDLER(kMyListViewId,LVN_ODCACHEHINT,OnPrepareListViewData)NOTIFY_HANDLER(kMyListViewId,LVN_ODFINDITEM,OnFindListViewData)COMMAND_RANGE_HANDLER_EX(kMyButtonId,kMyButtonId3,OnCommandIDHandlerEX)MSG_WM_TIMER(OnTimer)REFLECT_NOTIFICATIONS()END_MSG_MAP()protected:// Handler prototypes (uncomment arguments if needed):// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL /*bHandled*/)// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL /*bHandled*/)// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL /*bHandled*/)intOnCreate(LPCREATESTRUCT lpCreateStruct);LRESULTOnPaint(UINT/*uMsg*/,WPARAM/*wParam*/,LPARAM/*lParam*/,BOOL/*bHandled*/);voidUpdateLayout();LRESULTOnNMClickListResult(intidCtrl,LPNMHDR pnmh,BOOLbHandled);LRESULTOnGetListViewData(intidCtrl,LPNMHDR pnmh,BOOLbHandled);LRESULTOnPrepareListViewData(intidCtrl,LPNMHDR pnmh,BOOLbHandled);LRESULTOnFindListViewData(intidCtrl,LPNMHDR pnmh,BOOLbHandled);voidOnCommandIDHandlerEX(UINT uNotifyCode,intnID,CWindow wndCtl);voidReloadMockData();voidReloadListView();voidOnTimer(UINT_PTR nIDEvent);private:std::wstringGetControlText(HWND hwnd,wchar_t*bufNULL);CListViewCtrl listview_;vectorshared_ptrPhoto*photos_;CFont font_normal_;CFont font_bold_;CBrushHandle brush_white_;CBrushHandle brush_hollow_;CBrush brush_red_;CButton buttonReloadMockData_;CButton buttonReloadListView_;CButton buttonDeleteListViewOneRow_;};View.cpp// View.cpp : implementation of the CView class///////////////////////////////////////////////////////////////////////////////#includestdafx.h#includeresource.h#includeutility#includesstream#includestdint.h#includeassert.h#includeStrsafe.h#includerandom#includeView.h#includeCommCtrl.h#includestring#includeregexusingnamespacestd;BOOLCView::PreTranslateMessage(MSG*pMsg){returnFALSE;}LRESULTCView::OnPaint(UINT/*uMsg*/,WPARAM/*wParam*/,LPARAM/*lParam*/,BOOL/*bHandled*/){CPaintDCdc(m_hWnd);CMemoryDCmdc(dc,dc.m_ps.rcPaint);CRect rect_client;GetClientRect(rect_client);mdc.FillSolidRect(rect_client,RGB(255,255,255));//TODO: Add your drawing code herereturn0;}staticHFONTGetFont(intpixel,boolbold,constwchar_t*font_name){LOGFONT lf;memset(lf,0,sizeof(LOGFONT));// zero out structurelf.lfHeightpixel;// request a 8-pixel-height fontif(bold){lf.lfWeightFW_BOLD;}lstrcpy(lf.lfFaceName,font_name);// request a face name ArialHFONT font::CreateFontIndirect(lf);returnfont;}std::wstringCView::GetControlText(HWND hwnd,wchar_t*buf){autolength::GetWindowTextLength(hwnd);boolbufNullfalse;if(!buf){bufnewwchar_t[length1]();bufNulltrue;}::GetWindowText(hwnd,buf,length1);std::wstringstr(buf);if(bufNull)delete[]buf;returnstr;}staticstd::wstringGetProductBinDir(){staticwchar_tszbuf[MAX_PATH];GetModuleFileName(NULL,szbuf,MAX_PATH);PathRemoveFileSpec(szbuf);intlengthlstrlen(szbuf);szbuf[length]L\\;szbuf[length1]0;returnstd::wstring(szbuf);}inttoRandInt(intmin,intmax){// thread_local 修饰符的变量只初始化一次,每个线程一个gen,避免多线程调用同一个gen导致数据竞争。// 使用minstd_rand生成性能高简单的可预测的随机数。// 使用mt19937 生成性能稍低很难预测的随机数。//thread_local std::mt19937 gen(std::random_device{}());thread_localstd::minstd_randgen(std::random_device{}());std::uniform_int_distributiondist(min,max);returndist(gen);}LRESULTCView::OnGetListViewData(intidCtrl,LPNMHDR pnmh,BOOLbHandled){NMLVDISPINFO*plvdi(NMLVDISPINFO*)pnmh;autoiItemplvdi-item.iItem;if(-1iItem)return0;autocountphotos_.size();if(!count||countiItem)return0;autophotophotos_[iItem];if(plvdi-item.maskLVIF_TEXT){switch(plvdi-item.iSubItem){case0:{autovalueto_wstring((int64_t)iItem1);StringCchCopy(plvdi-item.pszText,plvdi-item.cchTextMax,value.c_str());break;}case1:{autovaluephoto-get()-nameL-to_wstring(toRandInt(1,100));StringCchCopy(plvdi-item.pszText,plvdi-item.cchTextMax,value.c_str());break;}case2:StringCchCopy(plvdi-item.pszText,plvdi-item.cchTextMax,photo-get()-format.c_str());break;case3:StringCchCopy(plvdi-item.pszText,plvdi-item.cchTextMax,photo-get()-createDate.c_str());break;}}return0;}LRESULTCView::OnPrepareListViewData(intidCtrl,LPNMHDR pnmh,BOOLbHandled){return0;}LRESULTCView::OnFindListViewData(intidCtrl,LPNMHDR pnmh,BOOLbHandled){LPNMLVFINDITEM pnmfi(LPNMLVFINDITEM)pnmh;autoiItempnmfi-iStart;if(-1iItem)return-1;autocountphotos_.size();if(!count||countiItem)return-1;return0;}LRESULTCView::OnNMClickListResult(intidCtrl,LPNMHDR pnmh,BOOLbHandled){return0;}voidCView::OnCommandIDHandlerEX(UINT uNotifyCode,intnID,CWindow wndCtl){switch(nID){casekMyButtonId:{ReloadMockData();break;}casekMyButtonId2:{ReloadListView();MessageBox(L刷新表格数据完成);break;}casekMyButtonId3:{std::vectorintrows;intiItem-1;while((iItemlistview_.GetNextItem(iItem,LVNI_SELECTED))!-1)rows.push_back(iItem);if(rows.empty())break;for(intirows.size()-1;i0;--i)photos_.erase(photos_.begin()rows.at(i));listview_.SetItemCountEx(photos_.size(),LVSICF_NOINVALIDATEALL|LVSICF_NOSCROLL);MessageBox(L已删除);break;}}}voidCView::ReloadListView(){listview_.SetItemCount(0);for(autoi0;iphotos_.size();i)deletephotos_[i];photos_.clear();}voidCView::OnTimer(UINT_PTR nIDEvent){staticintconstkMaxCount200;staticintindex0;staticintcount0;if(countkMaxCount){count0;index0;KillTimer(nIDEvent);MessageBox(L刷新模拟数据完成);return;}wchar_tbuf[MAX_PATH]{0};LVCOLUMN co;memset(co,0,sizeof(co));co.maskLVCF_TEXT;co.pszTextbuf;co.cchTextMaxMAX_PATH;listview_.GetColumn(1,co);std::wstringc0Text(buf);listview_.GetColumn(2,co);std::wstringc1Text(buf);listview_.GetColumn(3,co);std::wstringc2Text(buf);for(inti0;i500countkMaxCount;i,index){autophotonewPhoto();wsprintf(buf,(c0TextL-%d).c_str(),index);photo-namebuf;wsprintf(buf,(c1TextL-%d).c_str(),index);photo-formatbuf;wsprintf(buf,(c2TextL-%d).c_str(),index);photo-createDatebuf;photos_.push_back(newshared_ptrPhoto(photo));}listview_.SetItemCountEx(photos_.size(),LVSICF_NOINVALIDATEALL|LVSICF_NOSCROLL);//listview_.SetItemCount(photos_.size());count;}voidCView::ReloadMockData(){SetTimer(1,500);}intCView::OnCreate(LPCREATESTRUCT lpCreateStruct){font_normal_::GetFont(16,false,LArial);font_bold_::GetFont(16,true,LArial);brush_hollow_AtlGetStockBrush(HOLLOW_BRUSH);brush_white_AtlGetStockBrush(WHITE_BRUSH);brush_red_.CreateSolidBrush(RGB(255,0,0));// 1.创建CListViewCtrllistview_.Create(m_hWnd,0,NULL,WS_CHILD|WS_TABSTOP|WS_VISIBLE|LVS_ALIGNLEFT|LVS_REPORT|LVS_SHOWSELALWAYS|WS_BORDER|LVS_OWNERDATA,0,kMyListViewId);listview_.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_DOUBLEBUFFER);//listview_.SetBkColor(RGB(255, 255, 255));listview_.SetTextBkColor(RGB(255,255,255));listview_.SetFont(font_normal_);autoheaderlistview_.GetHeader();header.SetFont(font_bold_);listview_.SetBkColor(RGB(255,255,255));listview_.InsertColumn(0,LNo.,LVCFMT_LEFT,100);listview_.InsertColumn(1,LName,LVCFMT_LEFT,100);listview_.InsertColumn(2,LFormat,LVCFMT_LEFT,100);listview_.InsertColumn(3,LCreate Date,LVCFMT_LEFT,100);// 2.创建按钮buttonReloadMockData_.Create(m_hWnd,0,L加载新数据,WS_CHILD|WS_VISIBLE,0,kMyButtonId);buttonReloadMockData_.SetFont(font_normal_);buttonReloadListView_.Create(m_hWnd,0,L刷新表格,WS_CHILD|WS_VISIBLE,0,kMyButtonId2);buttonReloadListView_.SetFont(font_normal_);buttonDeleteListViewOneRow_.Create(m_hWnd,0,L删除选中行,WS_CHILD|WS_VISIBLE,0,kMyButtonId3);buttonDeleteListViewOneRow_.SetFont(font_normal_);UpdateLayout();return0;}voidCView::UpdateLayout(){CRect rect;GetClientRect(rect);CClientDCdc(m_hWnd);dc.SelectFont(font_normal_);CSizesize_control(500,300);CRect rect_controlCRect(CPoint(20,20),size_control);listview_.MoveWindow(rect_control);CSize size_button;buttonReloadMockData_.GetIdealSize(size_button);rect_controlCRect(CPoint(rect_control.left,rect_control.bottom10),size_button);buttonReloadMockData_.MoveWindow(rect_control);CSize sizeButton2;buttonReloadListView_.GetIdealSize(sizeButton2);rect_controlCRect(CPoint(rect_control.right10,rect_control.top),sizeButton2);buttonReloadListView_.MoveWindow(rect_control);CSize sizeButton3;buttonDeleteListViewOneRow_.GetIdealSize(sizeButton3);rect_controlCRect(CPoint(rect_control.right10,rect_control.top),sizeButton3);buttonDeleteListViewOneRow_.MoveWindow(rect_control);}项目项目源码,VS2010以上 https://download.csdn.net/download/infoworld/93325545运行带SetItemCountEx带LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL参数:SetItemCount不带参数不带参数时当前可见区域一直刷新这里Name一直变化就是说明在插入数据时一直刷新参考LVM_GETNEXTITEMLVM_SETITEMCOUNTListView_SetItemCountListView_SetItemCountEx使用虚拟列表视图来解决新增大量数据卡顿问题关于列表视图控件
RELATED

相关推荐

中职教育 那些经久不衰的学习模式

中职教育 那些经久不衰的学习模式

在中职教育领域,特别是在护理行业,成都微畔教育科技有限公司(简称“微畔教育”)以其专业性和全面的服务体系脱颖而出,成为该领域的佼者。下面通过一个真实的科室休息室对话场景来体现微畔教育在中职护理行业的垄断性地…

📅 2026/10/27 7:29:07
UE5 Gameplay Ability System (GAS) 实战指南:构建数据驱动的ARPG技能与状态系统

UE5 Gameplay Ability System (GAS) 实战指南:构建数据驱动的ARPG技能与状态系统

如果你正在用UE5开发一款带有复杂技能、状态效果(Buff/Debuff)或属性成长的游戏,比如ARPG、MOBA或MMO,那么你一定遇到过这样的困境:技能逻辑散落在角色蓝图、动画蓝图、UI等各个角落,一个“火球术”的伤害、…

📅 2026/9/9 1:40:19
Minecraft红石隐藏门:8方块极简设计与双版本兼容方案

Minecraft红石隐藏门:8方块极简设计与双版本兼容方案

在《我的世界》中,建造隐藏门是许多玩家热衷的“红石工程”之一。无论是用于保护秘密基地,还是仅仅为了享受机关带来的乐趣,一个设计精巧、结构简单的隐藏门总能带来极大的成就感。然而,许多经典的红石隐藏门设计要么体积庞大、结…

📅 2026/9/8 3:56:08
MORE NEWS

更多资讯

📰

Docker容器GPU加速实战:CUDA驱动与框架版本对齐指南

1. 项目概述:Docker容器里跑GPU模型,不是“配个参数”就完事的你是不是也遇到过这种情况:本地训练一个PyTorch模型,单卡RTX 4090跑得飞快,但一打包进Docker镜像,nvidia-smi能看见显卡,torch.cud…

📰

10个提升Mac Dock效率的实用技巧

1. Mac程序坞的隐藏价值与常见误区作为一名使用Mac超过8年的资深用户,我见过太多朋友把Dock(程序坞)仅仅当作一个简单的应用启动栏。实际上,这个看似简单的界面元素蕴含着苹果工程师精心设计的诸多交互逻辑。很多人不知道的是&…

📰

Git删除指定commit的完整操作指南

1. Git分支中删除指定commit的完整指南作为版本控制系统的核心工具,Git在日常开发中扮演着重要角色。最近在团队协作时遇到一个典型场景:某次错误提交的commit已经推送到远程分支,需要在不影响其他提交的情况下将其从分支历史中彻底移除。经过…

📰

AI Agent开发中Skills的演进与实战应用

1. Skills的演进:从编程工具配角到Agent研发核心十年前我刚入行时,Skills还只是IDE里一个不起眼的插件功能。当时在Eclipse里安装Code Recommenders插件,它会根据上下文提示可能的API调用——这种初级代码补全就是Skills的雏形。如今在AI Age…

📰

Git删除特定commit的实用指南与最佳实践

1. 为什么需要删除分支中的特定commit?在团队协作开发中,Git分支管理是日常工作的核心部分。我遇到过无数次这样的情况:某个功能分支中混入了不该提交的敏感信息,或者不小心提交了错误的代码修改,又或者需要清理历史记…

📰

Agent-Reach:面向AI Agent的轻量级跨平台API通信中枢

1. 项目概述:Agent-Reach 是什么,它解决的是哪类真实问题? Agent-Reach 不是一个泛泛而谈的“智能体概念”,而是面向开发者、自动化工程师和内容运营者的一套 可落地、可嵌入、可调度的轻量级代理通信中枢 。它本质上是一套标准…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬