ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
楼主: ivccav

[原创] VBA窗体Listview虚拟模式极速显示100000000行大数据的实现

  [复制链接]

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-5-17 19:03 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
wowo000 发表于 2023-5-17 17:12
尊敬的ivccav老师:用win10专业版+office2021专业增强版测试,出现如图“下标越界错误”,劳烦解惑,谢谢!




不好意思,我的疏忽。最初导出数据的时候我是没有导出标题的。后来加了标题,但结果集数组是不包括标题的,所以行数超出,下标越界了。我更新附件了。我都差点忘记还有右键菜单导出数据的功能了,没有发现问题。

TA的精华主题

TA的得分主题

发表于 2023-5-17 19:12 | 显示全部楼层
ivccav 发表于 2023-5-17 17:52
能正常显示控件吗?只是导出数据有问题?

尊敬的ivccav老师:能正常显示Listview控件,就是右键导出时提示如图“下标越界”。有劳解惑,谢谢!

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-5-17 19:41 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
本帖最后由 ivccav 于 2023-5-17 19:47 编辑
wowo000 发表于 2023-5-17 19:12
尊敬的ivccav老师:能正常显示Listview控件,就是右键导出时提示如图“下标越界”。有劳解惑,谢谢!

2023-05-17_193938.png

TA的精华主题

TA的得分主题

发表于 2023-5-17 19:43 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-5-17 22:49 来自手机 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
opiona 发表于 2023-5-17 18:04
这个是个技术活  赞一下
如果同时在listbox 实现  那就更好了

listbox也支持虚拟模式

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-5-18 08:30 | 显示全部楼层
kings12333 发表于 2023-5-17 18:31
大佬,这个控件如何实现正负号数字排序?给个例子




在数组中进行排序,论坛中有很多。使用时注意数组的上下标,这些贴可能不支持lbound(arr)=0。
很多都是简单的讨论算法,用整数类型举例,没有考虑复杂的应用,只能参考。

https://club.excelhome.net/thread-661033-1-1.html

https://club.excelhome.net/thread-1090007-1-1.html

https://club.excelhome.net/thread-1004590-1-1.html

https://club.excelhome.net/thread-1245495-1-1.html

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-5-18 09:30 | 显示全部楼层



我实际场景中没有用到缓存,所有结果都保存在内存中的,所以没有研究。
缓存优化代码直接使用微软官方的,逻辑我没有改动,只是把c++变成vba。
在从数据库中查询巨量数据集时,或者结果需要非常耗时的运算时,可以使用缓存。


以下为缓存处理的微软原文:

