ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 Excel Home精品图文教程库
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
300集Office 2010微视频教程 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 17785|回复: 41

[原创] 纯VBA制作的Listview, Treeview控件

  [复制链接]

TA的精华主题

TA的得分主题

发表于 2015-12-7 11:11 | 显示全部楼层 |阅读模式
制作这个控件的动机是, 前不久在一个外国网站(http://www.jkp-ads.com/index.asp)看到老外用MSForms做了一个Treeview, 理由我就不说了. 看了之后觉得这个控件有不少可以改进的地方, 然后又看到好多人询问是否有制作Listview. 那个老外说没这个计划. 觉得自己可以做一个Listview的控件. 就开始动手, 大概花了有2周的时间, 因为是业余时间断断续续写的, 写完是1个多月后了.
老外写的控件显示部分用的动态增加标签控件,图像控件, Scrollbar用的Frame内置, 这样控件滚动部分完全由Frame控制, 好处是自己节省功夫, 但坏处是所有数据(控件)都必须一次性生成,这样在多数据的情况下, 控件性能可能会成为问题. 我测试过, 当增加5000个节点的时候, 在我的机器是10秒的时间, 作者的演示中也提示超过5000个节点时可能会花比较长的时间.
如果数据显示部分不是全部用动态控件的方式, 那么就要自己画数据了, 自己画数据也有2种方式, 一是把所有数据一次画出来, 这样画出的图片会比较大, 然后控件的滚动也交由Frame控制, 自己省功夫. 刚开始的时候我是这样做的, 但发现系统性能更差, 全部推翻重来. 我认为应该与Frame的图片缓存有关, 但自己没办法控制.
这样, 为提高控件性能, 每次只画当前显示部分的数据, 这样就不能用Frame的滚动条了, 刚开始用的MSForms的滚动条, 但那个滚动条, 闪啊闪啊, 闪得我太窝火, 没办法, 自己再写一个滚动条类, 自己写的控件外观就自己做主了, 全部应用系统主题,看起来顺眼多了.
写完这个控件, 因为微软的Listview有多重视图方式, 自己这个只写了一种视图方式, 不好意思叫Listview, 改了名字叫ItemList, 但加了一些Listview没有的属性和方法.比如行高, 行背景颜色,多种编辑方式等. 最重要的性能测试, 我加了有10万条数据, 画面刷新不到1秒. 我也就不再花心思改进了. 控件的代码都是想到写到, 里面应该会有好多地方可以再优化. 大家看到不要喷啊.
写完ItemList控件后, 再写Treeview, 没有前面的弯路, 花的时间就少了, 完全和微软的一样的没意思, 就加了一个多列的属性, 然后再加多几个事件, 写到差不多完工时, 突然有点怠工, 不想做了, 所以现在这个Treeview是个快完成品, 比半成品多点. 等什么时候有兴趣再继续写完它.

Treeview Demo

Treeview Demo

ItemList Demo

ItemList Demo

CommonControl.zip

691.91 KB, 下载次数: 1092

评分

9

查看全部评分

TA的精华主题

TA的得分主题

发表于 2015-12-7 14:10 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
如何调用不说一下吗?代码公开的吗?如果公开,移植方面就不成问题了。如果又是一个DLL等东西,那还是没啥用啊。

TA的精华主题

TA的得分主题

发表于 2015-12-7 14:42 | 显示全部楼层

TA的精华主题

TA的得分主题

发表于 2015-12-7 15:43 | 显示全部楼层
看了代码实在是夸张,吓一跳,可见VBA要写出这样的窗体控件,难度是非常大的。我努力的想把其中一部分窗体功能用入我的窗体中,可是难以实现。还希望楼主能整理出统一的出入接口,方便别人调用。否则我估计没有几个人能完全看懂,然后自由调用。

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-12-7 19:43 | 显示全部楼层

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-12-7 19:45 | 显示全部楼层
接口文档正在整理, 我都是模仿微软控件的接口, 基本上同名接口的功能都和微软的一样.

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-12-7 23:06 | 显示全部楼层
看起来没多少人对这个有兴趣, 单纯的使用这个控件很简单, 用VBA写并公开代码的目的是使用的人可以根据自己的需要修改控件, 这才是我的目的,下面是cTreeview类的用法和接口
cTreeview类的使用方法               
1. 新增一个窗体UserForm1, 在窗体中放入一个Frame控件, 这个控件是cTreeview类的基础, cTreeview要和这个控件绑定才能运行               
2. 在窗体模块中定义一个模块级变量,带WithEvents关键字,用于生成事件, 如演示窗体中:                
Private WithEvents mTree As cTreeview               
3. 在窗体的初始化事件中实例化变量,并绑定Frame控件               
Private Sub UserForm_Initialize()               
    Set mTree = New cTreeview               
    Set mTree.BindingFrame = Me.Frame1               
End Sub               
4. 最后, 在窗体的退出事件中加入释放类代码是一个好的编程习惯:               
Private Sub UserForm_Terminate()               
    Set mTree = Nothing               
End Sub               
5. cTreeview类准备工作完毕, 可以像MSForms中其他控件一样使用了, 比如下面, 具体使用可见属性,方法和事件的介绍               
增加节点:                 Set nodX = mTree.AddNode("Text1", tvwChild, "Text1.2", "Text1.2")
                mTree.AddNode "Text1.2", tvwChild, "Text1.2.1", "Text1.2.1"
删除节点:                mTree.RemoveNode "Text1.2.1"
得到选择的节点                Set nodX = mTree.SelectedNode
也可以见到cTreeview类发出的各个事件               





                       


cTreeview事件

cTreeview事件

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-12-7 23:07 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
  cTreeview类的属性
  
  
1
  
  Public Property Get Item(Index  As Variant) As Node
  
  只读属性,可以得到cTreeview的一个节点Node, Index参数可以是序号,关键字或节点ID
  
  
2
  
  Public Property Get FirstRoot()  As Node
  
  只读属性,获得类的第一个根节点
  
  
3
  
  Public Property Get LastRoot()  As Node
  
  只读属性,获得类的最后一个根节点
  
  
4
  
  Public Property Get NodeCount()  As Integer
  
  只读属性,获得类的节点数量
  
  
5
  
  Public Property Get/Set  BindingFrame() As MSForms.Frame
  
  绑定框架控件的属性, 获得或设定绑定的Frame Control
  
  
6
  
  Public Property Get Header() As  cHeader
  
  只读属性, 可以获得内部Header控件类, 进一步控制Header的属性
  
  
7
  
  Public Property Get/Let  ShowHeader() As Boolean
  
  是否显示Header 控件
  
  
8
  
  Public Property Get/Let  ShowTreeLine() As Boolean
  
  是否显示节点连线
  
  
9
  
  Public Property Get/Let  ShowPlusMinus() As Boolean
  
  节点是否显示收缩展开按钮,就是那个+/-
  
  
10
  
  Public Property Get/Let  ShowCheckBox() As Boolean
  
  节点是否显示CheckBox
  
  
11
  
  Public Property Get/Let  ShowImage() As Boolean
  
  节点是否显示图标
  
  
12
  
  Public Property Get/Set  ImageSet() As StdPicture
  
  节点的图标集, 由所有图标集合成一张大图片,由程序进行分割
  
  
13
  
  Public Property Get/Let  ImageRows() As Long
  
  图标集有几行图标
  
  
14
  
  Public Property Get/Let  ImageCols() As Long
  
  图标集有几列图标
  
  
15
  
  Public Property Get/Let  RowHeight() As Long
  
  节点行高,单位是像素
  
  
16
  
  Public Property Get/Set Font()  As StdFont
  
  控件字体属性
  
  
17
  
  Public Property Get/Let  Indentation() As Long
  
  节点缩进长度, 单位是像素
  
  
18
  
  Public Property Get/Let  MarginX() As Single
  
  树控件左侧留白,单位是磅
  
  
19
  
  Public Property Get MarginY()  As Single
  
  树控件上侧留白,单位是磅
  
  
20
  
  Public Property Get Editable()  As Boolean
  
  节点是否可以编辑
  
  
21
  
  Public Property Get  InEditMode() As Boolean
  
  只读属性,控件的节点是否处于编辑状态
  
  
22
  
  Public Property Get/Set  SelectedNode() As Node
  
  设置/获得选定的节点
  
  
23
  
  Public Function  GetVisibleCount() As Long
  
  只读属性,获得控件中可见的节点数
  
  
24
  
  Public Property Get  FirstVisibleNode() As Node
  
  只读属性, 获得第一个可见的节点
  
  
25
  
  Public Property Get  LastVisibleNode() As Node
  
  只读属性,获得最后一个可见的节点
  
  
26
  
  Public Property Get/Let  LockScreen() As Boolean
  
  设置/获得控件是否锁住屏幕更新,在更新大量数据时可以提高性能
  

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-12-7 23:09 | 显示全部楼层
cTreeview类的方法       
1        Public Function AddNode(Optional Relative As Variant, Optional Relationship As TreeRelationshipConstants = tvwChild, _
                            Optional Key As String, Optional Text As String, _
                            Optional Image As Integer, Optional SelectedImage As Integer) As Node
        控件的增加节点方法, 类似微软Treeview控件中的Nodes.Add方法, Relative参数指定相关的节点,可以是序号,关键字或ID
        Relationship参数指定关联节点的关系,枚举类型, 可以指定是子节点,下一节点或下一节点等
        可选Key是节点的关键字, 如果节点有关键字,可以根据这个Key用Item属性得到这个节点
        Text是节点文本, Image是节点的图标序号, SelectedImage是节点选中时的图标序号
2        Public Sub RemoveNode(Index As Variant)
        删除一个节点, Index参数可以是序号,关键字或ID
3        Public Sub Clear()
        清除整个控件的节点
4        Public Sub Refresh()
        控件强制进行刷新
5        Public Function FindNode(sText As String, Optional SearchInSubText As Boolean = True, Optional Compare As VbCompareMethod = vbBinaryCompare) As Node
        查找节点的方法,sText参数是要查找的文本,可选参数指定查找范围是否包括子文本(多列文本)以及是否大小写敏感
6        Public Function HitTest(ByVal X As Single, ByVal Y As Single) As Node
        判断在X,Y坐标下是哪个节点, 参数为横竖坐标, 单位是磅
7        Public Sub StartLabelEdit(nodX As Node, Optional ByVal Col As Long = 1)
            启动节点编辑,nodX指定编辑的节点, Col指定编辑是文本的第几列. (此功能未编写)
8        Public Function GetTreeString(Optional Index As Variant, Optional OutputInfo As OutputInfoEnum, Optional Title As Boolean = True) As String
        得到节点树的字符串,Index指定节点,OutputInfo指定字符串包含什么信息,Title指定字符串开始是否包含标题
9        Public Sub PrintViewTree()
        打印可见的树在调试窗口中, 调试用
10        Public Function NewEnum() As IEnumVARIANT
        集合枚举函数, 你不会直接用到, 这个函数是让你可以使用For…Each…Next这样的句式, 语言碰到这样的句式时会
        生成一个枚举类,然后每次调用枚举类的Skip,Move等方法.
        这个函数应该隐藏起来, 但我即使设置了隐藏属性也不顶用, 有谁知道方法吗?
       
cTreeview类的事件       
1        Public Event ColumnClick(ByVal Col As Long)
        事件在点击列时触发, 参数是第几列
2        Public Event BeforeLabelEdit(ByRef Cancel As Boolean)
        事件在节点开始编辑时触发, Cancel参数返回True可以阻止节点进入编辑状态
3        Public Event AfterLabelEdit(ByRef Cancel As Boolean, ByVal NewString As String)
        事件在节点结束编辑并在保存前时触发, Cancel参数返回True可以阻止节点保存编辑,NewString是新编辑的文本
4        Public Event Click()
        事件在点击控件时触发
5        Public Event DblClick()
        事件在双击控件时触发
6        Public Event Collapse(nodX As Node)
        事件在节点收缩时发生,nodX是收缩的节点
7        Public Event Expand(nodX As Node)
        事件在节点展开时发生,nodX是展开的节点
8        Public Event NodeCheck(nodX As Node)
        事件在节点的Checkbox被点击时发生, nodX是被点击的节点
9        Public Event NodeClick(nodX As Node, ByVal Col As Long)
        事件在节点被点击时发生, nodX是被点击的节点,Col是被点击第几列
10        Public Event NodeRightClick(nodX As Node, ByVal Col As Long)
        事件在节点被右击时发生, nodX是被右击的节点,Col是被点击第几列
11        Public Event NodeDblClick(nodX As Node, ByRef Toggle As Boolean)
        事件在节点被双击时发生, nodX是被双击的节点,Toggle参数返回False可以阻止节点展开或收缩
12        Public Event NodeChanged(nodX As Node)
        节点改变文本,前景色,背景色,加粗,图标…时触发
13        Public Event SelectedNodeChanged()
        选定节点改变时触发
14        Public Event KeyDown(ByRef KeyCode As Integer, ByRef Shift As Integer)
15        Public Event KeyPress(ByRef KeyAscii As Integer)
16        Public Event KeyUp(ByRef KeyCode As Integer, ByRef Shift As Integer)
        键盘事件, 就不说了
17        Public Event MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
18        Public Event MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
19        Public Event MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
        鼠标事件,也不说了

TA的精华主题

TA的得分主题

 楼主| 发表于 2015-12-7 23:11 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

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

GMT+8, 2024-5-12 14:49 , Processed in 0.039976 second(s), 11 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

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

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

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