You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

虚拟CMFCListCtrl滚动条闪烁问题技术求助

嘿,针对你用MFC虚拟列表控件(LVS_OWNERDATA)需要每秒刷新数据的需求,结合你给出的初始化代码,我给你一套实用的解决方案:

实现虚拟列表每秒自动刷新的核心方案

首先得明确:虚拟列表不会缓存所有数据,它只在需要显示时通过LVN_GETDISPINFO消息向你请求当前可见行的内容。所以咱们的刷新逻辑不是硬更每一行,而是通知控件数据源已更新,让它重新请求数据,同时尽量避免全屏闪烁。

1. 加个定时器触发每秒刷新

首先在你的CMyListCtrl类里加个1秒的定时器,用来定时更新数据源并通知列表:

  • 在Init函数末尾补上定时器初始化(记得修正你代码里的InsertColum笔误,应该是InsertColumn):
bool CMyListCtrl::Init(CWnd* pParent) { 
    CRect rectDummy; 
    if(!Create(WS_CHILD|WS_VISIBLE|WS_BORDER|LVS_REPORT|LVS_SHOWSELALWAYS|LVS_OWNERDATA, 
               rectDummy, pParent, IDC_LIST1)) 
        return false; 
    
    #define LVS_EX_DOUBLEBUFFER 0x00010000 
    SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_DOUBLEBUFFER); 
    InsertColumn(0,_T("#"),LVCFMT_LEFT, 20,1); 
    // 这里继续添加你的其他列...
    
    // 设置1秒(1000毫秒)定时器,ID用1001就行,自定义也可以
    SetTimer(1001, 1000, nullptr);
    return true;
}
  • 然后给类加上定时器消息处理(别忘了在消息映射里加ON_WM_TIMER()):
void CMyListCtrl::OnTimer(UINT_PTR nIDEvent)
{
    if (nIDEvent == 1001)
    {
        // 第一步:更新你的数据源(比如从接口拉取新数据、本地计算更新)
        UpdateMyDataSource(); // 这个函数需要你自己实现,更新背后的数据集合
        
        // 第二步:如果总行数变了,先通知控件更新总行数
        int newItemCount = GetUpdatedTotalItemCount(); // 替换成你实际的总行数
        SetItemCount(newItemCount);
        
        // 第三步:只刷新可见区域,避免全屏闪烁
        int topIndex = GetTopIndex();
        int visibleCount = GetCountPerPage();
        RedrawItems(topIndex, topIndex + visibleCount - 1);
    }
    CListCtrl::OnTimer(nIDEvent);
}

2. 优化LVN_GETDISPINFO确保取最新数据

虚拟列表显示内容全靠这个消息,一定要确保它能拿到最新的数据源:

void CMyListCtrl::OnGetDispInfo(NMHDR* pNMHDR, LRESULT* pResult)
{
    NMLVDISPINFO* pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
    LVITEM* pItem = &pDispInfo->item;

    if (pItem->mask & LVIF_TEXT)
    {
        // 从你刚更新的数据源里,取对应行和列的文本
        CString cellText = GetCellDataFromSource(pItem->iItem, pItem->iSubItem); // 你的数据源读取逻辑
        _tcscpy_s(pItem->pszText, pItem->cchTextMax, cellText);
    }

    *pResult = 0;
}

3. 别忘了清理定时器

窗口销毁时记得关掉定时器,避免内存泄漏:

void CMyListCtrl::OnDestroy()
{
    KillTimer(1001);
    CListCtrl::OnDestroy();
}

额外的闪烁优化

你已经设置了LVS_EX_DOUBLEBUFFER,这很好,再加上只刷新可见行的操作,基本就能避免明显闪烁了。如果还是有问题,可以试试在刷新前禁用控件重绘,刷新后再启用:

// 在RedrawItems前后加:
SetRedraw(FALSE);
RedrawItems(topIndex, topIndex + visibleCount - 1);
SetRedraw(TRUE);

这样一套操作下来,你的虚拟列表就能每秒自动拉取/更新数据,同时保持流畅不卡顿~

内容的提问来源于stack exchange,提问作者user9444860

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 10:47:31