优化缓存
当显示区域的内容发生更改时,虚拟列表视图控件会发送 [color=var(--theme-hyperlink)]LVN_ODCACHEHINT 通知消息。 该消息包含有关要缓存的项范围的信息。 收到通知消息后,应用程序必须准备好使用所请求范围的项信息加载缓存,以便发送 [color=var(--theme-hyperlink)]LVN_GETDISPINFO 通知消息时,该信息将随时可用。
在以下 C++ 代码示例中,应用程序定义的函数接受虚拟列表视图控件发送的缓存的项范围。 它执行验证以确定请求的项目范围尚未缓存,然后分配所需的全局内存,并在必要时填充缓存。
  1. void PrepCache(int iFrom, int iTo)
  2. {
  3.     /*  Global Variables

  4.      *  g_priCache[ ]: the main cache.
  5.      *  g_iCache:      the index of the first item in the main cache.
  6.      *  g_cCache:      the count of items in the main cache.
  7.      *
  8.      *  g_priEndCache[ ]: the cache of items at the end of the list.
  9.      *  g_iEndCache:      the index of the first item in the end cache.
  10.      *  g_cEndCache:      the count of items in the end cache.
  11.      */
  12.      
  13.     // Local Variables
  14.     int i;
  15.     BOOL fOLFrom = FALSE;
  16.     BOOL   fOLTo = FALSE;

  17.     // Check to see if this is the end cache.
  18.     if ((iTo == g_cCache - 1) && ((iTo - iFrom) < 30))  // 30 entries wide.
  19.     {
  20.         // Check to see if this is a portion of the current end cache.
  21.         if ((g_cCache) && (iFrom >= g_iEndCache) && (iFrom < g_iEndCache+g_cEndCache))
  22.             return;
  23.             // If it is a part of current end cache, no loading is necessary.

  24.         // This is a new end cache. Free the old memory.
  25.         if ( g_priEndCache )
  26.             GlobalFree( g_priEndCache );
  27.             
  28.         // Set the index and count values for the new end cache,
  29.         // and then retrieve the memory.
  30.         g_iEndCache   = iFrom;
  31.         g_cEndCache   = (iTo - iFrom + 1);
  32.         g_priEndCache = (RndItem *)GlobalAlloc(GPTR, sizeof(RndItem) * g_cEndCache);

  33.         if (! g_priEndCache)
  34.         {
  35.             // TODO: Out of memory. Perform error handling.
  36.         }

  37.         // Loop to fill the cache with the recommended items.
  38.         for (i=0; i<g_cEndCache; i++)
  39.         {
  40.             // TODO: Call a function that accesses item information and
  41.             // fills a cache element.
  42.         }
  43.     }

  44.     else
  45.     {   
  46.         // It is not a member of the current end cache.
  47.         // Try the primary cache instead.

  48.         // Check to see if iFrom is within the primary cache.
  49.         if ((g_cCache) && (iFrom >= g_iCache) && (iFrom < g_iCache+g_cCache))
  50.             fOLFrom = TRUE;

  51.         // Check to see if iTo is within the primary cache.
  52.         if ((g_cCache) && (iTo >= g_iCache) && (iTo <= g_iCache+g_cCache))
  53.             fOLTo = TRUE;

  54.         // do nothing if both iFrom and iTo are within the current cache.

  55.         if (fOLFrom && fOLTo)
  56.             return;

  57.         // Enlarge the cache size rather than make it specific to this hint.
  58.         if (fOLFrom)
  59.             iFrom = g_iCache;

  60.         else if (fOLTo)
  61.             iTo = g_iCache + g_cCache;

  62.         // A new primary cache is needed. Free the old primary cache.
  63.         if ( g_priCache )
  64.             GlobalFree( g_priCache );

  65.         // Set the index and count values for the new primary cache,
  66.         // and then retrieve the memory.
  67.         g_iCache   = iFrom;
  68.         g_cCache   = (iTo - iFrom + 1);
  69.         g_priCache = (RndItem *)GlobalAlloc( GPTR, sizeof( RndItem ) * g_cCache );

  70.         if (!g_priCache)
  71.         {
  72.             // TODO: Out of memory. Do error handling.
  73.         }

  74.         // Loop to fill the cache with the recommended items.
  75.         for (i=0; i<g_cCache; i++)
  76.         {
  77.             // TODO: Call a function that accesses item information
  78.             // and fills a cache element.
  79.         }
  80.     }
  81. }
复制代码

从缓存中检索项
此示例函数接受两个参数、应用程序定义的结构的地址和一个表示列表中项索引的整数值。 它会检查索引值,以发现是否缓存了所需的项。 如果是,则传递给函数的指针将设置为缓存中的某个位置。 如果该项不在主缓存或结束缓存中,则必须手动定位项信息。
  1. void RetrieveItem( RndItem * prndItem, int index )
  2. {
  3.     // Global Variables

  4.     // g_priCache[ ]: the main cache.
  5.     // g_iCache:      the index of the first item in the main cache.
  6.     // c_cCache:      the count of items in the main cache.
  7.     //
  8.     // g_priEndCache[ ]:  the cache of items at the end of the list.
  9.     // g_iEndCache:       the index of the first item in the end cache.
  10.     // g_cEndCache:       the count of items in the end cache.
  11.     //

  12.     // Check to see if the item is in the main cache.
  13.     if ((index >= g_iCache) && (index < g_iCache + g_cCache))
  14.         *prndItem = g_priCache[index-g_iCache];

  15.     // If it is not in the main cache, then check to see if
  16.     // the item is in the end area cache.
  17.     else if ((index >= g_iEndCache) && (index < g_iEndCache + g_cEndCache))
  18.         *prndItem = g_priEndCache[index-g_iEndCache];

  19.     else
  20.     {
  21.         // The item is not in either cache.
  22.         // Therefore, retrieve the item information manually.
  23.     }
  24. }
复制代码





TA的精华主题

TA的得分主题

 楼主| 发表于 2023-5-18 15:39 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
opiona 发表于 2023-5-17 18:04
这个是个技术活  赞一下
如果同时在listbox 实现  那就更好了




这个不知道有没有帮助:

vbAccelerator - Virtual ListBox.zip (26.91 KB, 下载次数: 153)

TA的精华主题

TA的得分主题

发表于 2023-5-18 19:48 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
看着好像不错
可惜不会英文  本人学俄语的

TA的精华主题

TA的得分主题

 楼主| 发表于 2023-5-18 21:07 来自手机 | 显示全部楼层
opiona 发表于 2023-5-18 19:48
看着好像不错
可惜不会英文  本人学俄语的

俄语也算大语种,我是学小语种的,津巴布韦语,更加看不懂英文
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-12-23 01:27 , Processed in 0.044072 second(s), 6 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表