CÔNG TY CỔ PHẦN BLUESOFTS

Lập trình Userform-VBA tạo mục nhập có danh sách tìm kiếm với BSSearchEngine - Add-in A-Tools

Nhập liệu nâng cao trong Add-in A-Tools cho phép tìm và lọc trên sheet. Từ phiên bản v10.1 cho phép người dùng lập trình với class BSSearchEngine để tạo cửa sổ tìm kiếm này với điều khiển - control trên Userform. Tốc độ nhanh dù hàng trăm ngàn dòng. BSSearchEngine cung cấp phong phú các thủ tục, thuộc tính, sự kiện để tùy biến giao diện và hành động.
 
Khi cài A-Tools bạn mở tập tin tại đường dẫn dưới đây để xem mã nguồn ví dụ đầy đủ:
(*) File mã nguồn ví dụ: "C:\A-Tools\HELP & DEMOS\A-Tools VBA Programming\BSSearchEngine - Create DropDown List on control\BSSearchEngine - DropDown List.xlsm"

Chủ đề này tôi sẽ hướng dẫn từng bước lập trình từ cơ bản đến nâng cao với BSSearchEngine để tạo tính năng tìm và lọc với control trên Userform giống như chức năng Nhập liệu nâng cao trên sheet.
 
Video phần 01 - Tạo mục tìm và lọc đơn giản
 

 
Dòng lệnh tối thiểu để tạo cửa sổ tìm và lọc với control
 
+ Bước 1: Nhúng thư viện AddinATools.dll
 
Trong cửa sổ lập trình VBA, chọn Project bạn muốn lập trình, vào menu Tools -> References... tick chọn "AddinATools.dll"

+ Bước 2: Tạo Userform và chèn một control TextBox
 
Control phục vụ để nhập liệu là TextBox. Bạn có thể sử dụng các control ComboBox, BSEdit hoặc control nào cho phép nhập liệu.
 
 
Nhấp đúp chuột vào Userform - Vào chế độ soạn thảo code trong Userform. Copy đoạn code dưới đây dán vào.

Private Sub UserForm_Initialize() 
   Set SE_MAHH = New BSSearchEngine  'Khởi tạo BSSearchEngine
   SE_MAHH.Create txtMAHH, Range("DMHH")  'Nhập thông tin cho BSSearchEngine
   SE_MAHH.BoundColumn = 1  'Ngầm định là 1 - Chỉ ra vị trí cột giá trị lấy về control
   'EditControl: TextBox, ComboBox, BSEdit, Handle to Edit
   'DataSource: Excel Range (high speed!)
   ' Array2D
   ' ADODB.Recordset
End Sub 
'Sự kiện nhận giá trị chọn từ danh sách. Lấy giá trị trong mảng điền vào các control khác.
Private Sub SE_MAHH_OnAfterUpdate(RowIndex As Variant, Values As Variant, ByVal Text As String) 
   lblTenHH.Caption = Values(1, 2)  'Tên hàng
   txtDVT.Text = Values(1, 4)  'Ðơn vị tính
End Sub 
 
Giải thích mã nguồn
 
+ BSSearchEngine: là class thực hiện tìm và lọc dữ liệu khi thay đổi dữ liệu trên control nhập liệu.

Sub BSSearchEngine.Create(EditControl, DataSource, [DataHasHeaderRow As Boolean = True], [ShowHeader As Boolean = True]) 
Create() là thủ tục nạp các thông tin cho điều BSSearchEngine. Các tham số là:
    EditControl: có thể là: Handle of the editor control; BSAC.BSEdit Control; MSForms.TextBox, MSForms.ComboBox
    DataSource: có thể là Excel Range, Array2D, ADODB.Recordset
    DataHasHeaderRow: ngầm định là True, chỉ ra dữ liệu nguồn có dòng tiêu đề.
    ShowHeader: ngầm định là True, chỉ ra cửa sổ tìm kiếm hiển thị dòng tiêu đề không.
 
Trong mã nguồn:

SE_MAHH.Create txtMAHH, Range("DMHH")

Control txtMAHH sẽ được kích hoạt cửa sổ tìm kiếm và lọc, dữ liệu nguồn tại vùng NAME "DMHH" - Range("DMHH")
 
+ BSSearchEngine.BoundColumn: là số nguyên, ngầm định là 1 chỉ ra vị trí cột trong dữ liệu nguồn giá trị được lấy về control nhập liệu.
 
Muốn tương tác lệnh trong khi thực hiện các hành động thì phải lập trình sự kiện cho BSSearchEngine. 
Sự kiện OnAfterUpdate() chạy ngay sau khi giá trị được cập nhật vào control. Cấu trúc sự kiện là
Sub OnAfterUpdate(RowIndex, Values, Text As String) 

+ RowIndex: là mảng 1D chứa tạo độ các dòng được chọn.
+ Values: là mảng 2D chứa giá trị đã chọn từ danh sách.
+ Text: là chuỗi được nhập vào control.
 
