使用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名稱要一致,不然循環會出錯。

後續在這個系統上添加對資料庫進行增刪改的功能,未完待續......


推薦閱讀:
相關文章