使用VBA做用户窗体的时候,ListView是经常需要用的一个控制项。
做一个用多个ListView进行联动显示数据的小窗口
本文主要涉及:
本章需要完成的效果如下:
1、在资料库中准备4张数据表
2、配置好VBA链接MySQL的设置,具体方法请参考之前写的一篇文章
3、在VBA插入用户窗体,模块,类模块,并在工具箱中先勾选出ListView控制项
1、在类模块中写入链接MySQL语句
Driver 你的ODBC版本 Server MySQL所在的IP地址 Port 埠号 DB 访问的资料库名称 Uid 访问的用户名 Pwd 访问的密码 Property Get 模拟数据() 模拟数据 = "Driver={MySQL ODBC 8.0 Unicode Driver};" & _ "Server= ;Port=3308;DB=模拟数据;" & _ "Uid= ;Pwd= ;OPTION=3;" End Property
2、在模块中写入几个全局变数,
3、设计用户窗体样式,这里需要注意,TextBox的名称修改成和前面Lable的内容一致,并且也要与资料库中项目和合同表的栏位名相同(统一的格式,便于循环)
项目
合同
4、双击窗体,开始编写代码,在用户窗体出现的时候我们需要初始化一些信息,使用UserForm_Initialize事件
Private Sub UserForm_Initialize() 初始化合Dic_项目字典,Key是标题名称,Item是列宽 Set Dic_项目 = CreateObject("Scripting.Dictionary") With Dic_项目 .Add "项目名称", 100 .Add "项目所在省份", 60 .Add "项目所在城市", 60 .Add "项目所在区域", 80 End With
初始化合Dic_合同字典,Key是标题名称,Item是列宽 Set Dic_合同 = CreateObject("Scripting.Dictionary") With Dic_合同 .Add "项目编号", 60 .Add "评审日期", 120 .Add "合同评审人", 55 .Add "卖方公司", 100 .Add "销售方式", 45 .Add "付款方式", 45 End With
初始化合Dic_型号字典,Key是标题名称,Item是列宽 Set Dic_型号 = CreateObject("Scripting.Dictionary") With Dic_型号 .Add "项目编号", 60 .Add "合同编号", 45 .Add "产品名称", 100 .Add "产品子分类", 60 .Add "产品分类", 60 .Add "产品销售额", 55 End With
初始化合Dic_业绩字典,Key是标题名称,Item是列宽 Set Dic_业绩 = CreateObject("Scripting.Dictionary") With Dic_业绩 .Add "项目编号", 60 .Add "合同编号", 45 .Add "销售部门", 45 .Add "办事处", 80 .Add "项目负责人", 55 End With
初始化ListView1 With ListView1 .ColumnHeaders.Add , , "合同编号", 45 For Each D In Dic_项目.keys .ColumnHeaders.Add , , D, Dic_项目(D), 2 最后一个2表示列内容居中显示 Next For Each D In Dic_合同.keys .ColumnHeaders.Add , , D, Dic_合同(D), 2 最后一个2表示列内容居中显示 Next .View = lvwReport 报表视图 .HideSelection = False 当控制项失去焦点时选择文本加亮显示 .FullRowSelect = True 选择整行 .Gridlines = True 显示网格线 .LabelEdit = lvwManual 不允许编辑第一列 End With 获取ListView1数据
初始化ListView2 With ListView2 .ColumnHeaders.Add , , "型号编号", 45 For Each D In Dic_型号.keys .ColumnHeaders.Add , , D, Dic_型号(D), 2 最后一个2表示列内容居中显示 Next .View = lvwReport 报表视图 .HideSelection = False 当控制项失去焦点时选择文本加亮显示 .FullRowSelect = True 选择整行 .Gridlines = True 显示网格线 .LabelEdit = lvwManual 不允许编辑第一列 End With
初始化ListView3 With ListView3 .ColumnHeaders.Add , , "负责人编号", 55 For Each D In Dic_业绩.keys .ColumnHeaders.Add , , D, Dic_业绩(D), 2 最后一个2表示列内容居中显示 Next .View = lvwReport 报表视图 .HideSelection = False 当控制项失去焦点时选择文本加亮显示 .FullRowSelect = True 选择整行 .Gridlines = True 显示网格线 .LabelEdit = lvwManual 不允许编辑第一列 End With End Sub
因为有很多地方需要用到4个表的标题,所以将其定义成全局变数,然后在窗体出现时初始化内容,后续可以随时调用。
在初始化字典的时候,每个表的主键不需要添加进去。
在初始化ListView列的时候,就可以直接循环字典添加
5、编写提取ListView1数据过程
提取ListView1数据
Sub 提取ListView1数据() 当选中ListView1某一行时,将选中的行内容显示在文本框 With ListView1.SelectedItem Me.Controls("合同编号") = .Text x = 0 For Each D In Dic_项目.keys x = x + 1 Me.Controls(D) = .SubItems(x) Next For Each D In Dic_合同.keys x = x + 1 Me.Controls(D) = .SubItems(x) Next End With End Sub
6、编写获取ListView1数据过程
获取ListView1数据
Sub 获取ListView1数据() 从资料库获取ListView1的数据 Dim conn As New ADODB.Connection Dim rst As New ADODB.Recordset Dim data As New MySQL Dim sql$ conn.Open data.模拟数据 sql = "SELECT 合同.*,项目.项目名称,项目.项目所在省份,项目.项目所在城市,项目.项目所在区域 " sql = sql & "FROM 合同 LEFT JOIN 项目 ON 合同.项目编号 = 项目.项目编号" rst.Open sql, conn 将rst子集循环到ListView1 Do While Not rst.EOF With ListView1.ListItems.Add .Text = rst.Fields("合同编号") x = 0 此处的循环顺序要和初始化的时候一致,先项目,在合同 For Each D In Dic_项目.keys x = x + 1 .SubItems(x) = rst.Fields(D) Next For Each D In Dic_合同.keys x = x + 1 .SubItems(x) = rst.Fields(D) Next rst.MoveNext End With Loop conn.Close: Set conn = Nothing: Set rst = Nothing End Sub
Dim data As New MySQL 链接类模块
Dim data As New MySQL
conn.Open data.模拟数据 调用类模块中的代码,直接打开MySQL资料库
conn.Open data.模拟数据
将查询到的rst子集使用循环写入ListView1中
ListView1的数据来自合同和项目表,在VBA中SQL语句看不太清晰,可以先使用Navicat将SQL语句写出来,然后在复制到VBA中
7、编写获取ListView2数据过程
获取ListView2数据
Sub 获取ListView2数据() 当选中ListView1某一行时,从资料库获取ListView2的数据 Dim conn As New ADODB.Connection Dim rst As New ADODB.Recordset Dim data As New MySQL conn.Open data.模拟数据 rst.Open "SELECT * FROM 型号 WHERE 合同编号 = " & ListView1.SelectedItem.Text & "", conn Do While Not rst.EOF With ListView2.ListItems.Add .Text = rst.Fields("型号编号") x = 0 On Error Resume Next For Each D In Dic_型号.keys x = x + 1 .SubItems(x) = rst.Fields(D) Next rst.MoveNext End With Loop conn.Close: Set conn = Nothing: Set rst = Nothing End Sub
8、编写获取ListView3数据过程
获取ListView3数据
Sub 获取ListView3数据() 当选中ListView1某一行时,从资料库获取ListView3的数据 Dim conn As New ADODB.Connection Dim rst As New ADODB.Recordset Dim data As New MySQL conn.Open data.模拟数据 rst.Open "SELECT * FROM 业绩 WHERE 合同编号 = " & ListView1.SelectedItem.Text & "", conn Do While Not rst.EOF With ListView3.ListItems.Add .Text = rst.Fields("负责人编号") x = 0 On Error Resume Next For Each D In Dic_业绩.keys x = x + 1 .SubItems(x) = rst.Fields(D) Next rst.MoveNext End With Loop conn.Close: Set conn = Nothing: Set rst = Nothing End Sub
写完3个获取ListView数据过程后,发现ListView2和ListView3很相似,只有4处标红的地方不同,那么可以写成带有参数的过程来精简代码。
9、设置ListView1单击事件
ListView1单击事件
Private Sub ListView1_Click() ListView1单击事件 ListView2.ListItems.Clear ListView3.ListItems.Clear Call 提取ListView1数据 调用过程 获取数据 "型号", ListView2, "型号编号", Dic_型号 ListView2 获取数据 "业绩", ListView3, "负责人编号", Dic_业绩 ListView3 End Sub
10、设置ListView1按键事件
ListView1按键事件
Private Sub ListView1_KeyUp(KeyCode As Integer, ByVal Shift As Integer) ListView1按键事件 38和40表示方向键上和下 If KeyCode = 38 Or KeyCode = 40 Then ListView1_Click End If End Sub
加一个判断,当用户按方向键上下的时候,执行单击事件的效果
至此编写完所有代码,一个简易的窗体显示系统完成。总共173行代码,还是比较少的了
在实际运用中可能表的栏位比较多,那么只需要在初始化字典的时候添加进去就OK,
要注意的就是MySQL数据中的栏位名,字典,还有用户窗体中的TextBox名称要一致,不然循环会出错。
后续在这个系统上添加对资料库进行增删改的功能,未完待续......