VBA中ListView应用1(显示数据)

VBA中ListView应用1(显示数据)

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

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

本文主要涉及:

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

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

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

前期准备:

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表示列内容居中显示
        For Each D In Dic_合同.keys
            .ColumnHeaders.Add , , D, Dic_合同(D), 2     '最后一个2表示列内容居中显示
        .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表示列内容居中显示
        .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表示列内容居中显示
        .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)
        For Each D In Dic_合同.keys
            x = x + 1
            Me.Controls(D) = .SubItems(x)
    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)
            For Each D In Dic_合同.keys
                x = x + 1
                .SubItems(x) = rst.Fields(D)
            rst.MoveNext
        End With
    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)
            rst.MoveNext
        End With
    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)
            rst.MoveNext
        End With
    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