Nếu bạn muốn chọn và nhận về sự kiện này nhiều dòng thì phải khai báo thuộc tính MultiInputColumns. 
 
+ BSSearchEngine.MultiInputColumns = True cho phép chọn và nhận về nhiều dòng giá trị. 
 
Kết quả khi chạy
 
 
Thay đổi màu sắc của từng dòng trong cửa sổ tìm và lọc của Nhập Liệu Nâng Cao trên Userform.

Để thay đổi màu trên nhập liệu nâng cao chúng ta dùng các thuộc tính, RowColor1, RowColor2:
BSSearchEngine.RowColor1: nhận màu dòng lẻ, giá trị là chuỗi hexa color hoặc kiểu Long trả về bởi hàm RGB.
BSSearchEngine.RowColor2: nhận màu dòng chẵn, giá trị là chuỗi hexa color hoặc kiểu Long trả về bởi hàm RGB.

Mã nguồn VBA như sau:

Option Explicit 
Private WithEvents SE_DATA As BSSearchEngine 
Private Sub UserForm_Initialize() 
   Set SE_DATA = New BSSearchEngine 
   SE_DATA.Create txtSearch, Range("KHO") 
   SE_DATA.BoundColumn = 12  'Lay cot ROW
   SE_DATA.RowColor1 = RGB(250, 210, 198)  ' or "#FAD2C6" ' Màu dòng lẻ
   SE_DATA.RowColor2 = "#F7B49F"  ' Or RGB(247, 180, 159) ' Màu dòng chẵn
End Sub 

'Sự kiện bắt khi giá trị được nhập - Giá trị lấy từ cột 12 do khai báo BountColumn = 12 

Private Sub SE_DATA_OnAfterUpdate(RowIndex As Variant, Values As Variant, ByVal Text As String) If Text <> "" Then If IsNumeric(Text) Then LoatDuLieu Text 'Tai phieu tu sheet "KHO" End If End If End Sub

Kết quả chạy ta được giao diện màu sắc trên cửa sổ BSSearchEngine


Hướng dẫn dùng ADO để lấy dữ liệu bằng câu lệnh SQL

Với giải pháp này bạn có thể lấy dữ liệu từ bên ngoài như SQL Server, MySQL, Oracle, Access, Excel,.... chỉ cần bạn nắm được cấu trúc của ConnectionString. Sau đây là các bước làm và những lưu ý.

+ Bước 1: Trong VBA, vào menu Tools -> References... chọn "Microsoft ActiveX Data Object..." Bạn chọn version nào cũng được.


Bước 2: Mở Userform dán đoạn code dưới đây:

Private cnn As ADODB.Connection 
Private rst As ADODB.Recordset 
Private SE_DMHH As BSSearchEngine 
Private Sub UserForm_Initialize() 
   Dim ExcelFile As String 
   ExcelFile = ThisWorkbook.FullName 
'Setup Recordset - DataSource:
   Set cnn = New ADODB.Connection 
   cnn.ConnectionString = "Provider=Microsoft.ACE.OLEDB.12.0;" & "Data Source=" & ExcelFile & ";" & "Extended Properties=""Excel 12.0 Xml;HDR=YES;IMEX=1""" 
   cnn.Open 
   'Set rst = cnn.Execute("SELECT * FROM DMHH") 'CAUTION: DO NOT USE THIS!
   'Set rst.ActiveConnection = cnn
   Set rst = New ADODB.Recordset 
   'rst.CursorLocation = adUseClient
   rst.Open "SELECT * FROM DMHH", cnn, adOpenStatic  'fine!
   '----------------------------
'Setup Search Engine:
   Set SE_DMHH = New BSSearchEngine 
   SE_DMHH.Create TextBox1, rst 
   '--------------------
End Sub 
'Free memory when close Userform
Private Sub UserForm_Terminate() 
   If Not rst Is Nothing Then 
      rst.Close 
   End If 
   If Not cnn Is Nothing Then 
      cnn.Close 
   End If 
   Set rst = Nothing 
   Set cnn = Nothing 
End Sub 

Bây giờ chạy Userform ta được màn hình như sau:


Lưu ý: việc chạy SQL để lất về Recordset ta có thể dùng lệnh

Set rst = cnn.Execute("SELECT * FROM DMHH")

Nếu bạn chỉ lấy dữ liệu một lần rồi đóng thì hoàn toàn được nhưng Recordset dùng cho BSSearchEngine được đọc đi đọc lại nhiều lần nên lệnh trên không tương thích. Bạn cần tạo Recordset như ví dụ đã nêu, tức phải là:

rst.Open "SELECT * FROM DMHH", cnn, adOpenStatic 
Bài viết sau tôi sẽ trình bày kỹ hơn sự khác nhau khi dùng DataSource là Excel Range, Array2D, Recordset.
 
 
Bài viết tiếp còn nữa ...