使用VBA做用户窗体的时候,ListView是经常需要用的一个控制项。

做一个用多个ListView进行联动显示数据的小窗口

本文主要涉及:

  • VBA 编写窗体程序
  • MySQL 存放数据
  • ListView 显示数据

本章需要完成的效果如下:

  • 在ListView1中显示合同和项目的资料,每个合同对应一个项目
  • 在ListView2中显示型号的资料,每个合同对应多个型号
  • 在ListView3中显示负责人的资料,每个合同对应多个负责人
  • 当在ListView1中使用滑鼠左键或者上下移动的时候,在下方的文本框,ListView2和ListView3中的数据会跟著对应的合同编号进行变化

前期准备:

1、在资料库中准备4张数据表

2、配置好VBA链接MySQL的设置,具体方法请参考之前写的一篇文章

木子-李:使用VBA+ODBC+MySQL实现Excel网路版?

zhuanlan.zhihu.com
图标

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数据过程

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数据过程

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 链接类模块

conn.Open data.模拟数据 调用类模块中的代码,直接打开MySQL资料库

将查询到的rst子集使用循环写入ListView1中

ListView1的数据来自合同和项目表,在VBA中SQL语句看不太清晰,可以先使用Navicat将SQL语句写出来,然后在复制到VBA中

7、编写获取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数据过程

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单击事件

Private Sub ListView1_Click()
ListView1单击事件
ListView2.ListItems.Clear
ListView3.ListItems.Clear
Call 提取ListView1数据
调用过程
获取数据 "型号", ListView2, "型号编号", Dic_型号 ListView2
获取数据 "业绩", ListView3, "负责人编号", Dic_业绩 ListView3
End Sub

10、设置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名称要一致,不然循环会出错。

后续在这个系统上添加对资料库进行增删改的功能,未完待续......


推荐阅读:
相关文章