You are on page 1of 100

https://sites.google.

com/site/exl2lab/vba-in-excel

Contents
Bài 0. Kiến thức chung về VBA ....................................................................................... 2
Bài 1. Tạo macro ............................................................................................................... 4
Bài 2. Ghi macro ............................................................................................................... 5
Bài 3. Hộp thoại thông báo .............................................................................................. 6
Bài 5. Workbook, worksheet ........................................................................................... 8
Bài 6. Range, Cells .......................................................................................................... 13
Bài 7. Hàm trong VBA ................................................................................................... 18
Bài 8. Events, Application Object ................................................................................. 25
Bài 9. Function and Sub ................................................................................................. 29
Bài 10. Array ................................................................................................................... 34
Bài 11. Dictionary ........................................................................................................... 40
Bài 12. FileSystemObject ............................................................................................... 46
Bài 13. Collection ............................................................................................................ 63
Bài 14. Hashtable ............................................................................................................ 67
Bài 15. Stack .................................................................................................................... 71
Bài 16. Queue .................................................................................................................. 77
Bài 17. SortedList ........................................................................................................... 81
Bài 18. ArrayList ............................................................................................................ 91

P a g e 1 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 0. Kiến thức chung về VBA


VBA (Visual Basic for Applications) là ngôn ngữ lập trình trong môi trường Office và một
số phần mềm khác. Ở phạm vi Exl2Lab chỉ giới thiệu về VBA trong Excel.

Giao diện cửa sổ VBA:


Có hai cách mở cửa sổ VBA.
Cách 1: Tại bảng tính Excel, nhấn tổ hợp phím Alt + F11.
Cách 2: Click Menu Ribbon / Developer / Visual Basic

* Cách làm hiện menu Developer trên ribbon:


Ở cửa sổ Excel vào Menu File/ Options. Tại sửa sổ Excel Options tới mục Customize Ribbon,
danh sách Main Tabs bên trái thì check mục Developer. Click OK.
1. Định dạng file Excel - Macro
Các định dạng file Excel cho phép chứa marco, gồm: *xls, *xla (Excel 2003 trở xuống), *.xlsm,
*.xlsb, *.xlam (Excel 2007 trở lên).
Chú thích: Với định dạng file *.xlsb cho file dung lượng nhỏ gọn, mở file nhanh.

2. Nơi đặt các macro (viết code ở đâu?)


(1) UserForm: Form (mẫu) giao diện người dùng thiết kế, và tất nhiên trong đó có các code để
thực thi các yêu cầu;
(2) Module: Là nơi thường được đặt các macro ở đây: Các thủ tục (Sub), hàm (Function). Tức là
những thư viện dùng chung;
(3) Class Module: Dùng để tạo ra các đối tượng (Object), mô tả thuộc tính, phương thức... của
đối tượng được tạo ra;
(4) Worksheet: Thường đặt các thủ tục liên quan tới sự kiện của worksheeet (Sub_Change);
(5) Workbook: Thường đặt các thủ tục liên quan tới sự kiện của workbook.

3. Cách chèn một module


Mở cửa sổ VBA (Nhấn tổ hợp phím Alt + F11).
Menu Insert, Module

P a g e 2 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

4. Macro setting
Thiết lập bảo mật cho macro:
Trên menu Developer, click Macro Security (hoặc Excel Options > Trust Center > Trust Center
Settings... > Macro Settings).
Ở mục Macro Setting có 4 lựa chọn:
1/ Vô hiệu hóa mọi macro và không thông báo.
2/ Vô hiệu hóa mọi macro và kèm theo thông báo.
3/ Vô hiệu hóa mọi macro ngoại trừ những macro được ký điện tử.
4/ Cho phép tất cả các macro (không được khuyến cáo, các mã nguy hiểm có thể được chạy).
5. Protect macro
Để bảo vệ code được bí mật, bạn thiết lập mật khẩu bảo vệ cho Project của VBA.
Tại giao diện của VBA, vào Tools, VBAProject Properties...
Cửa sổ VBAProject Properties, tới tab Protection:
- Check dòng Lock project for viewing
- Nhập mật khẩu vào khung Password và Confirm password.
Click OK

6. Nhận biết thuộc tính và phương thức của một đối tượng.
7. Một số thủ thuật
- Dùng MsgBox để kiểm tra kết quả tại dòng code bất kỳ.
- Dùng chức năng Step Into (nhấn phím F8) để kiểm tra từng dòng code.
- Dùng cửa sổ Immediate (Ctrl + G) để kiểm tra nhanh kết quả của một dòng code.

P a g e 3 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 1. Tạo macro


>> Download: File Tao macro
1. Tạo một nút lệnh (Button) trên trang tính Excel
Có 3 cách sau:
Cách 1:
- Từ menu Developer, Insert, chọn Button (1-Form Controls)
- Kéo chuột vẽ một button lên trang tính. Được "Button 1"
Cách 2:
- Từ menu Developer, Insert, chọn Command Button (2-ActiveX Controls)
- Kéo chuột vẽ một button lên trang tính. Được "CommandButton1"
Cách 3: (Sử dụng bất kỳ đối tượng nào (Object) trên trang tính làm nút lệnh, có thể là 1 hình
ảnh/ line/ textbox/ block hình sao...)
- Ở đây, ta vẽ một hình chữ nhật.
Vào menu Insert, Shapes, Rectangle. Vẽ một hình chữ nhật lên trang tính, rồi nhập text cho
Rectangle: "Nút lệnh"

2. Gán một macro cho nút lệnh


- Với nút lệnh được tạo theo cách 1 & 3: Click phải chuột vào nút lệnh, chọn Assign Macro...
Cửa sổ hiện ra, chọn tên macro muốn gán vào nút lệnh theo danh sách macro, click OK.

- Với nút lệnh tạo theo cách 2:


Click phải chuột vào nút CommandButton1 (Lưu ý: Design Mode trên Developer phải được
kích hoạt), chọn View Code.
Cửa sổ VBA hiện ra, nhập các dòng lệnh cho nút lệnh đó. Sau đó đóng cửa sổ VBA lại. Hủy
chế độ Design Mode và click CommandButton1.
Private Sub CommandButton1_Click()
'Nhập lệnh ở đây.
End Sub

3. Chèn một module


- Mở cửa sổ VBA, vào menu Insert, chọn Module.
- Click chọn vào module vừa chèn, ở cửa sổ Properties phía dưới (nhấn F4 nếu chưa thấy cửa sổ
Properties) rồi đặt tên cho module.
- Vùng bên phải viết code cho module.
Sub Hello()
MsgBox "Hello! Exl2Lab.", , "Msg box"
End Sub

P a g e 4 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 2. Ghi macro


>> Download: Record Macro

Ghi macro (Record Macro) là một công cụ rất hữu ích trong Excel VBA, nó ghi lại mọi thao
tác của bạn trên bảng tính Excel.
Bạn chỉ cần ghi lại một tác vụ (một hoặc nhiều thao tác) thực hiện với bảng tính Excel. Tiếp
đó, bạn gán nó (assign macro) vào một nút lệnh rồi click nút lệnh đó để lặp lại tác vụ vừa được
ghi.
Mặt khác, khi bạn không rõ, không biết tạo một chương trình (tác vụ) cụ thể trong VBA thì
bạn hãy sử dụng chức năng ghi macro. Sau khi bạn ghi macro xong, bạn có thể vào cửa sổ
VBA để xem chi tiết macro đó.
Tuy nhiên, macro được tạo ra bởi việc ghi macro cũng có nhược điểm. Đó là, macro đó áp
dụng cụ thể với trường hợp bạn vừa thao tác và ghi lại, câu lệnh chưa tối ưu, không áp dụng
được vùng dữ liệu khác... nên cần phải hiệu chỉnh với mục đích cụ thể.
Cách thực hiện:
- Trên menu Developer, click nút Record Macro.
- Cửa sổ Record Macro hiện ra. Đặt tên cho macro, thiết lập phím tắt để chạy (Run) macro,
thiết lập nơi hiệu lực của macro, miêu tả...
Rồi click OK.

- Khi đó chức năng Record Macro bắt đầu hoạt động, nhiệm vụ của bạn khi đó là thực hiện các
thao tác cần ghi lại trên bảng tính Excel.
Sau khi thao tác xong, bạn click nút Stop Recording trên menu Developer để kết thúc việc ghi
macro.
(Ví dụ ở đây, ta nhập số thứ tự từ 1 tới 5 vào các ô [A2:A6])
- Để xem code mà macro vừa được ghi lại, bạn vào cửa sổ VBA (nhấn Alt+F11)
- Để gán macro vừa được ghi vào nút lệnh, ta chèn một shape hình chữ nhật rồi assign macro
"Macro1" vào.
- Chạy thử Macro1: Xóa vùng dữ liệu ở [A2:A6] rồi click vào nút lệnh vừa tạo)
(Tham khảo file đính kèm ở cuối bài viết).

P a g e 5 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 3. Hộp thoại thông báo


>> Download: Msgbox | InputBox
1. MsgBox:
Hộp thoại thông báo msgbox trong VBA dùng để tạo thông báo thông tin nào cho người dùng
khi cần thiết.
Cấu trúc của hàm msgbox trong VBA:
MsgBox(Prompt, [Buttons As VbMsgBoxStyle], [Title], [HelpFile], [Context]) As
VbMsgBoxResult
Chú thích:
Prompt: Bắt buộc (phải có). Là nội dung của hộp thoại thông báo. Chiều dài tối đa
của Prompt là 1024 ký tự. Nếu nội dung hộp thoại thông báo có nhiều dòng, để tách dòng bạn
có thể dùng các ký tự tách dòng, gồm: Chr(13), Chr(10) hoặc từ khóa vbNewline.

Buttons: Không bắt buộc. Là hằng số quy định cụ thể số lượng và loại các nút hiển thị. Nếu
không sử dụng, giá trị mặc định là số 0.

Title: Không bắt buộc. Là chuỗi được hiển thị trên thanh tiêu đề của hộp thoại. Nếu bỏ qua, tên
ứng dụng được đặt trong thanh tiêu đề (ở đây, cụ thể ở đây là "Microsoft Excel").
HelpFile: Không bắt buộc. Chuỗi xác định tên tập tin trợ giúp sử dụng để cung cấp các trợ giúp
theo ngữ cảnh cho các hộp thoại.
Context: Không bắt buộc. Là số thứ tự tình huống trong HelpFile. Nếu HelpFile có thì Context
phải có.
VbMsgBoxResult:

Câu lệnh đơn giản như sau:


MsgBox "Nội dung thông báo."
Ví dụ 1:
Sub msgbox1()
MsgBox "Xin chào!"
End Sub

Có thể nối nội dung thông báo với nội dung trên bảng tính.
Ví dụ 2: Với [A1]="Exl2Lab"
Sub msgbox2()
MsgBox "Xin chào! " & Sheet1.Range("A1")
End Sub

Để tạo thông báo có nhiều dòng (xuống dòng trong bảng thông báo) ta dùng từ
khóa vbNewLine.
Ví dụ 3:
Sub msgbox3()
MsgBox "Xin chào! " & Sheet1.Range("A1") & vbNewLine & "Email: " &
Sheet1.Range("A2")
End Sub

Ngoài ra, msgbox thường hay dùng để kiểm tra kết quả từng đoạn code khi viết, để tạo thông
báo nhắc người dùng xác nhận trước một tác vụ quan trọng (như xóa dữ liệu, in ấn...).
Ví dụ 4:

P a g e 6 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Sub mgbDelete()
Dim ans As Integer
ans = MsgBox("Ban muon xoa du lieu tren sheet nay?", vbYesNo + vbQuestion, "Xoa du lieu")
If ans = vbYes Then
'Chọn Yes thì thực hiện tác vụ
Cells.ClearContents
Else
'không làm gì
End If
End Sub

Chi tiết các ví dụ xem file đính kèm ở cuối bài.

2. InputBox:

Cấu trúc hàm InputBox:


InputBox(Prompt,[Title],[Default],[Xpos],[Ypos],[HelpFile,Context]) As String
Chú thích:
Prompt: Bắt buộc. Là nội dung hiển thị ở trong hộp thoại thông báo, tối đa 1024 ký tự. Để
muốn xuống dòng trong hộp thoại thông báo thì dùng ký tự đặc biệt Chr(10) hoặc Chr(13) hoặc
dùng vbNewLine chèn vào giữa các dòng.
Title: Không bắt buộc. Là tiêu đề của hộp thoại thông báo, nếu để trống thì tiêu đề là tên ứng
dụng (ở đây là "Microsoft Excel").
Default: Không bắt buộc. Là giá trị mặc định nhập sẵn trong ô để người dùng nhập nội dung
cần thông báo vào.
XPos: Không bắt buộc. Là khoảng cách (đơn vị pixels) theo phương X (phương ngang) tính từ
mép trái màn hình hiển thị. Nếu để trống (không nhập) giá trị này thì hộp thoại sẽ hiển thị ở
giữa theo phương ngang.
YPos: Không bắt buộc. Là khoảng cách (đơn vị pixels) theo phương Y (phương đứng) tính từ
mép trên màn hình hiển thị. Nếu để trống (không nhập) giá trị này thì hộp thoại sẽ hiển thị ở
giữa theo phương đứng.
HelpFile: Không bắt buộc.Là chuỗi xác định tệp trợ giúp sẽ được sử dụng để cung cấp hỗ trợ
giúp ngữ cảnh cho hộp thoại thông báo.
Context: Không bắt buộc. Một số để xác định số ngữ cảnh trợ giúp được ngữ cảnh trợ giúp gán
cho chủ đề thích hợp. Nếu ngữ cảnh được cung cấp thì cũng phải cung cấp tài liệu trợ giúp
(HelpFile).
Ví dụ: Chi tiết xem file đính kèm ở cuối bài.
Sub Vidu_Iputbox()
Dim inBox As String
inBox = InputBox("Chon:" & vbNewLine & "1-Yes" & vbNewLine & "2-No", "Tieu de Input
Box", 1)
If inBox = "1" Or inBox = "2" Then
MsgBox "Day la gia tri vua chon: " & inBox, , "Thong bao"
Else
MsgBox "Chon sai!", , "Thong bao"
End If
End Sub

P a g e 7 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 4. Biến trong VBA


>> Download: Dim | Public | Private | Static

1. Các kiểu dữ liệu


(Tham khảo)

2. Khai báo biến và đặt tên biến trong VBA

- Mỗi chương trình ứng dụng thường xử lý nhiều dữ liệu, ta dùng khái niệm "biến" để lưu trữ dữ
liệu trong bộ nhớ máy tính, mỗi biến lưu trữ một dữ liệu của chương trình.
- Mặc dù VBA không yêu cầu (*), nhưng ta nên định nghĩa rõ ràng từng biến trước khi truy xuất
nó để code của chương trình được rõ ràng, dễ hiểu, dễ bảo trì và phát triển.

- Định nghĩa 1 biến là :


• Định nghĩa tên nhận dạng cho biến,
• Kết hợp kiểu với biến để xác định cấu trúc dữ liệu của biến,
• Định nghĩa tầm vực (phạm vi) truy xuất biến.

- Cú pháp đơn giản của lệnh định nghĩa biến:


[Static|Public|Private|Dim] AVariable [As Type]
+ Static, Public, Private, Dim (**): Các từ khóa để khai báo một biến.
+ Avariable: Tên biến cần khai báo.
Tại từng thời điểm, biến chứa một giá trị (nội dung) cụ thể. Theo thời gian nội dung của biến sẽ bị
thay đổi theo tính chất xử lý của code.

- Cách đặt tên cho một biến :


• Tên biến có độ dài tối đa 255 ký tự
• Ký tự đầu tiên phải là một ký tự chữ (letter), không phải ký tự số (0-9)
• Các ký tự tiếp theo có thể là các ký tự chữ (letter), ký số (digit), dấu gạch dưới
• Tên biến không được chứa các ký tự đặc biệt như các ký tự : ^, &, ), (,%, $, #, @, !, ~, +, -, *,

• VBA không phân biệt chữ HOA hay chữ thường trong tên biến.

Ví dụ:
Tên biến hợp lệ Tên biến không hợp lệ
Bien1_dong Bien-1: Vì có dấu gạch ngang
KhoiLuong Bien&1: Vì có ký tự &
1Bien_dong: Vì có ký tự số ở đầu

Các lưu ý khi đặt tên biến:


- Nên chọn tên biến ngắn gọn nhưng thể hiện rõ ý nghĩa.
Ví dụ: Ta muốn có một biến để lưu mã khác hàng thì có thể đặt: MaKH

- Khi viết tên biến ta nên viết hoa chữ đầu tiên của một từ có ý nghĩa.

Ví dụ: Đặt tên biến xác định khối lượng, số tiền: Kluong, SoTien

P a g e 8 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

- Không được dùng tên biến trùng với các từ khoá như: Print, Sub, End… (từ khóa là những từ mà
ngôn ngữ VBA đã dùng cho những thành phần xác định của ngôn ngữ).
+ As: Từ khóa, gán với kiểu dữ liệu nào cho biến.
+ Type: Kiểu dữ liệu cần gán cho biến đang khai báo. Nếu bỏ qua [As Type] thì biến đó mặc định
nhận kiểu dữ liệu Variant.

Chú thích (*): Có hay không bắt buộc khai báo biến trong VBA
- Khi ở trên cùng trong các môi trường VBA Project (Worksheet, Workbook, Module, Class
module, UserForm) có dòng Option Explicit thì các biến phải được khai báo trước khi sử dụng.
- Hai cách thiết lập Option Explicit:
Một là nhập trực tiếp ở trên cùng của môi trường viết code.
Hai là thiết lập Options trong VBA, yêu cầu khai báo biến (mục Require Variable Declaration
được chọn) thì ở trên cùng trong các môi trường VBA Project (Worksheet, Workbook, Module,
Class module, UserForm) sẽ tự động thêm dòng Option Explicit.

Chú thích (**): Giải thích các từ khóa đứng trước tên biến trong cú pháp khai báo biến.
[Static|Public|Private|Dim] AVariable [As Type]
Public, Private, Static là các từ khoá dùng để xác định phạm vi (tầm vực) của một vật thể
(variable, sub, or function).
Phạm vi/ tầm vực có hai tính chất: tính chất "có thể thấy được" và tính chất "tồn tại".
- Tồn tại: Chỉ áp dụng cho biến (variable), không tồn tại có nghĩa là chưa được thiết lập, hoặc đã
bị huỷ.
- Có thể thấy được: Áp dụng cho mọi loại (variable, sub, or function). Tùy theo cách khai báo mà
vật thể có thể thấy được trong một phạm vi nhưng lại bị che khuất trong phạm vi khác. Lưu ý là
vật thể có thể vẫn tồn tại, chỉ ở ngoài phạm vi thì không chạm được tới nó mà thôi.
Ở nội dung phần này, ta chỉ xét tới variable.

• Public: phạm vi toàn cục, ở đâu trong workbook cũng có thể thấy / dùng được. Tuy nhiên, nếu nó
được khai báo trong module mức thấp thì qua mức cao hơn có thể phải thêm tên của module vào
đầu để VBA biết nó ở đâu mà tìm.(TenModule.TenBien)
- Cấu trúc:
Public AVariable [As Type]
- Tồn tại: Biến chỉ giải phóng khi thoát file.
- Vị trí:
Để ngoài Sub/Function, trên cùng của môi trường VBA Project (Worksheet, Workbook, Module,
Class module, UserForm).

• Private: phạm vi nội bộ khi xét cả VBAProject, nó khai báo trên cùng module thì nó là toàn cục
của module đó, các code trong module đó đều thấy nó.
- Cấu trúc:
Private AVariable [As Type]
- Tồn tại: Biến chỉ giải phóng khi thoát file.
- Vị trí:
Để ngoài Sub/Function, trên cùng của môi trường VBA Project (Worksheet, Workbook, Module,
Class module, UserForm).

• Dim: Khai báo biến ở phạm vi toàn cục trong môi trường được khai báo (để ở ngoài Sub/
Function, trên cùng module) nhưng là phạm vi nội bộ khi xét cả VBAProject, hoặc nội bộ trong
Sub/ Function.

P a g e 9 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

- Cấu trúc:
Dim AVariable [As Type]
- Tồn tại: Biến giải phóng khi thoát file (phạm vi toàn cục của module), giải phóng khi thoát
Sub/Function (phạm vi nội bộ của Sub/Function).
- Vị trí:
+ Để ở ngoài Sub/ Function: Khai báo biến ở phạm vi toàn cục của môi trường khai báo.
+ Khai báo trong Sub/ Function: Phạm vi nội bộ của Sub/Function.

• Static: Khai báo biến ở phạm vi nội bộ trong Sub/ Function.


Cấu trúc:
Static AVariable [As Type]
- Tồn tại: Biến chỉ giải phóng khi thoát file.
- Vị trí: Chỉ đặt trong Sub/Function.

*** Ghi chú: Về vùng nhớ của chương trình

- Trong chương trình có 2 vùng bộ nhớ, vùng heap và vùng stack. Biến khai báo toàn cục thuộc về
heap và biến khai báo nội bộ Sub/Function là biến thuộc về stack. Các vật thể nằm trong vùng
stack sẽ bị huỷ sau khi Sub/Function Exit hoặc End. Riêng biến Static thì luôn thuộc về heap bất
kể nó là Public hay Private. Vì vậy biến Static không bị huỷ khi Sub/Function thoát.

- Phạm vi/tầm vực của heap và stack:


Heap là vùng nhớ chung của chương trình. Khi chương trình còn chạy thì những gì nằm trong
heap còn tồn tại.
Stack là vùng nhớ riêng của mỗi function/sub. Khi chương đang ở trong function/code thì những
gì trong stack còn tồn tại. Khi thoát function/sub thì những gì trong stack (của function/sub này) bị
huỷ hết.

- Tất cả các kiểu khai báo biến, kể cả Public hay Static thì biến đều được giải phóng khi code bị
bất cứ lỗi nào và dừng chương trình.

P a g e 10 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 5. Workbook, worksheet


>> Download: Workbook Object | Worksheet Object | Ví dụ phương thức Open_Close

Sơ đồ dạng phả hệ (dạng cây - TreeView) các đối tượng trong VBA:

1- Application (Microsoft Excel)


2- Workbook (Excel file)
3- Worksheet
4- Range

1. Đối tượng Workbook


Theo trên, workbook là đối tượng cấp 2 của Application (Microsoft Excel).
MsgBox ThisWorkbook.Parent Result: Microsoft Excel
Ví dụ:
Sub vidu1()
Range("A1").Value = "Xin chao!"
End Sub

Tức là đang hiểu (viết đầy đủ):


Sub vidu2()
Application.ThisWorkbook.Worksheets(1).Range("A1").Value = "Xin chao!"
End Sub

- Một số thuộc tính và phương thức thường dùng:

Workbooks.Open(filepath): Mở workbook mới, với filepath là đường dẫn của file cần mở.
Ví dụ: Workbooks.Open("C:\Users\Administrator\Desktop\Vidu.xlsx")

Workbooks.Add: Tạo mới workbook.

ActiveWorkbook.CodeName: Tên workbook trong VBA.


ThisWorkbook.Name: Tên workbook để quản lý tập tin (tên file).

ThisWorkbook.Path: Đường dẫn chứa workbook.

ThisWorkbook.FullName: Tên workbook bao gồm cả đường dẫn chứa nó.

ThisWorkbook.Save: Lưu các thay đổi đã tác động lên workbook.

ThisWorkbook.Close True '(SaveChanges = True): Đóng workbook và lưu các thay đổi đã tác
động lên workbook.

ThisWorkbook.Close False '(SaveChanges = False): Đóng workbook và không lưu các thay đổi
đã tác động lên workbook.
(Tham khảo file đính kèm ở cuối bài viết).
2. Đối tượng Worksheet
Trong VBA, khi xét tới đối tượng Worksheet thì nó là đối tượng cấp 3 (sau Workbook).
(Xem lại ví dụ ở phần đối tượng workbook ở trên.)

P a g e 11 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

- Có 3 cách để gọi (tham chiếu tới) đối tượng worksheet:

Cách 1: Sử dụng worksheet name – Là tên của bảng tính nhìn thấy ở dưới thanh trạng thái
(Sheet Tab).
Sub wsName()
Worksheets("Ten sheet 1").Range("A1").Value = "Xin chao!"
'Hoac co the viet sheets thay cho worksheets
Sheets("Ten sheet 1").Range("A2").Value = "Xin chao!"
End Sub

# Cách 2: Sử dụng thứ tự sắp xếp của worksheet ở sheet tab, tính từ trái qua phải, vị trí đầu tiên
là 1
Sub wsIndex()
Sheets(1).Range("B1").Value = Sheets(1).Name & "-Vi tri=" & Sheets(1).Index
Sheets(2).Range("B1").Value = Sheets(2).Name & "-Vi tri=" & Sheets(2).Index
End Sub

# Cách 3: Sử dụng CodeName của worksheet, là tên của worksheet trong VBA
Sub wsCodeName()
Sheet1.Range("B2").Value = Sheets(1).Name
Sheet2.Range("B2").Value = Sheets(2).Name
Sheet1.Range("C1").Value = Sheet1.CodeName
Sheet2.Range("C1").Value = Sheet2.CodeName
End Sub

- Một số phương thức và thuộc tính thường dùng:

.Count: Đếm số worksheets có trong một workbook


MsgBox Worksheets.Count

.Activate: Kích hoạt worksheet được chỉ định


Sheet1.Activate

.Select: Chọn worksheet được chỉ định


Sheet1.Select

Gọi tới đối tượng của worksheet:


.Cells
.Range
.Rows
.Columns

P a g e 12 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 6. Range, Cells


>> Download: Range - Cells Object

Range, cells là 2 đối tượng của worksheets (cells cũng là đối tượng của Range).
1. Đối tượng Range
+ Cấu trúc:
Worksheets.Range(Cell1, [Cell2])
Cell1 là cell đầu tiên trong vùng được gọi tới, tham số bắt buộc.
Cell2 là cell cuối cùng trong vùng được gọi tới, tham số không bắt buộc.
- Range có thể gồm một hoặc nhiều cells.
- Range có thể gồm một hoặc nhiều dòng/ cột, vùng không liên tục:
Ví dụ:
Set Rng1 = Sheet1.Range("A5", "B10")
Set Rng2 = Sheet1.Columns("B:D")
Set Rng3 = Sheet1.Rows("2:5")
+ Các cách viết gọi một range trong VBA:
Range("A5", "B10")
OR:
Range("A5:B10")
OR:
[A5:B10]
*Lưu ý:
- Khi gọi một range ta viết chỉ định cho một worksheet nào đó: Sheet1.Range("A5:B10")
Nếu không viết chỉ định Range("A5:B10") cho một worksheet cụ thể thì sẽ được hiểu Range
đang gán cho worksheet hiện hành ActiveSheet.Range("A5:B10"). Khi Run (khởi chạy) một
Sub (thủ tục) nào đó trong cửa sổ VBA phải đảm bảo worksheet muốn thực hiện Sub đó phải
đang được Active, nếu không sẽ chạy nhầm worksheet; hoặc ta có thể gán Sub đó vào nút lệnh
trên worksheet muốn thực hiện và kích hoạt Sub bằng cách click vào nút lệnh.
2. Đối tượng Cells
+ Cấu trúc:
Worksheets.Cells([RowIndex], [ColumnIndex])
Range.Cells([RowIndex], [ColumnIndex])
- RowIndex: Địa chỉ dòng của cell cần gọi, nếu bỏ qua thì mặc định tham số nhận giá trị là 1.
- ColumnIndex: Địa chỉ cột của cell cần gọi, nếu bỏ qua thì Cells trả về có chỉ số trong Range
được tính từ trái sang phải, từ trên xuống dưới.
- Nếu bỏ qua cả 2 tham số thì trả về toàn bộ Cells trong Range.
Ví dụ:
Sub RngObject()
Dim Rng As Range, Cll As Range, Cll1 As Range
Set Rng = Sheet1.Range("A5:B10")
Set Cll = Sheet1.Cells(1, 1)
Set Cll1 = Rng.Cells(1, 1)
MsgBox Rng.Address & vbNewLine & Cll.Address & vbNewLine & Cll1.Address
End Sub
3. Một số thuộc tính, phương thức thường dùng
3.1. Thuộc tính:
Value / .Value2 / .Text
Xét ví dụ cụ thể bên dưới:

P a g e 13 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Formula / Hasformula
Sub Set_Formula()
Dim Cll As Range, i As Long
Set Cll = Sheet1.Range("C5")
For i = 0 To 5
Cll.Offset(i, 0).Value = i + 10
Next i
Cll.Offset(6, 0).Formula = "=Sum(C5:C10)"
MsgBox Cll.Offset(6, 0).HasFormula
End Sub
Offset
Cú pháp:
Range.Offset([RowOffset],[ColumnOffset])
RowOffset: Số dòng giữa vùng tham chiếu gốc và vùng đích, hướng về phía trên Range
thì RowOffset mang giá trị âm.
Nếu không nhập thì RowOffset=0, cú pháp khi đó: Range.Offset(, ColumnOffset)
ColumnOffset: Số cột giữa vùng gốc và vùng đích, hướng về bên trái Range thì ColumnOffset
mang giá trị âm.
Nếu không nhập thì ColumnOffset=0, cú pháp khi đó: Range.Offset(RowOffset)

Ví dụ:
Sub Offset()
'Range.Offset([RowOffset],[ColumnOffset])'
Dim Cll As Range, Rng As Range
Set Cll = Sheet1.Range("B2")
Set Rng = Sheet1.Range("A5:A10")
MsgBox Cll.Offset(1, 1).Address '$C$3'
MsgBox Cll.Offset(, 2).Address '$D$2'
MsgBox Cll.Offset(2).Address '$B$4'
MsgBox Rng.Offset(1, 1).Address '$B$6:$B$11'
MsgBox Rng.Offset(, 1).Address '$B$5:$B$10'
MsgBox Rng.Offset(2).Address '$A$7:$A$12'
End Sub
Resize
Cú pháp:
Range.Resize([RowSize],[ColumnSize])
RowSize: Số dòng dãn ra so với cell đầu tiên của vùng tham chiếu gốc.
- Nếu không nhập thì RowSize=Range.Rows.Count, cú pháp khi đó: Range.Resize(,
ColumnSize)
ColumnSize: Số cột dãn ra so với cell đầu tiên của vùng tham chiếu gốc.
- Nếu không nhập thì ColumnSize=Range.Columns.Count, cú pháp khi
đó: Range.Offset(RowSize)
Ví dụ:
Sub Resize()
'Range.Resize([RowSize],[ColumnSize])'
Dim Cll As Range, Rng As Range
Set Cll = Sheet1.Range("B2")

P a g e 14 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Set Rng = Sheet1.Range("A5:A10")


MsgBox Cll.Resize(2, 2).Address '$B$2:$C$3'
MsgBox Cll.Resize(, 2).Address '$B$2:$C$2'
MsgBox Cll.Resize(2).Address '$B$2:$B$3'
MsgBox Rng.Resize(3, 3).Address '$A$5:$C$7'
MsgBox Rng.Resize(, 2).Address '$A$5:$B$10'
MsgBox Rng.Resize(2).Address '$A$5:$A$6'
End Sub
Count: Đếm các ô có trong range
Sub CountCells()
Dim Rng As Range
Set Rng = Sheet1.Range("A1:B10")
MsgBox Rng.Count
'Result 20
End Sub
Cell.Row: Trả về địa chỉ dòng của ô được gọi.
Cell.Column: Trả về địa chỉ cột của ô được gọi.
Sub RowColumnOfCell()
MsgBox Sheet1.Range("D20").Row 'Rusult 20
MsgBox Sheet1.Range("D20").Column 'Rusult 4
End Sub
Address: Trả về địa chỉ của vùng được gọi
Sub RngAddress()
MsgBox Sheet1.Range("A2:B9").Address
Result "$A$2:$B$9"
End Sub
Numberformat: Định dạng dữ liệu vùng tham chiếu tới.
Sub FormatRange()
Sheet1.Range("A15").Value = 1000000
Sheet1.Range("A15").NumberFormat = "#,0"
Sheet1.Range("A16").Value = Date
Sheet1.Range("A16").NumberFormat = "dd/mm/yyyy"
End Sub
End: Trả về cell cuối cùng theo hướng chỉ định.
(Nó tương ứng với việc nhấn Ctrl + Up/Down/Left/Right Arrow)
Cú pháp:
Range.End(XlDirection)
Với XlDirection có 4 tham số: xlDown, xlToLeft, xlToRight, xlUp
Sub EndDirection()
Range("G20").End(xlDown).Select
'Tra vê cell duoi cung côt G có du liêu liên tuc, tinh tu G20
'Press: Ctrl + Arrow Down from cell G20
Range("G20").End(xlUp).Select
'Tra vê cell trên cung côt G có du liêu dâu tiên, tinh tu G20
'Press: Ctrl + Arrow Up from cell G20
Range("G20").End(xlToLeft).Select
'Tra vê cell dâu tiên bên trái trên dòng 20 có du liêu, tinh tu G20
'Press: Ctrl + Arrow Left from cell G20
Range("G20").End(xlToRight).Select

P a g e 15 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

'Tra vê cell ngoài cùng bên phai trên dòng 20 có du liêu liên tuc, tinh tu G20
'Press: Ctrl + Arrow Right from cell G20
End Sub
# Ứng dụng thuộc tính End() để xác định dòng cuối cùng có dữ liệu:
Sub LastRow1()
'Tra vê dòng trên cùng có du liêu dâu tiên, xet tu cell duoi cùng bang tinh tro lên
Dim lRow As Long
lRow = Sheet1.Range("A" & Sheet1.Rows.Count).End(xlUp).Row
'Voi Excel 2003-97: Rows.Count=65,536
'Voi Excel 2007 tro len: Rows.Count=1,048,576
MsgBox lRow
End Sub

Sub LastRow2()
'Tra vê dòng duoi cùng có du liêu liên tuc, xet tu cell chi dinh tro xuong
Dim lRow As Long
lRow = Sheet1.Range("A5").End(xlDown).Row
MsgBox lRow
End Sub
3.2. Phương thức:
Select: Chọn vùng
Range("A2:C10").Select
Activate: Kích hoạt cell chỉ định hiện hành
Cells(2,5).Activate
Cells(2,5).Select
Copy: Sao chép vùng dữ liệu, bằng với thao tác chọn vùng dữ liệu rồi nhấn Ctrl + C
Range("A2:C10").Copy
Paste: Dán dữ liệu sau khi sao chép, bằng với thao tác nhấn Ctrl + V
Sub CopyRange()
Range("A1:A3").Select
Selection.Copy
Range("C15").Select
ActiveSheet.Paste
End Sub

'Viêt gon:
Sub CopyRange2()
Range("A1:A3").Copy Range("C15")
End Sub
Clear: Xóa nội dung và định dạng của vùng chỉ định
ClearContents: Chỉ xóa nội dung
ClearFormats: Chỉ xóa định dạng
Sub Clear()
Dim Rng As Range
Set Rng = Sheet1.Range("A1:C30")
Rng.Clear 'Xoa nôi dung va dinh dang
Rng.ClearContents 'Chi xóa nôi dung
Rng.ClearFormats 'Chi xoa dinh dang
End Sub

P a g e 16 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Delete: Xóa vùng, xóa dòng/cột, xóa ô (bằng với thao tác nhấn tổ hợp phím Ctrl và dấu trừ -)
Sub Delete()
Sheet1.Rows("25:30").Delete
Sheet1.Columns("H:K").Delete
End Sub

P a g e 17 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 7. Hàm trong VBA


Các hàm trong VBA:
Lookup/Ref Hàm tìm kiếm, lựa chọn theo tham chiếu >> Download File
Functions
String/Text Hàm xử lý về chuỗi, văn bản >> Download File
Functions
Date/Time Hàm xử lý về ngày/ thời gian >> Download File
Functions
Math/Trig Hàm về Toán học >> Download File
Functions
Logical Functions Hàm logic, cấu trúc lệnh (SELECT CASE, IF- >> Download File
THEN, FOR-NEXT...)*
Information Hàm xử lý thông tin >> Download File
Functions
Data Type Conv. Hàm chuyển đổi kiểu dữ liệu >> Download File
Functions
File/Directory Hàm xử lý về tập tin và thư mục >> Download File
Functions

Lookup/Ref Hàm tìm kiếm, lựa chọn theo tham chiếu


Functions
CHOOSE CHOOSE(position, value1, [value2, ... value_n])
Trả về 1 giá trị từ một danh sách các giá trị dựa trên vị trí chỉ định.
String/Text Hàm xử lý về chuỗi, văn bản
Functions
ASC Asc(String As String) 'As Long'
Trả về một số nguyên (0-255) đại diện cho mã ký tự tương ứng với một ký tự.
ASCW AscW(String As String) 'As Long'
Trả về một số nguyên (0-65535) đại diện cho mã ký tự tương ứng với một ký
tự.
CHR Chr(CharCode as Long)
Trả về ký tự tương ứng với mã ký tự (0-255) chỉ định đưa vào.
CHRW ChrW(CharCode as Long)
Trả về ký tự tương ứng với mã ký tự (0-65535) chỉ định đưa vào.
CONCATENATE string1 & string2 [& string3 & string_n] 'As String
with "&"
Nối các chuỗi lại với nhau thành một chuỗi mới.
FORMAT Format (Expression, [Format ]) 'As String
STRINGS
Định dạng giá trị đưa vào theo định dạng chỉ định.
INSTR InStr([Start],[String1],[String2],[Compare As VbCompareMethod =
vbBinaryCompare]) 'As Long'
Trả về vị trí xuất hiện đầu tiên của chuỗi con trong chuỗi đang xét.
INSTRREV InStrRev(StringCheck As String,StringMatch As String,[Start As Long = -
1],[Compare As VbCompareMethod = vbBinaryCompare]) 'As Long'

P a g e 18 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Trả về vị trí xuất hiện đầu tiên của chuỗi con trong chuỗi đang xét tính từ cuối
chuỗi.
LCASE LCase(String) 'As String
Chuyển chuỗi từ chữ in hoa thành chữ thường.
UCASE UCase(String) 'As String
Chuyển chuỗi từ chữ thường thành chữ in hoa.
LEFT Left(String,Length As Long) 'As String
Trích xuất một chuỗi con từ một chuỗi, bắt đầu từ ký tự đầu tiên bên trái.
LEN Len(Expression) As Long 'As Long
Trả về số ký tự của chuỗi.
LTRIM Ltrim(String) 'As String
Loại bỏ khoảng trắng ở đầu (bên trái) chuỗi đưa vào.
MID Mid(String,Start As Long,[Length]) 'As String
Trích xuất một chuỗi con từ một chuỗi (bắt đầu ở bất kỳ vị trí nào).
REPLACE Replace(Expression As String, Find As String, Replace As String, [Start As
Long = 1], [Count As Long=-1],[Compare As VbComapareMethod =
VbBinaryCompare]) 'As String
Thay thế một chuỗi ký tự trong một chuỗi bởi một tập hợp các ký tự khác.
RIGHT Right(String,Length As Long) 'As String
Trích một chuỗi con từ một chuỗi bắt đầu từ ký tự đầu tiên bên phải.
RTRIM Rtrim(String) 'As String
Loại bỏ khoảng trắng ở cuối (bên phải) chuỗi đưa vào.
SPACE SPACE(Number As Long) 'As String
Trả về chuỗi là các ký tự khoảng trắng, với số lượng ký tự chỉ định đưa vào.
SPLIT Split(Expression As String, [Delimiter], [Limit As Long = -1], [Compare As
VbCompareMethod = vbBinaryCompare]) 'Array1D() As String
Trả về một mảng 1 chiều, gồm các phần tử là các chuỗi con được tách ra từ
chuỗi đưa vào bởi dấu phân cách, chỉ mục cận dưới của mảng luôn bằng 0 cho
dù Option Base 1.
JOIN Join(SourceArray,[Delimiter]) 'As String'
Trả về một chuỗi được ghép từ các phần từ của mảng một chiều SourceArray
bởi dấu phân cách Delimiter.
STR STR(Numer) 'As String
Trả về dạng chuỗi của một số.
STRCOMP StrComp(String1, String2, [Compare As VbCompareMethod =
vbBinaryCompare]) 'As Integer
Trả về kết quả là một số nguyên đại diện cho kết quả so sánh 2 chuỗi.
STRCONV StrConv(String,Conversion As VbStrConv,[LocaleID as Long]) 'As String
Trả về một chuỗi được chuyển sang chữ hoa, chữ thường, in hoa ký tự đầu mỗi
từ hoặc Unicode.
STRREVERSE STRREVERSE(Expression As String) 'As String
Trả về chuỗi mới với các ký tự có thứ tự đảo ngược.
TRIM Trim(String) 'As String
Loại bỏ khoảng trắng ở đầu và cuối của chuỗi.
VAL Val(String as String) 'As Double
Trả về các số được tìm thấy trong một chuỗi.

P a g e 19 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Date/Time Hàm xử lý về ngày/ thời gian


Functions
DATE Date 'As Date
Trả về ngày hiện tại của hệ thống (máy tính).
DATEADD DateAdd(Interval As String, Number As Double, Date) 'As Date
Trả lại một ngày sau đó đã thêm một khoảng thời gian/ ngày nhất định.
DATEDIFF DateDiff(Interval As String, Date1, Date2, [FirstDayOfWeek As
VbDayOfWeek = vbSunday], [FirstWeekOfYear As VbFirstWeekOfYear =
vbFirstJan1]) 'As Long
Trả về sự khác biệt giữa hai giá trị ngày, dựa trên khoảng thời gian được chỉ
định.
DATEPART DatePart(Interval As String, Date, [FirstDayOfWeek As VbDayOfWeek =
vbSunday], [FirstWeekOfYear As VbFirstWeekOfYear = VbFirstJan1]) 'As
Integer
Trả về một phần xác định của một ngày nhất định.
DATESERIAL DateSerial(Year As Integer, Month As Integer, Day As Integer) 'As Date
Trả về một ngày trong năm.
DATEVALUE DateValue(Date As String) 'As Date
Trả về giá trị ngày của chuỗi định dạng kiểu ngày.
DAY Day(Date) 'As Integer
Trả về một ngày trong tháng (một số từ 1-31) từ giá trị ngày tháng đưa vào.
FORMAT DATES Format(Expression, [Format], [FirstDayOfWeek As VbDayOfWeek = vb
Sunday], [FirstWeekOfYear As VbFirstWeekOfYear = vbFirstJan1]) 'As
String
Expression: Giá trị ngày cần định dạng.
HOUR Hour(Time) As Integer
Trả về số giờ (một số từ 0-23) của thời gian đưa vào.
MINUTE Minute(Time) 'As Integer
Trả về số phút (một số từ 0-59) của thời gian đưa vào.
MONTH Month(Date) 'As Integer
Trả về tháng (một số từ 1-12) của giá trị ngày đưa vào.
MONTHNAME MONTHNAME(Month As long, [Abbreviate As Boolean = False]) 'As String
Trả về một chuỗi đại diện cho tháng được cho một số từ 1 đến 12.
NOW Now 'As Date
Trả lại ngày, giờ hiện tại của hệ thống.
TIMESERIAL TimeSerial(Hour As Integer, Minute As Integer, Second As Integer) 'As Date
Trả về thời gian ứng với giá trị giờ, phút và giây đưa vào.
TIMEVALUE TimeValue(Time As String) 'As Date
Trả về trị số thời gian của một thời gian ở dạng chuỗi.
WEEKDAY Weekday(Date, [FirstDayOfWeek As VbDayOfWeek = vbSunday]) 'As
Integer
Trả về một số đại diện cho ngày trong tuần tương ứng với ngày xét.
WEEKDAYNAME WeekdayName(Weekday As Long, [Abbreviate As Boolean = False],
[FirstDayOfWeek As VbDayOfWeek = vbUseSytemDayOfWeek]) 'As String
Trả về một chuỗi đại diện cho ngày trong tuần ứng với số từ 1 đến 7.
YEAR Year(Date) 'As Integer

P a g e 20 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Trả về trị số năm có bốn chữ số (một số từ năm 1900 đến 9999) ứng với ngày
đang xét.
Math/Trig Hàm về Toán học
Functions
ABS Abs(Number) 'As Double
Trả về giá trị tuyệt đối của một số.
ATN Atn(Number As Double) 'As Double
Trả về giá trị của phép tính ATAN trong Toán, từ -Pi/2 tới Pi/2.
COS Cos(Number As Double) 'As Double
Trả về giá trị của phép tính Cosine của một góc trong Toán (-1 tới 1).
EXP Exp(Number As Double) 'As Double
Trả về giá trị lũy thừa của cơ số e (e là hằng số toán học, xấp xỉ 2.718).
FIX Fix(Number)
Trả về phần số nguyên của một số.
FORMAT Format (Expression, [Format ]) 'As String
NUMBERS
Định dạng một số dưới dạng chuỗi.
INT Int(Number) 'As Double
Trả về phần số nguyên của một số.
LOG Log(Number As Double) 'As Double
Trả về giá trị của phép tính Logarit tự nhiên của một số (Log cơ số e hay
Ln(x)).
RANDOMIZE Randomize([Number])
Được sử dụng để thay đổi giá trị nguồn được sử dụng bởi máy tạo số ngẫu
nhiên cho hàm RND.
RND RND
Để tạo ra một số ngẫu nhiên giữa 0-1.
ROUND Round(Number, [NumDigitsAfterDecimail As Long]) 'As Double
Làm tròn một số đưa vào.
SGN Sgn(Number) 'As Integer
Trả về dấu của một số.
SIN Sin(Number As Double) 'As Double
Trả về giá trị của phép tính Sine của một góc trong Toán, từ -1 tới 1.
SQR Sqr(Number As Double) 'As Double
Trả về kết quả của phép toán căn bậc 2 của số cần tính.
TAN Tan(Number As Double) 'As Double
Trả về giá trị của phép tính Tan của một góc trong Toán.
Logical Functions Hàm logic, cấu trúc lệnh trong VBA
AND Conditions_1 And conditions_2 [… And conditions_n]
Trả về kết quả True nếu tất cả các điều kiện đưa vào là True.
OR Conditions_1 Or conditions_2 [… Or conditions_n]
Trả về TRUE nếu cos bất kỳ điều kiện nào là TRUE.
CASE Select Case Expression

Case condition_1

P a g e 21 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

result_1

Case condition_2

result_2

...

Case condition_n

result_n

Case Else

result_else

End Select
Tương tự cấu trúc lệnh If Then Else, trả về một giá trị nếu một điều kiện trả về
TRUE.
IF-THEN-ELSE If condition_1 Then

result_1

ElseIf condition_2 Then

result_2

...

ElseIf condition_n Then

result_n

Else

result_else

End If
Trả về một giá trị nếu một điều kiện trả về TRUE hoặc một giá trị khác nếu nó
trả về FALSE.
FOR...NEXT FOR counter = start TO end [Step increment]
{...statements...}
NEXT [counter]
Vòng lặp duyệt qua biến đếm.
DO Do While condition
WHILE…LOOP
{...statements...}

P a g e 22 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Loop
Vòng lặp duyệt qua điều kiện đưa vào.
WHILE...WEND WHILE condition
{...statements...}
END
Vòng lặp duyệt qua điều kiện đưa vào. Giống cấu trúc lệnh DO
WHILE…LOOP.
SWITCH Switch(ParamArray VarExpr() As Variant)
Switch (expr1, value1, expr2, value2, ... expr_n, value_n)
Xét một danh sách các biểu thức và trả về giá trị tương ứng cho biểu thức đầu
tiên trong danh sách có kết quả TRUE.
Information Hàm xử lý thông tin
Functions
ENVIRON Environ(Expression) 'As String
Trả về giá trị ứng biến của môi trường hệ điều hành cần xác định.
ISDATE IsDate(Expression) 'As Boolean
Trả về TRUE nếu biểu thức là một giá trị ngày hợp lệ.
ISEMPTY IsEmpty(Expression) 'As Boolean
Kiểm tra các ô trống hoặc các biến rỗng (chưa có giá trị), nếu đúng thì trả về
True, ngược lại trả về False.
ISERROR IsError(Expression) 'As Boolean
Trả về kết quả True nếu điều kiện cần kiểm tra là một lỗi, ngược lại trả về
False.
ISNULL IsNull(Expression) 'As Boolean
Kiểm tra giá trị NULL.
ISNUMERIC IsNumeric(Expression) 'As Boolean
Kiểm tra một giá trị là dạng số hay không. Trả về True nếu là dạng số, ngược
lại trả về False.
ISARRAY IsArray(VarName) 'As Boolean'
Kiểm tra một biến (VarName) là dạng mảng (Array) hay không. Trả về True
nếu là dạng mảng, ngược lại trả về False.
TYPENAME TypeName(VarName) 'As String'
Trả về kiểu dữ liệu của biến chỉ định.
Data Type Conv. Hàm chuyển đổi kiểu dữ liệu
Functions
CBOOL CBool(Expression) 'As Boolean
Chuyển giá trị về kiểu dữ liệu Boolean.
CBYTE CByte(Expression) 'As Byte
Chuyển giá trị về kiểu dữ liệu Byte (0-255).
CCUR CCur(Expression) 'As Currency
Chuyển giá trị về kiểu dữ liệu Currency.
CDATE CDate(Expression) 'As Date
Chuyển giá trị về kiểu dữ liệu Date.
CDBL CDbl(Expression) 'As Double
Chuyển giá trị về kiểu dữ liệu Double.
CDEC CDbl(Expression) 'As Decimal

P a g e 23 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Chuyển giá trị về kiểu dữ liệu Decimal.


CINT CInt(Expression) 'As Integer
Chuyển giá trị về kiểu dữ liệu Integer.
CLNG CLng(Expression) 'As Long
Chuyển giá trị về kiểu dữ liệu Long.
CSNG CSng(Expression) 'As Single
Chuyển giá trị về kiểu dữ liệu Single.
CSTR CStr(Expression) 'As String
Chuyển giá trị về kiểu dữ liệu String.
CVAR CVar(Expression)
Chuyển giá trị về kiểu dữ liệu đưa vào.
File/Directory Hàm xử lý về tập tin và thư mục
Functions
CHDIR ChDir(Path As String)
Dùng để thay đổi đường dẫn hoặc thư mục hiện tại.
CHDRIVE Chdrive(Drive As String)
Dùng để thay đổi ổ đĩa hiện tại.
CURDIR CurDir([Drive])
Trả về đường dẫn hiện tại.
DIR Dir([PathName],[Attributes As VbFileArrtibute = vbNormal]) As String
Trả về tên tập tin (file) đầu tiên tương ứng với tên đường dẫn và các thuộc tính
được chỉ định.
FILEDATETIME FileDateTime(PathName as String) 'As Date
Trả về ngày và thời gian khi tập tin được tạo hoặc sửa đổi lần cuối.
FILELEN FileLen(PathName As String) 'As Long
Trả về kích thước của tập tin ở đơn vị bytes.
GETATTR GetAttr(PathName As String) 'As VbFileAttribute
Trả về một số nguyên đại diện cho các thuộc tính của một tập tin, thư mục.
MKDIR MkDir(Path As String)
Tạo một thư mục chỉ định.
RMDIR RmDir(Path As String)
Xóa một thư mục chỉ định.
SETATTR SetAttr PathName As String, Attributes As VbFileAttribute
Thiết lập thuộc tính cho tập tin

P a g e 24 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 8. Events, Application Object


>> Download: Events | Application Object
1. Events
Một số sự kiện thường dùng.
1.1. Worksheet_Activate
Sự kiện khi Worksheet được kích hoạt hiện hành.
Ví dụ:
Private Sub Worksheet_Activate()
'Jump to last cell in column:'
Dim Cll As Range
Set Cll = Range("B" & Rows.Count).End(xlUp).Offset(1, 0)
Cll.Select
End Sub
1.2. Worksheet_Change
Sự kiện thay đổi, cập nhật dữ liệu của cell trên Worksheet.
Ví dụ:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Rng As Range
Set Rng = Range("B3:B100") 'Vùng nhâp du liêu.'
If Not Intersect(Target, Rng) Is Nothing Then 'Nêu ô dang xét không phai không thuôc
vùng Rng thì:'
Target.Offset(0, 2).Value = Now 'Nhâp thoi gian hiên hành vào ô tuong ung cách 2
côt'
End If
End Sub
Lưu ý: Nếu không chỉ định địa chỉ cho Target thì Target sẽ nhận là toàn bộ cells trên bảng tính.
1.3. Worksheet_SelectionChange
Sự kiện khi di chuyển trỏ chuột trên chọn cells trên Worksheet.

Ví dụ:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
'Hight light row and column from activecell:'

Exit Sub '<---------Bo dòng này dê chay code'

Dim iRow As Long, iCol As Long, i As Long, j As Long


Application.ScreenUpdating = False

Cells.Interior.ColorIndex = 0 'Xóa màu nên cu'


iRow = ActiveCell.Row 'Tra vê dòng cua ô hiên hành'
iCol = ActiveCell.Column 'Tra vê côt cua ô hiên hành'

For i = 1 To iRow
Cells(i, iCol).Interior.ColorIndex = 6 'Tô màu ô cùng dòng'
Next i

For j = 1 To iCol
Cells(iRow, j).Interior.ColorIndex = 6 'Tô màu ô cùng côt'
Next j

P a g e 25 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Application.ScreenUpdating = True
End Sub
1.4. Workbook_BeforeClose
Sự kiện trước khi đóng Workbook.

Ví dụ:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
'Hide sheets:'
Sheets("Temp").Visible = xlSheetHidden

'Luu bang tinh:'


ThisWorkbook.Save
End Sub
1.5. Workbook_BeforePrint
Sự kiện trước khi in bảng tính.

Ví dụ:
Private Sub Workbook_BeforePrint(Cancel As Boolean)
'Luu bang tinh truoc khi in:'
ThisWorkbook.Save
End Sub
1.6. Workbook_Open
Sự kiện khi mở Workbook.

Ví dụ:
Private Sub Workbook_Open()
'Gioi han ngay su dung file:
Dim dkNgay As Long
dkNgay = Sheet1.Range("A1").Value2 'Nhâp ngày diêu kiên vào [A1] cua sheets "Data"
If CLng(Date) > dkNgay Then 'Nêu ngày hiên tai > ngày diêu kiên
MsgBox "Quá han su dung!" & vbNewLine & "Liên hê tác gia:...", , "Thông báo"
Else
MsgBox "Xin chào!", , "Thông báo"
End If
End Sub
2. Application Object
2.1. ScreenUpdating
Điều khiển cập nhật màn hình: Khi điều khiển các đối tượng (sheets, range, cells), việc vô hiệu
hóa cập nhật màn hình (tránh nhấp nháy) giúp tốc độ code nhanh hơn.
2.2. Calculation
Mặc định thiết lập bảng tính tự động tính toán (CalculationAutomatic), khi điều khiển các đối
tượng (sheets, range, cells), ví dụ gán kết quả xuống bảng tính, các công thức thực hiện tính
toán với giá trị vừa được gán, máy tính phải xử lý thêm tác vụ, làm giảm tốc độ code thực hiện
lệnh. Vậy, để tăng tốc độ cho code ta sẽ chuyển thiết lập về dạng thủ công (CalculationManual).
Xem 2 ví dụ để so sánh:
Sub ScreenAndCal_ON()
'Vô hiêu hóa câp nhât màn hình
Application.ScreenUpdating = False

P a g e 26 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

'Thiêt lâp tinh toan vê dang thu công


Application.Calculation = xlCalculationManual
Dim i As Long, T As Double
'Lây gôc thoi gian chay code:
T = Timer

'Vòng lap gan sô thu tu: 1 - 100 000


For i = 1 To 100000
Sheet1.Range("A1").Offset(i, 0).Value = i
Next i

'Câp nhât màn hình


Application.ScreenUpdating = True
'Thiêt lâp tinh toan vê dang tu dông
Application.Calculation = xlCalculationAutomatic

'Thoi gian hoàn thành:


MsgBox Round(Timer - T, 2) & " giây" 'T=2.62 giây
End Sub
'--------------'
Sub ScreenAndCal_OFF()
Dim i As Long, T As Double
'Lây gôc thoi gian chay code:
T = Timer

'Vòng lap gan sô thu tu: 1 - 100 000


For i = 1 To 100000
Sheet1.Range("A1").Offset(i, 0).Value = i
Next i

'Thoi gian hoàn thành:


MsgBox Round(Timer - T, 2) & " giây" 'T=3.12 giây
End Sub
2.3. DisplayAlerts
Điều khiển hộp thoại thông báo khi thực thi code.
- Khi đóng file, xuất hiện hộp thoại:

Sub Alert_Close()
Application.DisplayAlerts = False
ActiveWorkbook.Close
Application.DisplayAlerts = True
End Sub
Khi đó, Excel đóng mà không lưu bảng tính, tương ứng với chọn “Don’t Save”.
2.4. WorksheetFunction
Sử dụng thuộc tính WorksheetFunction để gọi các hàm trong bảng tính.
Cấu trúc:
Application.WorksheetFunction.Formula
Với Formula là một hàm trong bảng tính (sum, countA, Match…)

P a g e 27 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Ví dụ:
Sub Worksheet_Function()
Dim WF As WorksheetFunction
Set WF = Application.WorksheetFunction
Dim aCount As Long
aCount = WF.CountIf(Sheet1.Range("A2:A10"), ">0")
MsgBox aCount

'Hoac viet gôp:


Dim maxValue As Long
maxValue = Application.WorksheetFunction.Max(Sheet1.Range("A2:A100"))
MsgBox maxValue
End Sub
2.5. GetOpenFilename
Lấy tên file từ cửa sổ chọn
Application.GetOpenFilename([FileFilter],[FilterIndex],[Title],[ButtonText],MultiSelect])
FileFilter: Chuỗi đưa ra điều kiện lọc loại tập tin trong cửa sổ chọn.
FilterIndex: Chỉ định chỉ số của loại tập tin mặc định được lọc.
Title: Tiêu đề của hộp thoại chọn tập tin, mặc định là “Open”.
ButtonText: Với MAC OS.
MultiSelect: True cho phép chọn nhiều tập tin, False (mặc định) chỉ cho chọn một.

Ví dụ:
Sub GetFileName_Any()
Dim FilePath As String
FilePath = Application.GetOpenFilename()
MsgBox FilePath
End Sub
'--------------'
Sub GetFileName_Excel()
Dim FilePath As String
FilePath = Application.GetOpenFilename("Excel file (*.xlsx), *.xlsx")
MsgBox FilePath
'Workbooks.Open (OpenFile)
End Sub

P a g e 28 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 9. Function and Sub


>> Download: Private Sub | Public Sub | Static Sub | ByVal-ByRef | Vidu
1. Cấu trúc
[Public | Private | Static] Function / Sub

Line(s) code

End Function / Sub


Function/ End Function: Bắt đầu/ kết thúc một hàm.
Sub/ End Sub: Bắt đầu/ kết thúc một thủ tục.
Các từ khóa Public, Private, Static để xác định phạm vi (tầm vực) của Function/ Sub.
- Public: phạm vi toàn cục, ở đâu trong môi trường VBA Project cũng có thể thấy / dùng được.
Ví dụ:
'Module1:
Public Sub Vidu()
MsgBox "Day la mot public_sub."
End Sub

'Module2:
Sub CallPublicSub()
Call Vidu
'Hoac:'
Module1.Vidu
End Sub
- Private: phạm vi nội bộ, các Function/ Sub khác trong cùng môi trường VBA Project mới
thấy/ dùng được.
Ví dụ:
'Module1:
Private Sub Vidu()
MsgBox "Day la mot private_sub."
End Sub
'Module2:
Sub CallPrivateSub1()
Call Vidu
'Hoac:'
'Module1.Vidu'
'Ket qua: Xay ra loi - "Sub or Function not defined" '
End Sub
Tuy nhiên, có cách để gọi một Function/ Sub từ một Module khác được khai báo Private.
Tiếp ví dụ trên:
'Module2:
Sub CallPrivateSub2()
'Cach goi toi mot Private Sub'
Run "Module1.Vidu"
End Sub
- Static: Phạm vi toàn cục, ở đâu trong môi trường VBA Project cũng có thể thấy / dùng được.
Đặc biệt, các biến được khai báo trong Static Sub/ Function được lưu giá trị cho tới khi thoát
ứng dụng.
Ví dụ:

P a g e 29 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

'Module1:
Static Sub Vidu()
Dim a As Long
a = a + 10
MsgBox a
'Chay sub nay 3 lan, bien a van duoc luu gia tri sau cac lan chay sub:'
'Lan 1: a=10'
'Lan 2: a=20'
'Lan 3: a=30'
End Sub

'Module2:
Sub CallStaticSub()
Call Vidu
'Chay sub nay sau khi chay sub Module1.Vidu'
'Hoac:'
Module1.Vidu
End Sub

2. Function
Cấu trúc:
[Public | Private | Static] Function([ByVal / ByRef | Arguments As type of variables]) [As type
of variables]

Line(s) code

End Function
Function/ End Function: Bắt đầu/ kết thúc một hàm.
Public | Private | Static: Không bắt buộc. Các từ khóa để xác định phạm vi (tầm vực) của
Function.
ByVal / ByRef: Không bắt buộc. Kiểu truyền đối số cho hàm. Mặc định là ByRef (kiểu tham
chiếu).
Arguments As type of variables: Không bắt buộc. Các đối số của hàm, và kiểu dữ liệu khai báo
tương ứng với đối số.
[As type of variables]: Không bắt buộc. Kiểu dữ liệu của kết quả trả về của hàm. Không khai
báo thì kết quả của hàm có kiểu dữ liệu được gán vào.

Ví dụ:
'//Hàm tách ho tên
Function TachHoTen(ByVal chuoi As String) As Variant
'Loai khoang trang dâu và cuôi chuôi:'
chuoi = Trim(chuoi)
Dim arrTmp As Variant, mangKQ()
'Cat chuoi hoten bang dâu phân cách: khoang trang'
arrTmp = Split(chuoi, " ") 'Ket qua tra ve là môt mang 1 chiêu gôm các chu phân cach boi
khoang trang'
ReDim mangKQ(1 To 3)
mangKQ(1) = arrTmp(LBound(arrTmp)) 'Ho'
mangKQ(3) = arrTmp(UBound(arrTmp)) 'Ten'

P a g e 30 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

mangKQ(2) = Mid(chuoi, Len(mangKQ(1)) + 2, Len(chuoi) - Len(mangKQ(1) &


mangKQ(3)) - 2) 'Dem'
mangKQ(2) = Trim(mangKQ(2)) 'Loai khoang trang nêu có.'
TachHoTen = mangKQ 'Gán kêt qua cho Function'
End Function

Công thức trên bảng tính:


=INDEX(TachHoTen($A5),1) 'Tra ve ho
=INDEX(TachHoTen($A5),2) 'Tra ve ten dem
=INDEX(TachHoTen($A5),3) 'Tra ve ten

Ví dụ:
'//Tính thê tích khôi hôp
Function TheTichHop(ByVal x As Double, ByVal y As Double, ByVal z As Double) As
Double
TheTichHop = x * y * z
End Function
Công thức trên bảng tính:
=TheTichHop(10,20,34)
=TheTichHop(B9, B10, B11)
3. Sub
Cấu trúc:

[Public | Private | Static] Sub([ByVal / ByRef | Arguments As type of variables])

Line(s) code

End Sub
Sub/ End Sub: Bắt đầu/ kết thúc một Sub.
Public | Private | Static: Không bắt buộc. Các từ khóa để xác định phạm vi (tầm vực) của Sub.
ByVal / ByRef | Arguments As type of variables: Không bắt buộc. Các đối số của Sub. ByVal /
ByRef là các kiểu truyền đối số.

Ví dụ:
Sub TachHoVaTen() 'Tách ho và tên'
Dim chuoi, Tmp
chuoi = Trim(Sheet1.Range("A5").Value)
Tmp = Split(chuoi, " ") 'Ket qua tra ve là môt mang 1 chiêu gôm các chu phân cach boi
khoang trang'
Sheet1.Range("F5").Value = Tmp(LBound(Tmp))
Sheet1.Range("H5").Value = Tmp(UBound(Tmp))
Sheet1.Range("G5").Value = Mid(chuoi, Len(Tmp(LBound(Tmp))) + 2, Len(chuoi) -
Len(Tmp(LBound(Tmp)) & Tmp(UBound(Tmp))) - 2)
End Sub
'----------------'
Sub TheTich() 'Tính thê tích khôi hôp'
Dim x As Double, y As Double, z As Double
x = Sheet1.Range("B9").Value

P a g e 31 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

y = Sheet1.Range("B10").Value
z = Sheet1.Range("B11").Value
MsgBox "Thê tích khôi hôp: " & x * y * z & " dvtt."
End Sub
'----------------'
Sub ScreenAndCal_ON()
Dim i As Long, T As Double
'Lây gôc thoi gian chay code:'
T = Timer

'Bât tang tôc cho code'


SpeedCode True 'Goi môt thu tuc con'
'Vòng lap gan sô thu tu: 1 - 100 000'
For i = 1 To 100000
Sheet1.Range("E" & i).Value = i
Next i

'Tat tang tôc cho code'


SpeedCode False 'Goi môt thu tuc con'

'Thoi gian hoàn thành:'


MsgBox Round(Timer - T, 2) & " giây" 'T=2.62 giây'
End Sub
'--------------'
Public Sub SpeedCode(ByVal OnOff As Boolean) 'Dây là môt thu tuc con'
With Application
If OnOff = True Then 'Nêu chon là True'
.ScreenUpdating = False 'Vô hiêu hóa câp nhât màn hình'
.Calculation = xlCalculationManual 'Tính toán thu công'
Else 'Nêu chon là False'
.ScreenUpdating = True 'Câp nhât màn hình'
.Calculation = xlCalculationAutomatic 'Tu dông tính toán'
End If
End With
End Sub
4. ByVal / ByRef
Là 2 kiểu truyền đối số cho Function/ Sub.
ByVal: Truyền đối số kiểu truyền giá trị.
ByRef: Truyền đối số kiểu tham chiếu
Mặc định, trong VBA truyền đối số kiểu tham chiếu ByRef.

Ví dụ:
Sub Test_ByValRef()
Dim x As Long, y As Long
x = 50
y = 50
MsgBox "By_Ref = " & By_Ref(x) & vbNewLine & "x = " & x 'By Ref_1 = 500 | x =
500

P a g e 32 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

MsgBox "By_Val = " & By_Val(y) & vbNewLine & "y = " & y 'By Val_2 = 500 | y = 50
End Sub
'-------------'
FFunction By_Ref(ByRef n As Long) As Long
n = 10 * n
By_Ref = n
End Function
'-------------'
Function By_Val(ByVal n As Long) As Long
n = 10 * n
By_Val = n
End Function
Chú thích:
- Với Function By_Ref():
Truyền đối số bằng tham chiếu (ByRef), tức là ta đang tham chiếu tới giá trị gốc. Giá trị của n
(giá trị ban đầu) được thay đổi trong hàm. (Ví dụ trên: Sau khi truyền đối số thì x = 500).
- Với Function By_Val():
Truyền đối số bằng giá trị, tức là ta chỉ lấy giá trị của đối số (copy value), chứ không làm thay
đổi giá trị ban đầu của đối số. Giá trị của n (giá trị ban đầu) vẫn giữ nguyên không đổi. (Ví dụ
trên: Sau khi truyền đối số thì y =50).
5. Ví dụ
Hàm trả về dòng cuối dùng có dữ liệu tương ứng với cell tham chiếu.
'//Function tra vê dòng cuôi cùng có du liêu'
Function LastRow(ByVal ws As Worksheet, ByVal sCol As String) As Long
If ws.FilterMode = True Then ws.ShowAllData 'Nêu dang filter thi clear'
ws.Cells.EntireRow.Hidden = False 'Unhide toan bô rows'
LastRow = ws.Cells(ws.Rows.Count, sCol).End(xlUp).Row 'Tra vê dòng cuôi cùng có du
liêu'
End Function

Hàm rút ngắn họ và tên với trường hợp có từ 2 tên đệm trở lên.
'//Function rut ngan ho và tên (nêu có 2 tên dêm)'
Function ShortName(ByVal sName As String) As String '//Công thuc o bang tinh Excel
=ShortName("ho và tên")'
Dim arrTmp, i As Long
sName = WorksheetFunction.Trim(sName)
arrTmp = Split(sName, " ")
If UBound(arrTmp) > 2 Then
For i = LBound(arrTmp) + 1 To UBound(arrTmp) - 1
arrTmp(i) = Left(arrTmp(i), 1) & "."
Next i
ShortName = Join(arrTmp, " ")
Else
ShortName = sName
End If
End Function

P a g e 33 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 10. Array


>> Download: Array
0. Khái quát chung
Mảng (array) là một tập hợp của nhiều phần tử được gọi thông qua một tên.
Ví dụ: Arr
Ta xác định phần tử trong mảng thông qua địa chỉ của phần tử đó trong mảng.
Ví dụ: Arr(2): Tức là gọi tới phần tử có địa chỉ thứ tự là 2 trong mảng Arr.
Phân loại:
Theo kích thước của mảng, chia thành: mảng 1 chiều và mảng nhiều chiều.
Ví dụ:
Mảng 1 chiều: Arr(5)
Mảng 2 chiều: Arr2(4, 9)
Mảng 3 chiều: Arr3(5,12,30)
Theo tính chất về khả năng thay đổi (khai báo lại) kích thước của mảng trong quá trình sử dụng,
chia thành: mảng tĩnh, mảng động.

Khai báo mảng:


Public | Private | Dim | Static Arr([Lower To] Upper) [As type of variables]
- Public | Private | Dim | Static: Là các từ khóa để khai báo biến mảng.
(xem chi tiết ở Bài 4. Biến trong VBA)
- Arr: Tên của biến mảng cần khai báo, tuân theo quy tắc đặt tên một biến.
- Lower: Cận dưới một chiều của mảng (*).
- Upper: Cận trên một chiều của mảng
- To: Là từ khóa
- As type of variables: Kiểu dữ liệu của các phần từ trong mảng Arr.
Nếu mảng gồm nhiều chiều thì các chiều được ngăn cách bởi dấu phẩy.
(*) Chú thích: Cận dưới một chiều của mảng mặc định Lower=0, tức là mặc định trong
VBA Option Base 0.
Ví dụ:
Dim Arr1(5): Tương ứng với Dim Arr1(0 To 5), mảng 1 chiều có 6 phần tử.
Dim Arr2(6, 9): Tương ứng với Dim Arr(0 To 6, 0 To 9), mảng 2 chiều, chiều thứ nhất (0-
6), chiều thứ hai (0-9).
Để thay đổi cận dưới mặc định này ta khai báo ở trên cùng của module cần thay đổi:
Option Base 1
Khi đó: Dim Arr1(5) sẽ tương ứng Dim Arr1(1 To 5).
Kích thước của mảng:
Dùng 2 hàm LBound() và UBound() để xác định cận dưới và cận trên của mảng.
LBound(ArrayName, Dimension)

UBound(ArrayName, Dimension
ArrayName: Tên mảng.
Dimension: Chiều của mảng cần xác định.
Kích thước của một chiều thứ i của mảng Arr = UBound(Arr,i) – Lbound(Arr,i) + 1.
Kích thước lớn nhất mỗi chiều của mảng là 2^31 – 1. Tuy nhiên, mảng đó có hoạt động được
hay không còn phụ thuộc vào bộ nhớ của máy tính, nếu mảng có kích thước vượt quá bộ nhớ
khả dụng của máy tính sẽ gặp lỗi “Out of memory”.
Tham khảo thêm Array Size.
Ví dụ:

P a g e 34 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Sub L_UBound()
Dim Arr(1 To 10, 1 To 4)
MsgBox LBound(Arr, 1) & " - " & UBound(Arr, 1) 'Result: 1 - 10
MsgBox LBound(Arr, 2) & " - " & UBound(Arr, 2) 'Result: 1- 4
End Sub

Ứng dụng của mảng trong viết code: Tăng tốc cho code.
Theo tính chất khi sử dụng, ta xét mảng tĩnh và mảng động.
1. Mảng tĩnh
Một mảng tĩnh là mảng có số chiều, kích thước của chiều được khai báo cụ thể ngay từ đầu.
Dim StaticArr (1 đến 20) As Long
Không thể thay đổi kích thước hoặc kiểu dữ liệu của mảng tĩnh (Redim / Redim Preserve).
Khi thực hiện xóa một mảng tĩnh (Erase StaticArr), không có bộ nhớ nào được giải phóng. Khi
đó, việc xóa đó đơn giản là đặt lại tất cả các phần tử của mảng về giá trị mặc định của chúng (0,
vbNullString, Empty hoặc Nothing, tùy thuộc vào kiểu dữ liệu của mảng đó đã được khai báo).

Ví dụ:
Dim Arr(1 To 8) 'Mảng 1 chiều có 8 phần từ (1-8)

Dim Arr2(1 to 9, 1 To 1) 'Mảng 2 chiều, chiều 1 có 9 phần tử (1-9), chiều 2 có 1 phần từ (1-1)
Kích thước khai báo phải là một hằng số cụ thể, không thể khai báo thông qua một biến.
Đúng:
Dim A(1 to 3)
Dim A1( 1 to 4, 1 to 9)

Không đúng:
Sub KhaiBaoLoi()
Dim n As Long
n=5
Dim Arr(1 To n) 'Error: Constant expression required
End Sub
2. Mảng động
Khi chưa xác định được số chiều và kích thước chiều của mảng cần khai báo, ta dùng mảng
động. Mảng động cho phép khai báo số chiều, kích thước mỗi chiều của mảng sau.

Ví dụ:

Dim Arr1() As Long, Arr2() As String

'Ta mới chỉ khai báo biến mảng nhưng chưa biết số chiều, kích thước của chiều.'
Mảng động cho phép thay đổi kích thước của mảng, nhưng không thể thay đổi kiểu dữ liệu của
mảng.
Khi thực hiện xóa (Erase) một mảng động, bộ nhớ được phân bổ cho mảng đó được giải phóng.
Để sử dụng mảng động sau khi Erase cần thực hiện ReDim mảng động đó.
Khi đã xác định được số chiều và kích thước của chiều ta tiến hành khai báo lại cho mảng, với
từ khóa Redim

Ví dụ:

P a g e 35 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Sub Arr_Dynamic_1()
Dim Arr1() As Long, Arr2() As Long, m As Long, n As Long, i As Long
m = 50
n = 60
ReDim Arr1(1 To m) '1.1'
ReDim Arr2(1 To m, 1 To 1) '1.2'
For i = 1 To m 'Vòng lap gán giá tri vào mang'
Arr1(i) = i
Arr2(i, 1) = i
Next i
ReDim Arr1(1 To n) '2.1'
ReDim Arr2(1 To m, 1 To n) '2.2'
MsgBox "Arr1(1) = " & Arr1(1) & vbNewLine & "Arr2(1,1) = " & Arr2(1, 1)
'Result: Arr1(1) = 0 | Arr2(1,1) = 0'
End Sub
Trong ví dụ trên, ban đầu ta khai báo 2 biến mảng Arr1(), Arr2() nhưng chưa khai báo số chiều
và kích thước của chiều.
Tiếp đó, ta khai báo lại lần thứ nhất (1.1 và 1.2) 2 mảng đó với số chiều và kích thước cụ thể:
ReDim Arr1(1 To m): mảng có 1 chiều, có m -1 +1 = 50 phần tử.
ReDim Arr2(1 To m, 1 To 1): mảng 2 chiều, chiều 1 có kích thớc m -1 +1 = 50, chiều 2 có kích
thớc là 1.
Tiếp theo, ta gán các giá trị cho các phần tử trong mảng (vòng lặp For Next).
Sau đó, ta khai báo lại lần thứ hai (2.1 và 2.2) 2 mảng đó với số chiều và kích thước cụ thể:
ReDim Arr1(1 To n): mảng có 1 chiều, có n -1 +1 = 60 phần tử.
ReDim Arr2(1 To m, 1 To n): mảng 2 chiều, chiều 1 có kích thớc m -1 +1 = 50, chiều 2 có kích
thước n -1 +1 = 60.
Lưu ý ở đây:
- Sau khi Redim để khai báo thay đổi số chiều và kích thước của chiều thì các phần tử trong
mảng trước đó đều bị xóa.
- Khi cần khai báo lại để thay đổi kích thước của mảng mà vẫn giữ các phần từ đã có thì ta
dùng Redim Preserve. Tuy nhiên, cần chú ý rằng Redim Preserve chỉ áp dụng được để thay đổi
kích thước chiều cuối cùng của mảng.

Ví dụ:
Sub Arr_Dynamic_2()
Dim Arr1() As Long, Arr2() As Long, m As Long, n As Long, i As Long
m = 50
n = 60
ReDim Arr1(1 To m) '1.1'
ReDim Arr2(1 To m, 1 To 1) '1.2'
For i = 1 To m 'Vòng lap gán giá tri vào mang'
Arr1(i) = i
Arr2(i, 1) = i
Next i
ReDim Preserve Arr1(1 To n) '2.1'
ReDim Preserve Arr2(1 To m, 1 To n) '2.2'
MsgBox "Arr1(1) = " & Arr1(1) & vbNewLine & "Arr2(1,1) = " & Arr2(1, 1)
'Result: Arr1(1) = 1 | Arr2(1,1) = 1'
End Sub

P a g e 36 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Để ý (2.2) ở ví dụ trên: ReDim Preserve Arr2(1 To m, 1 To n), chỉ có thể thay đổi kích thước
chiều cuối (chiều thứ 2) của mảng Arr2.
3. Chép trị từ range của bảng tính vào array và gán các phần tử của array xuống range
của bảng tính
(Range – Array – Range)
3.1. Range – Array:
Theo hình học giải tích ta có chia ra 1 chiều (đường thẳng), 2 chiều (mặt phẳng), 3 chiều (dạng
khối), và n chiều.
Một range trên bảng tính Excel luôn luôn có 2 chiều (row và column), vậy range sẽ thuộc dạng
mặt phẳng.
Khi chép giá trị của một range cho mảng (mảng động), VBA dùng một hàm copy. Hàm này
mặc định cho kết quả là mảng 2 chiều, row của range tương ứng với chiều thứ nhất của mảng,
column tương ứng với chiều thứ hai của mảng.

Dim Arr(), Rng As Range


'Set Rng = Range("A1:E20")'
Arr = Rng.Value
Lưu ý:
- Trường hợp đặc biệt, khi range chỉ gồm 1 cell, VBA tự nhận biết và không dùng hàm copy
mảng mà dùng hàm copy giá trị đơn, kết quả trả về là 1 giá trị (không phải mảng).
Do đó, phải bẫy lỗi trường hợp range chỉ gồm 1 cell trước khi copy vào mảng.
Dim Arr(), Rng As Range
'Set Rng = Range'
If Rng.Count > 1 Then
Arr = Rng.Value
End If
Hoặc ta khai báo biến Arr ở dạng Variant, và kiểm tra kiểu dữ liệu của biến Arr sau khi được
gán giá trị của range:
Dim Arr As Variant, Rng As Range
'Set Rng = Range("A1")
Arr = Rng.Value
If TypeName(Arr) = "Variant()" Then 'or: If IsArray(Arr) = True Then
'Your code.'
End If
- Khi kết hợp dùng hàm Application.Transpose() áp dụng vào range chỉ có 1 cột thì kết quả trả
về là mảng 1 chiều. Lưu ý: Hàm Transpose sẽ gặp lỗi khi có một phần tử trong mảng có nhiều
hơn 255 ký tự.
Dim Arr(), Rng As Range
Set Rng = Sheet1.Range("A2:A30")
If Rng.Count > 1 Then
Arr = Application.Transpose(Rng.Value)
End If
Ngoài ra, hàm Transopse chuyển mảng 1 chiều thành mảng 2
chiều: Arr2D=Application.Transpose(Arr1D)
- Cận dưới (LBound) của các chiều của mảng luôn bắt đầu từ 1, cho dù không khai báo Option
Base 1.
- Không thể copy giá trị của một range vào mảng tĩnh theo cấu trúc Arr = Rng.Value, mà phải
dùng vòng lặp để truyền từng giá trị của range vào mảng.
3.2. Array – Range:

P a g e 37 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Khi cần gán mảng xuống range ta dùng cấu trúc:


Rng.value = Arr
Trong đó, range có số dòng/ cột tương ứng (bằng hoặc nhỏ hơn) so với kích thước 2 chiều của
mảng Arr.
Lưu ý:
- Khi gán mảng 1 chiều xuống range thì range đó chỉ gồm 1 dòng.
Sub ImportArray_1D()
Dim Arr(), Rng As Range
Set Rng = Sheet1.Range("A2:A30")
If Rng.Count > 1 Then
Arr = Application.Transpose(Rng.Value) 'Arr là mang 1 chiêu'
End If
'Gán mang Arr xuông bang tinh'
Sheet1.Range("B10").Resize(1, UBound(Arr, 1)).Value = Arr
End Sub
- Khi range chỉ định để gán giá trị của 1 mảng xuống mà nó có số dòng/ cột lớn hơn so với kích
thước chiều của mảng thì những cells nằm ngoài sẽ trả về #N/A.
Sub ImportArray_2D()
Dim Arr()
Arr = Sheet1.Range("A2:B4").Value
'Gán mang Arr xuông bang tinh, chú ý xem kêt qua #N/A:'
Sheet1.Range("A15").Resize(UBound(Arr, 1) + 2, UBound(Arr, 2) + 1).Value = Arr
End Sub
4. Ví dụ
Xét ví dụ nhỏ: Điền số thứ tự dạng số nguyên (1-n) vào vùng A2:A1000000.

Function tạo trả về một mảng 2 chiều, chiều thứ nhất có số phần từ bằng số dòng của range,
chiều thứ hai có kích thước bằng 1 phần tử.
Function ArrSeries(ByVal Rng As Range) As Variant
Dim aTmp(), i As Long
ReDim aTmp(1 To Rng.Rows.Count, 1 To 1)
For i = 1 To UBound(aTmp, 1)
aTmp(i, 1) = i
Next i
ArrSeries = aTmp
End Function
Sub gọi function ArrSeries() rồi gán giá trị mảng trả về từ function ArrSeries() xuống range:
Sub SetSeries_Array()
Dim Rng As Range, T As Double
T = Timer
Set Rng = Sheet1.Range("A1:A100000")
Rng.Value = ArrSeries(Rng)
MsgBox Round(Timer - T, 2) & " giây" 'T=0.12 giây'
End Sub

Sub thực hiện gán số thứ xuống range theo phương thức gán xuống từng cell của range:
Sub SetSeries_Range()
Application.ScreenUpdating = False

P a g e 38 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Application.Calculation = xlCalculationManual
Dim i As Long, T As Double
T = Timer
For i = 1 To 100000
Sheet1.Range("A1").Offset(i - 1, 0).Value = i
Next i
Application.ScreenUpdating = True
Application.Calculation = xlCalculationAutomatic
MsgBox Round(Timer - T, 2) & " giây" 'T=2.75 giây'
End Sub
Nhận xét: Tốc độ code khi sử dụng mảng nhanh hơn rất nhiều sử dụng phương thức sử dụng
range.

P a g e 39 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 11. Dictionary


>> Download: Dictionary
Dictionary (Dic) là một phần trong thư viện Microsoft Scripting Runtime (scrrun.dll), cho phép
lưu trữ và truy xuất số lượng lớn Item theo Key duy nhất tương ứng.
1. Khai báo
1.1. Kiểu khai báo sớm
(Có Tooltip khi gọi Dic, phải thiết lập trong Tools/References)
- Trong cửa sổ VBA, Tools menu, References.
- Tìm và check vào mục “Microsoft Scripting Runtime” trong cửa sổ References – VBAProject.
Khai báo trong code:
Dim Dic As Scripting.Dictionary

Set Dic = New Scripting.Dictionary


1.2. Kiểu khai báo muộn
(Không có Tooltip khi gọi Dic, không cần thiết lập trong Tools/References).

Khai báo trong code:


Dim Dic As Object

Set Dic = CreateObject("Scripting.Dictionary")


2. Các phương thức
2.1. Add
Dic.Add Key, Item
Thêm Item (đối tượng) vào Dic, yêu cầu Key của Item phải chưa tồn tại trong Dic.
Key: Nhận dữ liệu là kiểu số hoặc kiểu chuỗi, yêu cầu Key là duy nhất trong Dic.
Item: Nhận kiểu dữ liệu là chuỗi hoặc số, bao gồm cả rỗng. Item có thể là một giá trị đơn hoặc
một mảng (Array).

Ví dụ:
Sub AddMethod()
'Dic.Add Key, Item'
Dim Dic As Object
Set Dic = CreateObject("Scripting.Dictionary")
Dic.Add "KeyA", 10
Dic.Add "KeyB", "Item2"
Dic.Add "KeyC", ""
Dic.Add "KeyD", Array(20, 50)
End Sub
2.2. Exists
Dic.Exists(Key)
Kiểm tra sự tồn tại của một Key trong Dic. Trả về True nếu Key đó tồn tại trong Dic, ngược lại
trả về False.

Ví dụ:
Sub ExistsMethod()
'Dic.Exists(Key) '
Dim Dic As Object
Set Dic = CreateObject("Scripting.Dictionary")
Dic.Add "KeyA", 10

P a g e 40 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

MsgBox Dic.Exists("KeyA") 'True'


End Sub
2.3. Remove
Dic.Remove(Key)
Xóa một Item trong Dic theo Key chỉ định. Nếu Key chỉ định chưa tồn tại trong Dic thì sẽ xảy
ra lỗi.

Ví dụ:
Sub RemoveMethod()
'Dic.Remove(Key) '
Dim Dic As Object
Set Dic = CreateObject("Scripting.Dictionary")
Dic.Add "KeyA", 10
Dic.Remove ("KeyA")
MsgBox Dic.Exists("KeyA") 'False'
End Sub
2.4. RemoveAll
Dic.RemoveAll
Xóa tất cả các Items có trong Dic.
Ví dụ:
Sub RemoveAllMethod()
'Dic.RemoveAll'
Dim Dic As Object
Set Dic = CreateObject("Scripting.Dictionary")
Dic.Add "KeyA", 10
Dic.Add "KeyB", 20
Dic.RemoveAll
MsgBox Dic.Count '0'
End Sub

2.5. Items
Dic.Items
Trả về một mảng một chiều gồm toàn bộ Items có trong Dic.
Mảng một chiều này luôn có cận dưới bằng 0, dù khai báo Option Base 1

Ví dụ:
Sub ItemsMethod()
'Dic.Items'
Dim Dic As Object, Arr()
Set Dic = CreateObject("Scripting.Dictionary")
Dic.Add "KeyA", 10
Dic.Add "KeyB", 20
Arr = Dic.Items 'LBound(Arr) = 0'
End Sub
2.6. Keys
Dic.Keys
Trả về một mảng một chiều gồm toàn bộ Keys tồn tại trong Dic.
Mảng một chiều này luôn có cận dưới bằng 0, dù khai báo Option Base 1

P a g e 41 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Ví dụ:
Sub KeysMethod()
'Dic.Keys'
Dim Dic As Object, Arr()
Set Dic = CreateObject("Scripting.Dictionary")
Dic.Add "KeyA", 10
Dic.Add "KeyB", 20
Arr = Dic.Keys 'LBound(Arr) = 0'
End Sub
3. Thuộc tính
3.1. Item
Dic.Item(Key)

'Hoặc:'

Dic(Key)
- Gọi Item theo Key chỉ định. Nếu Key chỉ định chưa tồn tại trong Dic, thì Dic sẽ tự động thêm
(Add) Key đó vào, và Item ứng với Key đó là rỗng.
- Thay đổi giá trị của Item theo Key chỉ định. Nếu Key chỉ định chưa tồn tại trong Dic, thì Dic
sẽ tự động thêm (Add) key đó vào, và Item ứng với Key đó có giá trị vừa đưa vào.

Ví dụ:
Sub ItemProperty()
'Dic.Item(Key)'
'Dic(Key) '
Dim Dic As Object, x, y, z
Set Dic = CreateObject("Scripting.Dictionary")
Dic.Add "KeyA", 10
Dic.Add "KeyB", 20
x = Dic.Item("KeyA") '10'
y = Dic("KeyA") '10'
z = Dic("KeyC")
Dic("KeyC") = 100
MsgBox Dic.Item("KeyC") '100'
MsgBox Dic.Count '3'
End Sub
3.2. Key
Dic.Key(Key) = NewKey
Dùng để thay đổi giá trị mới của một Key chỉ định đã tồn tại trong Dic. Yêu cầu:
- Key chỉ định phải đã tồn tại trong Dic
- Giá trị mới của Key đó phải là duy nhất trong Dic (tức là có thể vẫn là giá trị cũ).

Ví dụ:
Sub KeyProperty()
'Dic.Key(Key)=NewKey'
Dim Dic As Object
Set Dic = CreateObject("Scripting.Dictionary")
Dic.Add "KeyA", 10

P a g e 42 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Dic.Key("KeyA") = "KeyB"
End Sub

3.3. Count
Dic.Count
Trả về số Items có trong Dic.

Ví dụ:
Sub CountProperty()
'Dic.Count '
Dim Dic As Object, i As Long
Set Dic = CreateObject("Scripting.Dictionary")
For i = 1 To 5
Dic.Add "Key" & i, ""
Next i
MsgBox Dic.Count '5'
End Sub
3.4. CompareMode
Dic.CompareMode = BinaryCompare

Dic.CompareMode = TextCompare
Thiết lập thuộc tính phân biệt chữ hoa chữ thường cho giá trị của Key.
BinaryCompare: (Giá trị mặc định của Dic) Phân biệt chữ hoa chữ thường
TextCompare: Không phân biệt chữ hoa chữ thường
Lưu ý: Thiết lập CompareMode cho Dic khi Dic rỗng (chưa có item nào trong Dic).

Ví dụ:
Sub CompareModeProperty()
'Dic.CompareMode = vbBinaryCompare'
'Dic.CompareMode = vbTextCompare '
Dim Dic As Object, i As Long
Set Dic = CreateObject("Scripting.Dictionary")
With Dic
.CompareMode = vbBinaryCompare
'.CompareMode = vbTextCompare '
.Add "code", "lower"
.Add "CODE", "UPPER"
End With
End Sub
4. Ứng dụng
- Lọc loại trùng.
- Tạo dãy số ngẫu nhiên không trùng.
-…
4.1. Một số hàm

Hàm lọc loại trùng cột đầu tiên của một Range:
'//Loc loai trung mot cot'
Function UniqueColumn1D(ByVal Rng As Range) As Variant
If Rng.Count = 1 Then UniqueColumn1D = Rng.Value: Exit Function

P a g e 43 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Dim Dic As Object, i As Long, arr()


arr = Rng.Value
Set Dic = CreateObject("Scripting.Dictionary")
For i = LBound(arr, 1) To UBound(arr, 1)
If arr(i, 1) <> "" And Dic.Exists(arr(i, 1)) = False Then
Dic.Add arr(i, 1), ""
End If
Next i
UniqueColumn1D = Dic.Keys
End Function

Hàm lọc loại trùng cột đầu tiên cho mảng 2 chiều:
'//Loc loai trung mang 2 chieu'
Function UniqueArray(ByVal arr As Variant) As Variant
If IsArray(arr) = False Then Exit Function
Dim Dic As Object, i As Long
Set Dic = CreateObject("Scripting.Dictionary")
For i = LBound(arr, 1) To UBound(arr, 1)
If arr(i, 1) <> "" And Dic.Exists(arr(i, 1)) = False Then
Dic.Add arr(i, 1), ""
End If
Next i
UniqueArray = Dic.Keys
End Function
4.2. Ví dụ
Cho bảng dữ liệu như dưới. Yêu cầu, căn cứ vào cột [B] – Code để loại loại trùng, kết quả trả
về gồm 4 cột dữ liệu:
[No.] là thứ tự danh mục Code,
[Code] là danh mục Code sau khi loại trùng,e
[Date] là ngày ứng với Code đầu tiên tìm thấy, xét từ trên xuống,
[Quantity] là tổng ứng với mỗi [Code] lọc được.

- Code trong Module:


Sub FilterData()
'Sub loc loai trung theo cot [Code] - côt [B]'
Dim Dic As Object
Dim Rng As Range, i As Long, lRow As Long, ArrData(), Result(), iTmp As String, j As Long
Set Dic = CreateObject("Scripting.Dictionary")
'Gan doi tuong Dictionary vao bien Dic'
With Sheet1
'Xét sheet1'
lRow = .Range("B" & Rows.Count).End(xlUp).Row
'Tra ve dong cuoi cung co du lieu thuoc cot [B]'
ArrData = .Range("B2:D" & lRow).Value2
'Gan vung du lieu [B2:D & lRow] vao bien mang ArrData'
lRow = UBound(ArrData, 1)
'Tra ve kich thuoc chieu thu nhat cua mang ArrData'
ReDim Result(1 To lRow, 1 To 4)

P a g e 44 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

'Khai bao cu the so chieu va kich thuoc chieu cho bien mang Result'
For i = 1 To lRow
'Xet vong lap bien i chay tu 1 toi lRow
iTmp = ArrData(i, 1)
'Gan phan tu (i,1) cua mang ArrData vao bien iTmp
If iTmp <> "" Then
'Xet iTmp, neu khac rong thi
If Not Dic.Exists(iTmp) Then
'Xet iTmp, neu chua ton tai trong Dic thi
j=j+1
'Tang gia tri cua j len 1 don vi
Dic.Add iTmp, j
'Them item co gia tri = j ung voi key = iTmp
'Truyen ket qua vao bien mang Result:
Result(j, 1) = j
Result(j, 2) = iTmp
Result(j, 3) = ArrData(i, 2)
Result(j, 4) = ArrData(i, 3)
Else
'Nguoc lai: iTmp da ton tai trong Dic thi
Result(Dic.Item(iTmp), 4) = Result(Dic.Item(iTmp), 4) + ArrData(i, 3)
'Cong don so luong vao phan tu cua mang Result co chi so (Dic.Item(iTmp), 4)
End If
End If
Next i
If j > 0 Then
'Xet j >: Tuc la co ket qua loc
.Range("H2").Resize(100, 4).ClearContents
'Xoa du lieu trong vung gan ket qua
.Range("H2").Resize(j, 4) = Result
'Gan ket qua xuong bang tinh
End If
End With
End Sub

P a g e 45 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 12. FileSystemObject


>> Donwload: FileSystemObject

FileSystemObject (FSo) là một phần trong thư viện Microsoft Scripting Runtime (scrrun.dll), là
công cụ chuyên xử lý về Drive, Folder, File.

1. Khai báo

1.1. Kiểu khai báo sớm


(Có Tooltip khi gọi FSo, phải thiết lập trong Tools/References)
- Trong cửa sổ VBA, Tools menu, References.
- Tìm và check vào mục “Microsoft Scripting Runtime” trong cửa sổ References – VBAProject.
Khai báo trong code:

Dim FSo As Scripting.FileSystemObject


Set FSo = New Scripting.FileSystemObject

1.2. Kiểu khai báo muộn


(Không có Tooltip khi gọi FSo, không cần thiết lập trong Tools/References).
Khai báo trong code:
Dim FSo As Object
Set FSo = CreateObject("Scripting.FileSystemObject")

2. Các phương thức

2.1. BuildPath
FSo.BuildPath(Path As String, Name As String) As String

Phương thức BuildPath gán một tên vào một đường dẫn (trả về một chuỗi là đường dẫn).
Path: Bắt buộc. Đường dẫn để nối tên vào.
Name: Bắt buộc. Tên cần nối vào đường dẫn chỉ định.
Ví dụ:
Sub BuildPath()
' Dim Fso As Scripting.FileSystemObject
' Set Fso = New Scripting.FileSystemObject
Dim FSo As Object
Set FSo = CreateObject("Scripting.FileSystemObject")
Dim NewPath As String
NewPath = FSo.BuildPath(ThisWorkbook.Path, "NewFolder")
MsgBox NewPath
End Sub

2.2. CopyFile
FSo.CopyFile(Source As String, Destination As String, [OverWriteFiles As Boolean = True])

Source: Bắt buộc. Đường dẫn của một hoặc nhiều tập tin cần sao chép (Có thể sử dụng ký tự
đại diện “*?”).
Destination: Bắt buộc. Nơi để dán tập tin đã sao chép (ký tự đại diện không thể được sử dụng).
OverWrite: Không bắt buộc. Một giá trị Boolean xác định một tập tin đã tồn tại có thể bị ghi đè

P a g e 46 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

hay không. True cho phép các tập tin đã có được ghi đè lên và False ngăn ngừa các tập tin đã có
bị ghi đè lên. Mặc định là True.
Ví dụ:
Sub CopyFile()
' Dim Fso As Scripting.FileSystemObject
' Set Fso = New Scripting.FileSystemObject
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim sPath As String, dPath As String
sPath = ThisWorkbook.Path & "\*.xlsx"
dPath = "D:\Vidu"
FSo.CopyFile sPath, dPath, True
End Sub

2.3. CopyFolder
FSo.CopyFolder(Source As String, Destination As String, [OverWriteFiles As Boolean =
True])

Source: Bắt buộc. Đường dẫn của một hoặc nhiều thư mục cần sao chép (Có thể sử dụng ký tự
đại diện “*?”).
Destination: Bắt buộc. Nơi để dán thư mục đã sao chép (ký tự đại diện không thể được sử
dụng).
OverWriteFiles: Không bắt buộc. Một giá trị Boolean xác định một thư mục đã tồn tại có thể bị
ghi đè hay không. True cho phép các thư mục đã có được ghi đè lên và False ngăn ngừa các thư
mục đã có bị ghi đè lên. Mặc định là True.
Ví dụ:
Sub CopyFolders()
'Copy all the folders in "D:\Example"
'to the folder "D:\Vidu"
' Dim Fso As Scripting.FileSystemObject
' Set Fso = New Scripting.FileSystemObject
Dim FSo As Object
Set FSo = CreateObject("Scripting.FileSystemObject")
Dim sPath As String, dPath As String
sPath = "D:\Example\*"
dPath = "D:\Vidu"
FSo.CopyFolder sPath, dPath, True
End Sub
'-----------------'
Sub CopyFolder()
'Copy only the folder "OldFolder" in "D:\Example"
'to the folder "D:\Vidu"
' Dim Fso As Scripting.FileSystemObject
' Set Fso = New Scripting.FileSystemObject
Dim FSo As Object
Set FSo = CreateObject("Scripting.FileSystemObject")
Dim sPath As String, dPath As String
sPath = "D:\Example\OldFolder"
dPath = "D:\Vidu"

P a g e 47 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

FSo.CopyFolder sPath, dPath, True


End Sub

2.4. CreateFolder
FSo.CreateFolder(Path As String) As Folder

Path: Bắt buộc. Là đường dẫn của thư mục cần tạo.
Nếu thư mục cần tạo đã tồn tại thì sẽ gặp lỗi, cần kiểm tra sự tồn tại trước khi tạo mới.
Ví dụ:
Sub CreateFolder()
'FSo.CreateFolder(Path As String) As Folder
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
FSo.CreateFolder (ThisWorkbook.Path & "\NewFolder")
'Gap loi neu thu muc da ton tai, can kiem tra su ton tai cua thu muc do truoc khi dung
.CreateFolder
End Sub

2.5. CreateTextFile
FSo.CreateTextFile(FileName As String, [OverWrite As Boolean = True], [Unicode As
Boolean = False]) As TextStream

Tạo một tập tin văn bản dạng TextStream trong một thư mục chỉ định, có thể đọc và viết vào
tập tin đó.
FileName: Bắt buộc. Là đường dẫn đầy đủ của tập tin cần tạo.
OverWrite. Không bắt buộc. Thiết lập cho phép có ghi đè tập tin đã tồn tại hay không. Mặc
định là True, tức là cho phép ghi đè tập tin đã tồn tại. Ngược lại, False tức là không cho phép
ghi đè.
Unicode: Không bắt buộc. Thiết lập tập tin văn bản được tạo dưới định dạng Unicode (ứng với
True) hay ASCII (ứng với False). Mặc định là False.
Ví dụ:
Sub CreateTextFile()
'FSo.CreateTextFile(FileName As String, [OverWrite As Boolean = True], [Unicode As
Boolean = False]) As TextStream
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim nameText As String, TxtFile As TextStream
nameText = ThisWorkbook.Path & "\NewText.txt"
Set TxtFile = FSo.CreateTextFile(nameText, True, True)
TxtFile.WriteLine ("Hello World!")
TxtFile.WriteLine ("This is a example!")
TxtFile.Close
End Sub

2.6. DeleteFile
FSo.DeleteFile(FileSpec As String, [Force As Boolean = False])

FileSpec: Bắt buộc. Đường dẫn của một hoặc nhiều tập tin cần xóa, cho phép dùng ký tự đại
diện (*?).

P a g e 48 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Force: Không bắt buộc. Thiết lập cho phép tập tin có thuộc tính Read-Only có bị xóa hay
không. True cho phép tập tin Read-Only bị xóa, False thì chúng không bị xóa. Mặc định là
False.
Lưu ý: Gặp lỗi nếu tập tin không tồn tại.
Ví dụ:
Sub DeleteFile()
'FSo.DeleteFile(FileSpec As String, [Force As Boolean = False])
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim nameText As String
nameText = ThisWorkbook.Path & "\NewText.txt"
FSo.CreateTextFile nameText, True, False
'nameText = ThisWorkbook.Path & "\*.txt"
FSo.DeleteFile nameText, True
'Gap loi neu tap tin can xoa khong ton tai
End Sub

2.7. DeleteFolder
FSo.DeleteFolder(FolderSpec As String, [Force As Boolean = False])

FolderSpec: Bắt buộc. Là đường dẫn của một hoặc nhiều thư mục cần xóa, cho phép dùng ký tự
đại diện.
Force: Không bắt buộc. Thiết lập cho phép thư mục có thuộc tính Read-Only có bị xóa hay
không. True cho phép thư mục Read-Only bị xóa, False thì chúng không bị xóa. Mặc định là
False.
Lưu ý: Gặp lỗi nếu thư mục không tồn tại.
Ví dụ:
Sub DeleteFolder()
'FSo.DeleteFolder(FolderSpec As String, [Force As Boolean = False])
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
FSo.DeleteFolder (ThisWorkbook.Path & "\NewFolder")
'FSo.DeleteFolder (ThisWorkbook.Path & "\?")
End Sub

2.8. DriveExists
FSo.DriveExists(DriveSpec As String) As Boolean

Kiểm tra sự tồn tại của một ổ đĩa. Trả về True nếu nó tồn tại, ngược lại trả về False.
DriveSpec: Bắt buộc. Tên ổ đĩa cần kiểm tra.
Ví dụ:
Sub DriveExists()
'FSo.DriveExists(DriveSpec As String) As Boolean
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
MsgBox FSo.DriveExists("C:\")
End Sub

2.9. FileExists

P a g e 49 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

FSo.FileExists(FileSpec As String) As Boolean

Kiểm tra sự tồn tại của một tập tin. Trả về True nếu nó tồn tại, ngược lại trả về False.
FileSpec: Bắt buộc. Đường dẫn đầy đủ của tập tin cần kiểm tra.
Ví dụ:
Sub FileExists()
'FSo.FileExists(FileSpec As String) As Boolean
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
MsgBox FSo.FileExists(ThisWorkbook.FullName)
End Sub

2.10. FolderExists
FSo.FolderExists(FolderSpec As String) As Boolean

Kiểm tra sự tồn tại của một thư mục. Trả về True nếu nó tồn tại, ngược lại trả về False.
FolderSpec: Bắt buộc. Đường dẫn đầy đủ của thư mục cần kiểm tra.
Ví dụ:
Sub FolderExists()
'FSo.FolderExists(FolderSpec As String) As Boolean
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
MsgBox FSo.FolderExists(ThisWorkbook.Path)
End Sub

2.11. GetAbsolutePathName
FSo.GetAbsolutePathName(Path As String) As String

Trả về đường dẫn đầy đủ từ ổ đĩa cho đường dẫn đưa vào.
Path: Bắt buộc. Là đường dẫn gợi ý để trả về đường dẫn đầy đủ.
Ví dụ:
Sub GetAbsolutePathName()
'FSo.GetAbsolutePathName(Path As String) As String
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim sPath As String
sPath = FSo.GetAbsolutePathName(ThisWorkbook.Name)
MsgBox sPath
End Sub

2.12. GetBaseName
FSo.GetBaseName(Path As String) As String

Trả về tên cơ sở của một tập tin (tên của tập tin không gồm phần mở rộng) hoặc tên của thư
mục cho thành phần cuối cùng trong một đường dẫn chỉ định đưa vào.
Path: Bắt buộc. Là đường dẫn của tập tin hay thư mục đưa vào.
Lưu ý: Path có thể là đường dẫn của tập tin hoặc thư mục.
Ví dụ:

P a g e 50 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Sub GetBaseName()
'FSo.GetBaseName(Path As String) As String
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim sPath As String
sPath = FSo.GetBaseName(ThisWorkbook.Name)
'sPath = FSo.GetBaseName(ThisWorkbook.Path)
MsgBox sPath
End Sub

2.13. GetDrive
FSo.GetDrive(DriveSpec As String) As Drive

Trả về đối tượng Drive (ổ đĩa) tương ứng với ổ đĩa trong đường dẫn chỉ định đưa vào.
DriveSpec: Bắt buộc. Có thể ở dạng tên ổ đĩa (C,D,E), hoặc ở dạng (C:, D: ), ở dạng (C:\, D:\ ),
hoặc ở dạng chia sẻ trong LAN (\\Computer\Folder2).
Đối tượng Drive có 12 thuộc tính.
Ví dụ:
Sub GetDrive()
'FSo.GetDrive(DriveSpec As String) As Drive
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim dDrive As Drive
Set dDrive = FSo.GetDrive("C:\")
MsgBox GetDriveProperties(dDrive)
End Sub

Public Function GetDriveProperties(ByVal dDrive As Drive) As String


Dim Result()
ReDim Result(1 To 20)
With dDrive
Result(1) = "AvailableSpace: " & .AvailableSpace
Result(2) = "DriveLetter: " & .DriveLetter
Result(3) = "DriveType: " & .DriveType
Result(4) = "FileSystem: " & .FileSystem
Result(5) = "FreeSpace: " & .FreeSpace
Result(6) = "IsReady: " & .IsReady
Result(7) = "Path: " & .Path
Result(8) = "RootFolder: " & .RootFolder
Result(9) = "SerialNumber: " & .SerialNumber
Result(10) = "ShareName: " & .ShareName
Result(11) = "TotalSize: " & .TotalSize
Result(12) = "VolumeName: " & .VolumeName
End With
ReDim Preserve Result(1 To 12)
GetDriveProperties = Join(Result, vbCrLf)
End Function

2.14. GetDriveName

P a g e 51 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

FSo.GetDriveName(Path As String) As String

Trả về tên ổ đĩa từ đường dẫn chỉ định đưa vào.


Path: Bắt buộc. Là đường dẫn đưa vào sẽ trả về tên ổ đĩa.
Ví dụ:
Sub GetDriveName()
'FSo.GetDriveName(Path As String) As String
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
MsgBox FSo.GetDriveName(ThisWorkbook.Path) 'C:
End Sub

2.15. GetExtensionName
FSo.GetExtensionName(Path As String) As String

Trả về phần mở rộng của tập tin.


Path: Bắt buộc. Là đường dẫn đầy đủ của tập tin.
Ví dụ:
Sub GetExtensionName()
'FSo.GetExtensionName(Path As String) As String
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim extFile As String
extFile = FSo.GetExtensionName(ThisWorkbook.FullName)
MsgBox extFile
End Sub

2.16. GetFile
FSo.GetFile(FilePath As String) As File

Trả về đối tượng File.


FilePath: Bắt buộc. Là đường dẫn đầy đủ của tập tin.
Đối tượng File có 12 thuộc tính, 4 phương thức.
Ví dụ:
Sub GetFile()
'FSo.GetFile(FilePath As String) As File
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim oFile As File
Set oFile = FSo.GetFile(ThisWorkbook.FullName)
MsgBox GetFileProperties(oFile)
End Sub

Public Function GetFileProperties(ByVal oFile As File) As String


Dim Result()
ReDim Result(1 To 20)
With oFile
Result(1) = "Attributes: " & .Attributes
Result(2) = "DateCreated: " & .DateCreated

P a g e 52 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Result(3) = "DateLastAccessed: " & .DateLastAccessed


Result(4) = "DateLastModified: " & .DateLastModified
Result(5) = "Drive: " & .Drive
Result(6) = "Name: " & .Name
Result(7) = "ParentFolder: " & .ParentFolder
Result(8) = "Path: " & .Path
Result(9) = "ShortName: " & .ShortName
Result(10) = "ShortPath: " & .ShortPath
Result(11) = "Size: " & .Size
Result(12) = "Type: " & .Type
End With
ReDim Preserve Result(1 To 12)
GetFileProperties = Join(Result, vbCrLf)
End Function

Các phương thức của đối tượng File: Copy, Delete, Move, OpenTextStream
Sub FileMethods()
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim oFile As File
Set oFile = FSo.GetFile(ThisWorkbook.FullName)
'oFile.Copy (Destination As String, [OverWriteFiles As Boolean = True])
'oFile.Delete([Force As Boolean = False])
'oFile.Move(Destination As String)
'oFile.OpenAsTextStream([IOMode As IOMode = ForReading],[Format As Tristate =
TristateFalse]) As TextStream

oFile.Copy "D:\", True


End Sub

2.17. GetFileName
FSo.GetFileName(Path As String) As String

Trả về tên của tập tin gồm cả phần mở rộng hoặc tên của thư mục cho thành phần cuối cùng
trong một đường dẫn chỉ định đưa vào.
Path: Bắt buộc. Là đường dẫn của tập tin hoặc thư mục chỉ định.
Phương thức GetFileName trả về một chuỗi chứa tên tệp tin hoặc tên thư mục cho thành phần
cuối cùng trong một đường dẫn được chỉ định.
Lưu ý:
- Nếu Path là đường dẫn của File thì:
GetFileName = GetBaseName & "." & GetExtensionName
GetFileName = oFile.Name

- Nếu Path là đường dẫn của Folder thì:


GetFileName = GetBaseName

Ví dụ:
Sub GetFileName()
'FSo.GetFileName(Path As String) As String

P a g e 53 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

'1 - Nêu Path là File:


'GetFileName = GetBaseName & "." & GetExtensionName
'GetFileName = oFile.Name
'2 - Nêu Path là Folder:
'GetFileName = GetBaseName

Dim FSo As Scripting.FileSystemObject


Set FSo = New Scripting.FileSystemObject
Dim fName As String
fName = FSo.GetFileName(ThisWorkbook.FullName)
'fName = FSo.GetFileName(ThisWorkbook.Path)
MsgBox fName
End Sub

2.18. GetFolder
FSo.GetFolder(FolderPath As String) As Folder

Trả về đối tượng Folder (thư mục).


FolderPath: Bắt buộc. Là đường dẫn của thư mục chỉ định.
Đối tượng Folder có 15 thuộc tính, 4 phương thức.
Lưu ý: Hai thuộc tính của đối tượng Folder: Files và SubFolders trả về một Collection (*).
Ví dụ:
Sub GetFolder()
'FSo.GetFolder(FolderPath As String) As Folder
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim oFolder As Folder
Set oFolder = FSo.GetFolder(ThisWorkbook.Path)
MsgBox GetFolderProperties(oFolder)
End Sub

Public Function GetFolderProperties(ByVal oFolder As Folder) As String


Dim Result()
ReDim Result(1 To 20)
With oFolder
Result(1) = "Attributes: " & .Attributes
Result(2) = "DateCreated: " & .DateCreated
Result(3) = "DateLastAccessed: " & .DateLastAccessed
Result(4) = "DateLastModified: " & .DateLastModified
Result(5) = "Drive: " & .Drive
Result(6) = "Files.Count: " & .Files.Count
Result(7) = "IsRootFolder: " & .IsRootFolder
Result(8) = "Name: " & .Name
Result(9) = "ParentFolder: " & .ParentFolder
Result(10) = "Path: " & .Path
Result(11) = "ShortName: " & .ShortName
Result(12) = "ShortPath: " & .ShortPath
Result(13) = "Size: " & .Size
Result(14) = "SubFolders.Count: " & .SubFolders.Count

P a g e 54 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Result(15) = "Type: " & .Type


End With
ReDim Preserve Result(1 To 15)
GetFolderProperties = Join(Result, vbCrLf)
End Function

Các phương thức của đối tượng Folder: Copy, CreateTextFile, Delete, Move
Sub FolderMethods()
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim oFolder As Folder
Set oFolder = FSo.GetFolder(ThisWorkbook.Path)
'oFolder.Copy(Destination As String, [OverWriteFiles As Boolean = True])
'oFolder.CreateTextFile(FileName As String, [OverWrite As Boolean = True], [Unicode As
Boolean = False]) As TextStream
'oFolder.Delete(Force As Boolean = False])
'oFolder.Move(Destination As String)

oFolder.Copy "D:\", True


End Sub

2.19. GetParentFolderName
FSo.GetParentFolderName(Path As String) As String

Trả về đường dẫn của thư mục chính (thư mục cha) của thành phần cuối cùng trong một đường
dẫn chỉ định đưa vào.
Path: Bắt buộc. Là đường dẫn của một tập tin hoặc một thư mục chỉ định.
Ví dụ:
Sub GetParentFolderName()
'FSo.GetParentFolderName(Path As String) As String
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim sFolder As String
sFolder = FSo.GetParentFolderName(ThisWorkbook.FullName)
'sFolder = FSo.GetParentFolderName(ThisWorkbook.Path)
MsgBox sFolder
End Sub

2.20. GetSpecialFolder
FSo.GetSpecialFolder(SpecialFolder as SpecialFolderConst) As Folder

Trả về đối tượng Folder (thư mục) đặc biệt của hệ điều hành Windows.
SpecialFolder: Bắt buộc. Là hằng số tương ứng với thư mục đặc biệt của Windows.
0 = WindowsFolder - Contains files installed by the Windows operating system
1 = SystemFolder - Contains libraries, fonts, and device drivers
2 = TemporaryFolder - Used to store temporary files

Ví dụ:

P a g e 55 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Sub GetSpecialFolder()
'FSo.GetSpecialFolder(SpecialFolder as SpecialFolderConst) As Folder
'SpecialFolderConst:
'0=WindowsFolder - Contains files installed by the Windows operating system
'1=SystemFolder - Contains libraries, fonts, and device drivers
'2=TemporaryFolder - Used to store temporary files
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim specFolder As Folder
Set specFolder = FSo.GetSpecialFolder(0)
MsgBox specFolder.Name 'Windows
End Sub

2.21. GetTempName
FSo.GetTempName

Trả về tên một tập tin *.tmp ngẫu nhiên.

Ví dụ:
Sub GetTempName()
'FSo.GetTempName
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim tmpFile As String, specFolder As Folder
Set specFolder = FSo.GetSpecialFolder(2)
tmpFile = FSo.GetTempName
MsgBox tmpFile
'specFolder.CreateTextFile (tmpFile) 'Create a temp file in the "Temp" folder.
End Sub

2.22. MoveFile
FSo.MoveFile(Source As String, Destination As String)

Di chuyển một hoặc nhiều tập tin (Files) tới địa chỉ chỉ định.
Sourve: Bắt buộc. Tên của môt hoặc nhiều tập tin cần di chuyển, có thể sử dụng ký tự đại diện
(*?).
Destination: Đường dẫn địa chỉ cần di chuyển tới. Không thể sử dụng ký tự đại diện.
Ví dụ:
Sub MoveFile()
'FSo.MoveFile(Source As String, Destination As String)
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim sFiles As String, dPath As String
sFiles = "D:\Example\*.txt"
dPath = "E:\NewFolder"
FSo.MoveFile sFiles, dPath
End Sub

2.23. MoveFolder

P a g e 56 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

FSo.MoveFolder(Sourve As String, Destination As String)

Di chuyển một hoặc nhiều thư mục (Folders) tới địa chỉ chỉ định.
Sourve: Bắt buộc. Tên của môt hoặc nhiều thư mục cần di chuyển, có thể sử dụng ký tự đại
diện (*?).
Destination: Đường dẫn địa chỉ cần di chuyển tới. Không thể sử dụng ký tự đại diện.
Ví dụ:
Sub MoveFolder()
'FSo.MoveFolder(Sourve As String, Destination As String)
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim sFolders As String, dPath As String
sFolders = "D:\Example2\*"
dPath = "E:\NewFolder2"
FSo.MoveFolder sFolders, dPath
End Sub

2.24. OpenTextFile
FSo.OpenTextFile(FileName As String, [IOMode As IOMode = ForReading], [Create As
Boolean = False], [Format As Tristate = TristateFalse]) as TextStream

Mở ra một tệp được chỉ định và trả về một đối tượng TextStream có thể được sử dụng để truy
cập tập tin đó.
FileName: Bắt buộc. Là đường dẫn của tập tin cần mở.
IOMode: Không bắt buộc. Thiết lập kiểu mở tập tin. Mặc định là ForReading.
1 = ForReading - Mở một tập tin để đọc. Không thể ghi thêm nội dung vào tập tin
2 = ForWriting - Mở một tập tin để ghi thêm nội dung.
8 = ForAppending - Mở một tập tin và ghi vào cuối của tập tin.
Create: Không bắt buộc. Thiết lập liệu một tập tin mới có thể được tạo ra nếu tên tập tin đưa
vào không tồn tại. True tức là tạo một tập tin mới, False không tạo một tập tin mới. Mặc định là
False.
Format: Không bắt buộc. Là định dạng mở tập tin.
0 = TristateFalse - Mở tệp dưới dạng ASCII. Đây là giá trị mặc định.
-1 = TristateTrue - Mở tập tin dưới dạng Unicode.
-2 = TristateUseDefault - Mở tập tin bằng cách sử dụng hệ thống mặc định.
Ví dụ:
Sub OpenTextFile()
'FSo.OpenTextFile(FileName As String, [IOMode As IOMode = ForReading], [Create As
Boolean = False], [Format As Tristate = TristateFalse]) as TextStream
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim txtFile As TextStream, sText As String
Set txtFile = FSo.OpenTextFile("D:\Test1.txt", ForReading, False, TristateUseDefault)
sText = txtFile.ReadAll
txtFile.Close
MsgBox sText
End Sub

P a g e 57 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Public Function ReadTextFile(ByVal pathTextFile As String) As String


Dim FSo As Object
Dim txtFile As TextStream
Dim sText As String
Set FSo = CreateObject("Scripting.FileSystemObject")
Set txtFile = FSo.OpenTextFile(pathTextFile, 1, False, -2)
sText = txtFile.ReadAll
txtFile.Close
ReadTextFile = sText
End Function

3. Thuộc tính

3.1. Thuộc tính Drives của FSo


FSo.Drives

Trả về một Collection, cung cấp chi tiết về tất cả các ổ đĩa (Drives) được gắn vào hệ thống,
hoặc là vật lý hoặc là logic. Có 2 thuộc tính: Count và Item
Count: Trả về số ổ đĩa được gắn vào hệ thống.
FSo.Drives.Count

Item: Trả về đối tượng ổ đĩa (Drive) theo Key chỉ định.
FSo.Drives.Item(Key) As Drive
Hoặc
FSo.Drives(Key) As Drive

Tương đương với phương thức GetDrive của FSo: FSo.GetDrive(DriveSpec As String) As
Drive

Ví dụ:
Sub Drives()
'FSo.Drives:
'1:
'FSo.Drives.Count 'Tra ve so luong o dia gan vao he thong
'2:
'FSo.Drives.Item(Key) As Drive 'Tra ve doi tuong o dia theo key chi dinh
'FSo.Drives(Key) As Drive 'Tra ve doi tuong o dia theo key chi dinh
'= FSo.GetDrive(DriveSpec As String) As Drive 'Phuong thuc GetDrive cua FSo

Dim FSo As Scripting.FileSystemObject


Set FSo = New Scripting.FileSystemObject
Dim objDrive As Drive, countDrives As Long
countDrives = FSo.Drives.Count
MsgBox countDrives
Set objDrive = FSo.Drives.Item("C:")
MsgBox objDrive.DriveLetter
'Or:
'Set objDrive = FSo.Drives("C:")
'Or:

P a g e 58 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

'Set objDrive =FSo.GetDrive ("C:\")


End Sub

3.2. Chú thích (*):


Hai thuộc tính của đối tượng Folder: Files và SubFolders trả về một Collection (mở mục 2.18).
a. Thuộc tính Files của Folder
objFolder.Files

Trả về một Collection, cung cấp tất cả các tập tin (Files) có trong thư mục đó.
Có 2 thuộc tính: Count và Item
Count: Trả về số lượng tập tin có trong thư mục đó.
objFolder.Files.Count

Item: Trả về đối tượng File theo Key chỉ định.


objFolder.Files.Item(Key) As File
'Hoặc:
objfolder.Files(Key) As File

Tương đương với phương thức GetFile của FSo: FSo.GetFile(FilePath As String) As File
Ví dụ:
Sub FolderProperties_Files()
'objFolder.Files:
'1:
'objFolder.Files.Count 'Tra ve so luong Files trong Folder
'2:
'objFolder.Files.Item(Key) As File 'Tra ve duoi tuong File theo Key chi dinh
'objfolder.Files(Key) As File 'Tra ve duoi tuong File theo Key chi dinh
'= FSo.GetFile(FilePath As String) As File 'Phuong thuc GetFile cua FSo

Dim FSo As Scripting.FileSystemObject


Set FSo = New Scripting.FileSystemObject
Dim objFolder As Folder, countFiles As Long
Set objFolder = FSo.GetFolder(ThisWorkbook.Path)
countFiles = objFolder.Files.Count
MsgBox countFiles
End Sub

b. Thuộc tính SubFolders của Folder


objFolder.SubFolders

Trả về một Collection, cung cấp tất cả các thư mục (Folders) có trong thư mục đó.
- Có 1 phương thức: Add
Tạo mới một Folder:
objFolder.SubFolders.Add(Name As String) As Folder

Tương đương với phương thức CreateFolder của FSo: FSo.CreateFolder(Path As String) As
Folder
- Có 2 thuộc tính: Count và Item
Count: Trả về số lượng Folders có trong Folder chỉ định đưa vào.

P a g e 59 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

objFolder.SubFolders.Count

Item: Trả về đối tượng Folder theo Key chỉ định


objFolder.SubFolders.Item(Key) As Folder
'Hoặc:
objFolder.SubFolders(Key) As Folder

Tương đương với phương thức GetFolder của FSo: FSo.GetFolder(FolderPath As String) As
Folder
Ví dụ:
Sub FolderProperties_SubFolders()
'objFolder.SubFolders:
'1:
'objFolder.SubFolders.Add(Name As String) As Folder 'Tao mot Folder
'= FSo.CreateFolder(Path As String) As Folder 'Tuong duong voi phuong thuc
CreateFolder cua FSo
'2:
'objFolder.SubFolders.Count 'Tra ve so luong Folders co trong Folder dang
xet
'3:
'objFolder.SubFolders.Item(Key) As Folder 'Tra ve duoi tuong Folder theo Key chi
dinh
'objFolder.SubFolders(Key) As Folder 'Tra ve duoi tuong Folder theo Key chi
dinh
'= FSo.GetFolder(FolderPath As String) As Folder 'Tuong duong voi phuong thuc
GetFolder cua FSo
Dim FSo As Scripting.FileSystemObject
Set FSo = New Scripting.FileSystemObject
Dim objFolder As Folder, countFolders As Long, oFolder As Folder, sFolder As String
Set objFolder = FSo.GetFolder(ThisWorkbook.Path)
sFolder = "NewFolder2"
countFolders = objFolder.SubFolders.Count
If FSo.FolderExists(objFolder.Path & "\" & sFolder) = False Then
objFolder.SubFolders.Add sFolder
End If
Set oFolder = objFolder.SubFolders.Item(sFolder)
If objFolder.SubFolders.Count > countFolders Then
MsgBox "The new folder is: " & oFolder.Name
End If
End Sub

4. Một số Sub/ Function


'// Tra ve chuoi la noi dung cua text file theo duong dan chi dinh
Public Function ReadTextFile(ByVal pathTextFile As String) As String
Dim FSo As Object, txtFile As TextStream, sText As String
Set FSo = CreateObject("Scripting.FileSystemObject")
Set txtFile = FSo.OpenTextFile(pathTextFile, 1, False, -2)
sText = txtFile.ReadAll
txtFile.Close

P a g e 60 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

ReadTextFile = sText
End Function

'// Tra ve danh sach Files trong mot Folder chi dinh, theo kieu loai File chi dinh (co the su dung
ky tu dai dien *?)
'typeName=0: Tra ve danh sach ten cua File (File.Name, gom phan mo rong cua File)
'typeName=1: Tra ve danh sach ten co so cua File (BaseName, khong gom phan mo rong cua
File)
'typeName=2: Tra ve danh sach duong dan day du cua File (File.Path)
'typeName=3: Tra ve danh sach duong dan rut gon cua File (File.ShortPath)
Public Function GetFilesInFolder(ByVal pathFolder As String, ByVal extensionFile As String,
Optional ByVal typeName As Byte = 0)
Dim FSo As Object, objFolder As Folder, objFile As File, Result(), i As Long
Set FSo = CreateObject("Scripting.FileSystemObject")
Set objFolder = FSo.GetFolder(pathFolder)
extensionFile = VBA.UCase(extensionFile)
For Each objFile In objFolder.Files
If VBA.UCase(FSo.GetExtensionName(objFile)) Like extensionFile Then
i=i+1
ReDim Preserve Result(1 To i)
Select Case typeName
Case 0
Result(i) = objFile.Name
Case 1
Result(i) = FSo.GetBaseName(objFile.Path)
Case 2
Result(i) = objFile.Path
Case 3
Result(i) = objFile.ShortPath
End Select
End If
Next objFile
GetFilesInFolder = Result
End Function

'// Tra ve duong dan day du cua Folder duoc chon. Neu khong chon thi tra ve chuoi rong
(len(chuoi)=0)
Public Function GetPathFolder(ByVal pathFolder As String) As String
Dim fDlog As FileDialog, sItem As String
Set fDlog = Application.FileDialog(msoFileDialogFolderPicker)
With fDlog
.Title = "Select a Folder"
.AllowMultiSelect = False
.InitialFileName = pathFolder
If .Show <> -1 Then GoTo NextCode
sItem = .SelectedItems(1)
End With
NextCode:
GetPathFolder = sItem

P a g e 61 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Set fDlog = Nothing


End Function

'// Xoa Files trong Folder chi dinh, loai File chi dinh (co the su dung ky tu dai dien *?)
'=== Ghi chu: Can trong khi su dung ===
Public Sub DeleteFiles(ByVal pathFolder As String, ByVal extensionFile As String, Optional
ByVal Force As Boolean = False)
Dim FSo As Object, objFile As File
Set FSo = CreateObject("Scripting.FileSystemObject")
extensionFile = VBA.UCase(extensionFile)
With FSo.GetFolder(pathFolder)
For Each objFile In .Files
If VBA.UCase(FSo.GetExtensionName(objFile)) Like extensionFile Then
FSo.DeleteFile objFile, Force
End If
Next objFile
End With
End Sub

'// Xoa tat ca Folders trong Folder chi dinh


'=== Ghi chu: Can trong khi su dung ===
Public Sub DeleteFolders(ByVal pathFolder As String, Optional ByVal Force As Boolean =
False)
Dim FSo As Object, objFolder As Folder
Set FSo = CreateObject("Scripting.FileSystemObject")
With FSo.GetFolder(pathFolder)
For Each objFolder In .SubFolders
FSo.DeleteFolder objFolder, Force
Next
End With
End Sub

'// Xoa tat ca Files va Folders trong Folder chi dinh


'=== Ghi chu: Can trong khi su dung ===
Public Sub DeleteAll(ByVal pathFolder As String, Optional ByVal Force As Boolean = False)
Dim FSo As Object, objFolder As Folder, objFile As File
Set FSo = CreateObject("Scripting.FileSystemObject")
With FSo.GetFolder(pathFolder)
For Each objFolder In .SubFolders
FSo.DeleteFolder objFolder, Force
Next
For Each objFile In .Files
FSo.DeleteFile objFile, Force
Next objFile
End With
End Sub

P a g e 62 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 13. Collection


>> Download: Collection
Collection trong VBA là một cấu trúc dữ liệu đơn giản có sẵn trong VBA để lưu trữ các đối
tượng. Các collections trong VBA linh hoạt hơn so với Array trong VBA vì chúng không giới
hạn ở kích cỡ của chúng vào bất kỳ thời điểm nào và không yêu cầu phải dò lại kích thước bằng
tay.
Collection rất hữu dụng khi ta không muốn sử dụng các cấu trúc dữ liệu phức tạp hơn (nhưng
khá tương tự) như ArrayList hay Dictionary.

1. Khai báo Collection


Dim myCol As Collection
Set myCol = New Collection

2. Các phương thức (có 4 phương thức)

2.1. Add
myCol.Add (Item, [Key], [Before], [After])

Thêm một Item vào collection.


Item: Bắt buộc. Item nhận kiểu dữ liệu là số hoặc chuỗi bất kỳ, giá trị đơn hoặc một mảng
(array).
Key: Không bắt buộc. Nếu có nhập Key thì yêu cầu Key đó chưa tồn tại trong collection, Key
chỉ nhận giá trị kiểu chuỗi.
Before: Không bắt buộc. Chỉ định vị trí của Item thêm vào trước một Item đã có trong
collection (theo chỉ số của Item đó).
After: Không bắt buộc. Chỉ định vị trí của Item thêm vào đứng sau một Item đã có trong
collection (theo chỉ số của Item đó).
Ví dụ:
Sub AddMethod()
Dim myCol As Collection
Set myCol = New Collection
'mycol.Add (Item, [Key], [Before], [After]) '
myCol.Add 2 'Item: 2 '
myCol.Add "B" 'Item: 2, "B" '
myCol.Add "C", key:="KeyC" 'Items: 2, "B", "C" '
myCol.Add "A", "KeyA", before:=2 'Items: 2, "A","B","C" '
myCol.Add 1, , After:=4 'Items: 2, "A","B","C",1 '
myCol.Add Array(5, 20) 'Items: 2, "A","B","C",1, array(5,20)'
End Sub

2.2. Count
myCol.Count

Trả về số Items có trong collection.


Ví dụ:
Sub CountMethod()
Dim myCol As Collection, i As Long
Set myCol = New Collection
For i = 1 To 10

P a g e 63 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

myCol.Add i
Next i
MsgBox myCol.Count
End Sub

2.3. Item
myCol.Item (Index)
'Hoặc:
myCol(Index)
'Hoặc:
myCol(Key)

Gọi tới Item của collection theo chỉ số của Item hoặc theo Key ứng với Item đó.
Ví dụ:
Sub ItemMethod()
Dim myCol As Collection
Set myCol = New Collection
myCol.Add "A", "KeyA"
MsgBox myCol.Item(1)
MsgBox myCol(1)
MsgBox myCol("KeyA")
End Sub

2.4. Remove
mycol.Remove(Index)
'Hoặc
mycol.Remove(Key)

Xóa một Item trong collection theo chỉ số của Item hoặc Key ứng với Item đó.
Ví dụ:
Sub Remove()
Dim myCol As Collection
Set myCol = New Collection
myCol.Add "A", "KeyA"
myCol.Add 10, "2"
myCol.Add 20, "Key3"
myCol.Remove (2)
myCol.Remove ("Key3")
MsgBox myCol.Count
End Sub

3. Ứng dụng
- Lọc loại trùng
- Sắp xếp dữ liệu
'// Kiem tra su ton tai cua mot key trong Collection'
Public Function KeyExists(myCol As Collection, ByVal keyCheck As String) As Boolean
KeyExists = False
On Error GoTo EndFunction
myCol.Item keyCheck

P a g e 64 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

KeyExists = True
EndFunction:
End Function

'// Loc loai trung mot cot'


Public Function UniqueColumnCollection(ByVal Rng As Range) As Variant
If Rng.Count = 1 Then UniqueColumnCollection = Rng.Value: Exit Function
Dim myCol As Collection, i As Long, j As Long, arr(), Result(), sKey As Variant
Set myCol = New Collection
arr = Rng.Value
For i = LBound(arr, 1) To UBound(arr, 1)
sKey = arr(i, 1)
If sKey <> "" Then
If KeyExists(myCol, sKey) = False Then
myCol.Add "", sKey
j=j+1
ReDim Preserve Result(1 To j)
Result(j) = sKey
End If
End If
Next i
UniqueColumnCollection = Result
End Function

'// Sort A-Z cac Item trong Collection'


Public Sub SortingCollection(myCol As Collection, firstIndex As Long, lastIndex As Long)
Dim valCentre As Variant, vTemp As Variant
Dim valMin As Long
Dim valMax As Long
valMin = firstIndex
valMax = lastIndex
valCentre = myCol((firstIndex + lastIndex) \ 2)
Do While valMin <= valMax
Do While myCol(valMin) < valCentre And valMin < lastIndex
valMin = valMin + 1
Loop
Do While valCentre < myCol(valMax) And valMax > firstIndex
valMax = valMax - 1
Loop
If valMin <= valMax Then
' Swap values
vTemp = myCol(valMin)
myCol.Add myCol(valMax), After:=valMin
myCol.Remove valMin
myCol.Add vTemp, before:=valMax
myCol.Remove valMax + 1
' Move to next positions
valMin = valMin + 1
valMax = valMax - 1

P a g e 65 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

End If
Loop
If firstIndex < valMax Then SortingCollection myCol, firstIndex, valMax
If valMin < lastIndex Then SortingCollection myCol, valMin, lastIndex
End Sub

'// Truyen cac Items cua Collection vao Array (2 chieu)


Public Function CollectionToArray(myCol As Collection) As Variant
Dim arr() As Variant, i As Long
ReDim arr(1 To myCol.Count, 1 To 1)
For i = 1 To myCol.Count
arr(i, 1) = myCol.Item(i)
Next i
CollectionToArray = arr
End Function

P a g e 66 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 14. Hashtable


>> Download: Hastable
Hashtable là một thư viện nằm trong “System.Collections” của .NET Framework. Cho phép lưu
trữ dữ liệu ở dạng mảng với Key riêng duy nhất, cho phép chèn và tìm kiếm đối tượng (Item)
rất nhanh, kể cả với dữ liệu có kích cỡ lớn.
Yêu cầu: Hệ thống phải cài đặt .NET Framework

1. Khai báo Hashtable

1.1. Kiểu khai báo sớm


(Không có Tooltip khi gọi Hashtable, phải thiết lập trong Tools/References)
- Trong cửa sổ VBA, Tools menu, References.
- Tìm và check vào mục “mscorlib.dll” trong cửa sổ References – VBAProject.

Khai báo trong code:


Dim HTbl As New Hashtable

1.2. Kiểu khai báo muộn


(Không có Tooltip khi gọi Hashtable, không cần thiết lập trong Tools/References).
Khai báo trong code:
Dim HTbl As Object
Set HTbl = CreateObject("System.Collections.Hashtable")

2. Các phương thức (có 5 phương thức)

2.1. Add
HTbl.Add Key, Item

Thêm một Item vào Hashtable.


Key: Bắt buộc. Key nhận kiểu dữ liệu là số hoặc chuỗi bất kỳ. Yêu cầu Key phải duy nhất trong
Hashtable, nếu Key đó đã tồn tại thì xảy ra lỗi.
Item: Bắt buộc. Item nhận kiểu dữ liệu là số hoặc chuỗi bất kỳ, giá trị đơn hoặc một mảng
(array).

Ví dụ:
Sub AddMethod()
Dim HTbl As Object
Set HTbl = CreateObject("System.Collections.Hashtable")
'HTbl.Add Key, Item'
'Key: number + string, Duy nhat. Gap loi khi Key da ton tai trong HTbl'
'Item: number + string'
HTbl.Add 10, 100
HTbl.Add "KeyA", 200
HTbl.Add "KeyB", "TextB"
HTbl.Add 20, 5
HTbl.Add "KeyC", ""
HTbl.Add "KeyD", Array(20, 25)
End Sub

P a g e 67 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

2.2. Count
HTbl.Count

Trả về số Items có trong Hashtable.


Ví dụ:
Sub CountMethod()
Dim HTbl As Object
Set HTbl = CreateObject("System.Collections.Hashtable")
'HTbl.Count'
Dim i As Long
For i = 1 To 10
HTbl.Add "Key" & i, i
Next i
MsgBox HTbl.Count '10'
End Sub

2.3. Item
HTbl.Item (Key)
'Hoặc:'
HTbl(Key)

Gọi tới Item của Hashtable theo Key chỉ định.


Nếu Key chỉ định đưa vào chưa tồn tại trong Hashtable thì không xảy ra lỗi và kết quả trả về là
rỗng.
Ví dụ:
Sub ItemMethod()
Dim HTbl As Object
Set HTbl = CreateObject("System.Collections.Hashtable")
'HTbl.Item(Key)'
'HTbl(Key)'
HTbl.Add 10, 100
HTbl.Add "KeyA", 200
HTbl("KeyA") = 500
MsgBox HTbl.Item(10) '100'
MsgBox HTbl.Item("KeyA") '500'
End Sub

2.4. Remove
HTbl.Remove(Key)

Xóa một Item trong Hashtable theo Key chỉ định ứng với Item đó.
Ví dụ:
Sub RemoveMethod()
Dim HTbl As Object
Set HTbl = CreateObject("System.Collections.Hashtable")
'HTbl.Remove(Key)'
Dim i As Long
For i = 1 To 10

P a g e 68 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

HTbl.Add "Key" & i, i


Next i
HTbl.Remove ("Key4")
MsgBox HTbl.Count '9'
End Sub

2.5. ContainsKey
HTbl.ContainsKey(Key)

Kiểm tra sự tồn tại của một Key trong Hashtable. Trả về True nếu Key đó tồn tại, ngược lại trả
về False.
Ví dụ:
Sub ContainsKeyMethod()
Dim HTbl As Object
Set HTbl = CreateObject("System.Collections.Hashtable")
'HTbl.ContainsKey(Key)'
HTbl.Add 10, 100
HTbl.Add "KeyA", 200
MsgBox HTbl.Containskey(10) 'True'
MsgBox HTbl.Containskey("KeyA") 'True'
MsgBox HTbl.Containskey("KeyX") 'False'
End Sub

2.6. ContainsValue
HTbl.ContainsValue(Value)

Kiểm tra sự tồn tại giá trị của Item trong Hashtable. Trả về True nếu giá trị đó đã tồn tại, ngược
lại trả về False.
Ví dụ:
Sub ContainsValueMethod()
Dim HTbl As Object
Set HTbl = CreateObject("System.Collections.Hashtable")
'HTbl.ContainsValue(Value)'
HTbl.Add 10, 100
HTbl.Add "KeyA", "TextA"
MsgBox HTbl.ContainsValue(100) 'True'
MsgBox HTbl.ContainsValue("TextA") 'True'
MsgBox HTbl.ContainsValue("TextB") 'False'
End Sub

3. Ứng dụng
- Lọc loại trùng
-…

3.1. Hàm lọc loại trùng trong một cột


'// Loc loai trung mot cot
Public Function UniqueColumnHashtable(ByVal Rng As Range) As Variant
If Rng.Count = 1 Then UniqueColumnHashtable = Rng.Value: Exit Function
Dim HTbl As Object, i As Long, j As Long, arr(), Result(), sKey As Variant

P a g e 69 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Set HTbl = CreateObject("System.Collections.Hashtable")


arr = Rng.Value
For i = LBound(arr, 1) To UBound(arr, 1)
sKey = arr(i, 1)
If sKey <> "" Then
If HTbl.Containskey(sKey) = False Then
HTbl.Add sKey, ""
j=j+1
ReDim Preserve Result(1 To j)
Result(j) = sKey
End If
End If
Next i
UniqueColumnHashtable = Result
End Function

P a g e 70 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 15. Stack


>> Download: Stack object
Stack là một thư viện nằm trong “System.Collections” của .NET Framework. Cho phép lưu trữ
dữ liệu (items) có kích cỡ lớn, rất hữu ích trong các tình huống khi cần xử lý trước nhất những
items mà truyền vào Stack sau cùng.
Đây là cấu trúc dữ liệu dựng theo ngăn xếp để thực hiện tích chất LIFO (last in first out).
Yêu cầu: Hệ thống phải cài đặt .NET Framework

1. Khai báo Stack

1.1. Kiểu khai báo sớm


(Không có Tooltip khi gọi Stack, phải thiết lập trong Tools/References)
- Trong cửa sổ VBA, Tools menu, References.
- Tìm và check vào mục “mscorlib.dll” trong cửa sổ References – VBAProject.
Khai báo trong code:
Dim oStack As New Stack

1.2. Kiểu khai báo muộn


(Không có Tooltip khi gọi Stack, không cần thiết lập trong Tools/References).
Khai báo trong code:
Dim oStack As Object
Set oStack = CreateObject("System.Collections.Stack")

2. Các phương thức, thuộc tính

2.1. Push
oStack.Push Item

Thêm một Item vào vị trí trên cùng (top) của Stack.
Item nhận kiểu dữ liệu bất kỳ (kiểu số hoặc chuỗi), giá trị đơn hoặc một mảng (array).
Ví dụ:
Sub PushMethod()
'Dim oStack As New Stack'
Dim oStack As Object
Set oStack = CreateObject("System.Collections.Stack")
'oStack.Push Item'
oStack.Push 5
oStack.Push "TextA"
oStack.Push ""
End Sub

2.2. Count
oStack.Count

Trả về số Items có trong Stack.


Ví dụ:
Sub CountProperty()
Dim oStack As Object
Set oStack = CreateObject("System.Collections.Stack")

P a g e 71 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

'oStack.Count'
oStack.Push 5
oStack.Push "TextA"
MsgBox oStack.Count '2'
End Sub

2.3. Peek
oStack.Peek

Trả về Item trên cùng của Stack và không xóa Item đó.
Ví dụ:
Sub PeekMethod()
Dim oStack As Object, i As Long
Set oStack = CreateObject("System.Collections.Stack")
'oStack.Peek'
For i = 1 To 10
oStack.Push "Value-" & i
Next i
MsgBox oStack.Peek 'Value-10'
End Sub

2.4. Pop
oStack.Pop

Xóa và trả về Item trên cùng của Stack.


Ví dụ:
Sub PopMethod()
Dim oStack As Object, i As Long, sValue As String
Set oStack = CreateObject("System.Collections.Stack")
'oStack.Pop'
For i = 1 To 10
oStack.Push "Value-" & i
Next i
sValue = oStack.Pop
MsgBox sValue 'Value-10'
MsgBox oStack.Count '9'
End Sub

2.5. Contains
oStack.Contains

Kiểm tra sự tồn tại của một Item trong Stack. Trả về True nếu Item đó tồn tại, ngược lại trả về
False.
Ví dụ:
Sub ContainsMethod()
Dim oStack As Object
Set oStack = CreateObject("System.Collections.Stack")
'oStack.Contains'
oStack.Push 5

P a g e 72 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

oStack.Push "TextA"
MsgBox oStack.Contains(5) 'True'
MsgBox oStack.Contains("TextA") 'True'
MsgBox oStack.Contains("TextB") 'False
End Sub

2.6. ToArray
oStack.ToArray

Sao chép các Item trong Stack vào một mảng (Array). Mảng trả về là mảng một chiều, chỉ số
cận dưới của mảng luôn bằng 0, cho dù thiết lập Option Base 1.
Ví dụ:
Sub ToArrayMethod()
Dim oStack As Object, i As Long, arr()
Set oStack = CreateObject("System.Collections.Stack")
'oStack.ToArray Mang 1 chieu,cac phan tu trong mang xep nguoc, khong phu thuoc
Option Base 1'
For i = 1 To 10
oStack.Push i
Next i
arr = oStack.ToArray
MsgBox arr(0) '10'
End Sub

2.7. Clear
oStack.Clear

Xóa tất cả các Items có trong Stack.


Ví dụ:
Sub ClearMethod()
Dim oStack As Object, i As Long
Set oStack = CreateObject("System.Collections.Stack")
'oStack.Clear'
For i = 1 To 10
oStack.Push i
Next i
oStack.Clear
MsgBox oStack.Count '0'
End Sub

2.8. Clone
oStack.Clone

Sao chép toàn bộ Stack đã dựng sang một Stack mới.


Ví dụ:
Sub CloneMethod()
Dim oStack As Object, newStack As Object
Set oStack = CreateObject("System.Collections.Stack")
'oStack.Clone'

P a g e 73 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

oStack.push 20
Set newStack = oStack.Clone
MsgBox newStack.Peek '20'
End Sub

2.9. ToString
oStack.ToString

Trả về tên đối tượng hiện hành, tức là “System.Collections.Stack”.


Ví dụ:
Sub ToStringMethod()
Dim oStack As Object, sName As String
Set oStack = CreateObject("System.Collections.Stack")
'oStack.ToString'
sName = oStack.ToString
MsgBox sName 'System.Collections.Stack'
End Sub

2.10. GetHashCode
oStack.GetHashCode

...

3. Ứng dụng
- Lọc loại trùng
-…

3.1. Hàm lọc loại trùng trong một cột


'// Loc loai trung mot cot
Public Function UniqueColumnStack(ByVal Rng As Range) As Variant
If Rng.Count = 1 Then UniqueColumnStack = Rng.Value: Exit Function
Dim HTbl As Object, i As Long, j As Long, arr(), Result(), sKey As Variant
Set HTbl = CreateObject("System.Collections.Stack")
arr = Rng.Value
For i = LBound(arr, 1) To UBound(arr, 1)
sKey = arr(i, 1)
If sKey <> "" Then
If HTbl.Containskey(sKey) = False Then
HTbl.Add sKey, ""
j=j+1
ReDim Preserve Result(1 To j)
Result(j) = sKey
End If
End If
Next i
UniqueColumnStack = Result
End Function

3.2. Hàm truyền các Items của Stack sang mảng 2 chiều

P a g e 74 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

'// Truyen cac Items cua Stack sang mang 2 chieu'


Public Function StackToArray2D(oStack As Object, Optional ByVal Reverse As Boolean =
False) As Variant
Dim iCount As Long
iCount = oStack.Count
If iCount = 0 Then Exit Function
Dim Result(), i As Long, j As Long, arr()
ReDim Result(1 To iCount, 1 To 1)
arr = oStack.ToArray
If Reverse = False Then
For i = LBound(arr) To UBound(arr) Step 1
j=j+1
Result(j, 1) = arr(i)
Next i
Else
For i = UBound(arr) To LBound(arr) Step -1
j=j+1
Result(j, 1) = arr(i)
Next i
End If
StackToArray2D = Result
End Function

3.3. Ví dụ so sánh tốc độ Add Keys với kiểu dữ liệu là kiểu số:

Stack:
Sub AddKeys_Stack()
Dim TT As Double
TT = Timer
Dim oStack As Object
Set oStack = CreateObject("System.Collections.Stack")
Dim x As Long, y As Long, i As Long
x = 1000000000
y = 1000020000
For i = x To y
If oStack.Contains(i) = False Then
oStack.push i
End If
Next i
Set oStack = Nothing
MsgBox Round(Timer - TT, 2) '1.64-1.78 giây'
End Sub

Hashtable:
Sub AddKeys_Hashtable()
Dim TT As Double
TT = Timer
Dim HTbl As Object
Set HTbl = CreateObject("System.Collections.Hashtable")

P a g e 75 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Dim x As Long, y As Long, i As Long


x = 1000000000
y = 1000020000
For i = x To y
If HTbl.Containskey(i) = False Then
HTbl.Add i, ""
End If
Next i
Set HTbl = Nothing
MsgBox Round(Timer - TT, 2) '0.19-0.20 giây'
End Sub

Dictionary:
Sub AddKeys_Dictionary()
Dim TT As Double
TT = Timer
Dim Dic As Object
Set Dic = CreateObject("Scripting.Dictionary")
Dim x As Long, y As Long, i As Long
x = 1000000000
y = 1000020000
For i = x To y
If Dic.Exists(i) = False Then
Dic.Add i, ""
End If
Next i
Set Dic = Nothing
MsgBox Round(Timer - TT, 2) '5.96-6.09 giây'
End Sub

P a g e 76 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 16. Queue


>> Download: Queue object

Queue là một thư viện nằm trong “System.Collections.” của .NET Framework. cùng.
Đây là cấu trúc dữ liệu dựng theo hàng để thực hiện tính chất FIFO (First In - First Out / Vào
trước - Ra trước).
Cho phép lưu trữ dữ liệu (items) có kích cỡ lớn, rất hữu ích trong các tình huống muốn lưu trữ
các Items theo thứ tự chỉ định.
Yêu cầu: Hệ thống phải cài đặt .NET Framework

1. Khai báo Queue

1.1. Kiểu khai báo sớm


(Không có Tooltip khi gọi Queue, phải thiết lập trong Tools/References)
- Trong cửa sổ VBA, Tools menu, References.
- Tìm và check vào mục “mscorlib.dll” trong cửa sổ References – VBAProject.
Khai báo trong code:
Dim oQueue As New Queue

1.2. Kiểu khai báo muộn


(Không có Tooltip khi gọi Queue, không cần thiết lập trong Tools/References).
Khai báo trong code:
Dim oQueue As Object
Set oQueue = CreateObject("System.Collections.Queue")

2. Các phương thức, thuộc tính

2.1. Count Property


oQueue.Count

Trả về số Items có trong Queue.


Ví dụ:
Sub CountProperty()
Dim oQueue As Object
Set oQueue = CreateObject("System.Collections.Queue")
'oQueue.Count'
oQueue.Enqueue 5
oQueue.Enqueue "TextA"
MsgBox oQueue.Count '2'
End Sub

2.2. Enqueue
oQueue.Enqueue Item

Thêm một Item vào vị trí cuối cùng (end) của Queue.
Item nhận kiểu dữ liệu bất kỳ (kiểu số hoặc chuỗi), giá trị đơn hoặc một mảng (array).
Ví dụ:
Sub EnqueueMethod()
Dim oQueue As Object

P a g e 77 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Set oQueue = CreateObject("System.Collections.Queue")


'oQueue.Enqueue Item'
oQueue.Enqueue 5
oQueue.Enqueue "TextA"
oQueue.Enqueue ""
oQueue.Enqueue Array(20, 40)
End Sub

2.3. Peek
oQueue.Peek
Trả về Item đầu tiên của Queue và không xóa Item đó.
Ví dụ:
Sub PeekMethod()
Dim oQueue As Object, i As Long
Set oQueue = CreateObject("System.Collections.Queue")
'oQueue.Peek'
For i = 1 To 10
oQueue.Enqueue "Value-" & i
Next i
MsgBox oQueue.Peek 'Value-1'
End Sub

2.4. Dequeue
oQueue.Dequeue

Xóa và trả về Item đầu tiên của Queue.


Ví dụ:
Sub DequeueMethod()
Dim oQueue As Object, i As Long, sValue As String
Set oQueue = CreateObject("System.Collections.Queue")
'oQueue.Dequeue'
For i = 1 To 10
oQueue.Enqueue "Value-" & i
Next i
sValue = oQueue.Dequeue
MsgBox sValue 'Value-1'
MsgBox oQueue.Count '9'
End Sub

2.5. Contains
oQueue.Contains

Kiểm tra sự tồn tại của một Item trong Queue. Trả về True nếu Item đó tồn tại, ngược lại trả về
False.
Ví dụ:
Sub ContainsMethod()
Dim oQueue As Object
Set oQueue = CreateObject("System.Collections.Queue")
'oQueue.Contains'

P a g e 78 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

oQueue.Enqueue 5
oQueue.Enqueue "TextA"
MsgBox oQueue.Contains(5) 'True'
MsgBox oQueue.Contains("TextA") 'True'
MsgBox oQueue.Contains("TextB") 'False
End Sub

2.6. ToArray
oQueue.ToArray

Sao chép các Item trong Queue vào một mảng (Array). Mảng trả về là mảng một chiều, chỉ số
cận dưới của mảng luôn băng 0, cho dù thiết lập Option Base 1.
Ví dụ:
Sub ToArrayMethod()
Dim oQueue As Object, i As Long, arr()
Set oQueue = CreateObject("System.Collections.Queue")
'oQueue.ToArray Mang 1 chieu, khong phu thuoc Option Base 1'
For i = 1 To 10
oQueue.Enqueue "Value-" & i
Next i
arr = oQueue.ToArray
MsgBox arr(0) 'Value-1'
End Sub

2.7. ToString
oQueue.ToString

Trả về tên đối tượng hiện hành, tức là “System.Collections.Queue”.


Ví dụ:
Sub ToStringMethod()
Dim oQueue As Object, sName As String
Set oQueue = CreateObject("System.Collections.Queue")
'oQueue.ToString'
sName = oQueue.ToString
MsgBox sName 'System.Collections.Queue'
End Sub

2.8. Clear
oQueue.Clear

Xóa tất cả các Items có trong Queue.


Ví dụ:
Sub ClearMethod()
Dim oQueue As Object, i As Long
Set oQueue = CreateObject("System.Collections.Queue")
'oQueue.Clear'
For i = 1 To 10
oQueue.Enqueue i
Next i

P a g e 79 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

oQueue.Clear
MsgBox oQueue.Count '0'
End Sub

2.9. Clone
oQueue.Clone

Sao chép toàn bộ Queue đã dựng sang một Queue mới.


Ví dụ:
Sub CloneMethod()
Dim oQueue As Object, newQueue As Object
Set oQueue = CreateObject("System.Collections.Queue")
'oQueue.Clone'
oQueue.Enqueue 20
Set newQueue = oQueue.Clone
MsgBox newQueue.Peek '20'
End Sub

3. Ứng dụng
- Lọc loại trùng
-…

3.1. Hàm lọc loại trùng trong một cột


'// Loc loai trung mot cot'
Public Function UniqueColumnQueue(ByVal Rng As Range) As Variant
If Rng.Count = 1 Then UniqueColumnQueue = Rng.Value: Exit Function
Dim oQueue As Object, i As Long, j As Long, arr(), Result(), sKey As Variant
Set oQueue = CreateObject("System.Collections.Queue")
arr = Rng.Value
For i = LBound(arr, 1) To UBound(arr, 1)
sKey = arr(i, 1)
If sKey <> "" Then
If oQueue.Contains(sKey) = False Then
oQueue.Enqueue sKey
j=j+1
ReDim Preserve Result(1 To j)
Result(j) = sKey
End If
End If
Next i
UniqueColumnQueue = Result
End Function

P a g e 80 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 17. SortedList


>> Download: Sortedlist object

SortedList là một thư viện nằm trong “System.Collections” của .NET Framework.
SortedList lưu trữ các Items theo Keys tương ứng thành cặp, được sắp xếp theo các Keys, cho
phép truy cập tới Item theo Key hoặc chỉ mục (index) ứng với Item đó.
Yêu cầu: Hệ thống phải cài đặt .NET Framework v1.1 trở lên.

1. Khai báo SortedList

1.1. Kiểu khai báo sớm


(Không có Tooltip khi gọi SortedList, phải thiết lập trong Tools/References)
- Trong cửa sổ VBA, Tools menu, References.
- Tìm và check vào mục “mscorlib.dll” trong cửa sổ References – VBAProject.
Khai báo trong code:
Dim oSList As New SortedList

1.2. Kiểu khai báo muộn


(Không có Tooltip khi gọi SortedList, không cần thiết lập trong Tools/References).
Khai báo trong code:
Dim oSList As Object
Set oSList = CreateObject("System.Collections.SortedList")

2. Các thuộc tính

2.1. Count
oSList.Count

Trả về số lượng phần tử (Items) thực sự tồn tại trong SortedList.


Ví dụ:
Sub CountProperty()
'oSList.Count'
Dim oSList As Object, i As Long
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add "Key-" & i, i
Next i
oSList.Add "Key-", Array(2, 5)
MsgBox oSList.Count '6'
End Sub

2.2. Capacity
oSList.Capacity

Trả về số lượng các phần tử hoặc đặt (thiết lập) số lượng các phần tử mà SortedList có thể lưu
trữ.
+ Các lỗi xảy ra đặt số lượng các phần tử cho SortedList:
- Khi giá trị của Capacity nhỏ hơn số lượng phần từ đã tồn tại trong SortedList (count).

P a g e 81 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

- Khi giá trị của Capacity trả về SortedList có kích thước vượt dung lượng bộ nhớ có thể dùng
của hệ thống (OutOfMemoryException).
+ Capacity luôn luôn lớn hơn hoặc bằng Count. Nếu Count vượt quá Capacity trong khi thêm
các phần tử, Capacity sẽ tự động tăng lên bằng cách tái phân bổ lại mảng nội bộ trước khi sao
chép các phần tử cũ và thêm các phần tử mới.
+ Có thể giảm Capacity bằng cách dùng phương thức TrimToSize hoặc bằng cách thiết lập giá
trị Capacity cụ thể (nhưng phải đảm bảo >= Count, nếu không sẽ xảy ra lỗi). Khi giá trị của
Capacity được xác định cụ thể, mảng nội bộ cũng được phân bổ lại để đáp ứng dung lượng đã
xác định.
Ví dụ:
Sub CapacityProperty()
'oSList.Capacity'
Dim oSList As Object, vCnt As Long, vCty As Long, i As Long
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add "Key-" & i, i
Next i
vCnt = oSList.Count '5'
vCty = oSList.capacity '16'
oSList.capacity = 5
MsgBox oSList.capacity '5'
End Sub

2.3. Item
oSList.Item(Key)
'Hoặc:'
oSList(Key)

Trả về giá trị của Item theo Key chỉ định trong SortedList, hoặc gán giá trị mới cho Item theo
Key của Item đó.
- Nếu gán một giá trị cho một Item theo một Key chưa tồn tại trong SortedList thì SortedList tự
động thêm Key đó, và Item đó có giá trị vừa đưa vào.
Ví dụ:
Sub ItemProperty()
'oSList.Item(Key) '
'oSList(Key) '
Dim oSList As Object, i As Long
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add "Key-" & i, ""
Next i
oSList.Item("Key-1") = 100
MsgBox oSList("Key-1") '100'
oSList("KeyA") = 20
MsgBox oSList.Count '6'
End Sub

3. Các phương thức

P a g e 82 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

3.1. Add
oSList.Add Key, Item

Thêm một Item vào SortedList theo Key chỉ định.


Key: Phải duy nhất trong SortedList và khác null. Key nhận kiểu dữ liệu hoặc là số hoặc là
chuỗi.
Item: Nhận kiểu dữ liệu bất kỳ (kiểu số hoặc chuỗi, null), giá trị của Items có thể trùng nhau,có
thể là một trị đơn, hoặc một mảng (array).
Chỉ số đầu tiên của Key/ Item trong SortedList bằng 0.
Khi một Item được thêm vào, nó được chèn vào SortedList theo thứ tự sắp xếp chính xác theo
Keys, và chỉ mục (Index) của nó được thiết lập tương ứng phù hợp theo Key.

Ví dụ:
Sub AddMethod()
'oSList.Add Key, Item '
'Key: OR number OR string, <>null'
'Item: number, string, array'
'First index = 0 '
Dim oSList As Object
Set oSList = CreateObject("System.Collections.SortedList")
oSList.Add "5", 20
oSList.Add "KeyA", "Item2"
oSList.Add "KeyB", ""
oSList.Add "KeyC", Array(12, 40)
End Sub

3.2. Clear
oSortedList.Clear

Xóa toàn bộ các Items trong SortedList.


Ví dụ:
Sub ClearMethod()
'oSList.Clear'
Dim oSList As Object, i As Long
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add i, ""
Next i
oSList.Clear
MsgBox oSList.Count '0'
End Sub

3.3. Clone
oSortedList.Clone

Tạo một bản sao từ SortedList đã có.


Ví dụ:

P a g e 83 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Sub CloneMethod()
'oSList.Clone'
Dim oSList As Object, i As Long, newSList As Object
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add i, ""
Next i
Set newSList = oSList.Clone
MsgBox newSList.Count '5'
End Sub

3.4. Contains / ContainsKey


oSList.Contains(Key)
oSList.ContainsKey(Key)

Kiểm tra sự tồn tại của một Key trong SortedList. Trả về True nếu Key đã tồn tại trong
SortedList, ngược lại trả về False.
Lưu ý: Key chỉ định kiểm tra phải cùng kiểu dữ liệu (số hoặc chuỗi) với kiểu dữ liệu của Key
đã có trong SortedList, nếu không xảy ra lỗi.
Ví dụ:
Sub ContainsMethod()
'oSList.Contains(Key)'
Dim oSList As Object, i As Long, sKey As String
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add "Key-" & i, i
Next i
sKey = "Key-2"
MsgBox oSList.Contains(sKey) 'True'
End Sub

Sub ContainsKeyMethod()
'oSList.ContainsKey(Key)'
Dim oSList As Object, i As Long, sKey As String
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add "Key-" & i, i
Next i
sKey = "Key-5"
MsgBox oSList.ContainsKey(sKey) 'True'
End Sub

3.5. ContainsValue
oSList.ContainsKey(Key)

Kiểm tra sự tồn tại giá trị của một Item trong SortedList. Trả về True nếu giá trị đó đã tồn tại
trong SortedList, ngược lại trả về False.
Ví dụ:

P a g e 84 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Sub ContainsValueMethod()
'oSList.ContainsKey(Key)'
Dim oSList As Object
Set oSList = CreateObject("System.Collections.SortedList")
oSList.Add "KeyA", 2
oSList.Add "KeyB", ""
oSList.Add "KeyC", "Item3"
MsgBox oSList.ContainsValue(2) 'True'
MsgBox oSList.ContainsValue("") 'True'
MsgBox oSList.ContainsValue("Item4") 'False'
End Sub

3.6. GetByIndex
oSList.GetByIndex(Index)

Trả về giá trị của một Item trong SortedList theo chỉ mục (Index) chỉ định.
Ví dụ:
Sub GetByIndexMethod()
'oSList.GetByIndex(Index) //Index = 0 : Count-1 / Return: Item'
Dim oSList As Object, i As Long, sKey
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add "Key-" & i, "Value-" & i
Next i
sKey = oSList.GetByIndex(0)
MsgBox sKey '"Value-1"'
End Sub

3.7. GetKey
oSList.GetKey(Index)

Trả về một Key có trong SortedList theo chỉ mục (Index) chỉ định.
Index: Có giá trị từ 0 tới Count-1.
Ví dụ:
Sub GetKeyMethod()
'oSList.GetKey(Index) //Index = 0 : Count-1 '
Dim oSList As Object, i As Long, sKey
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add "Key-" & i, i
Next i
sKey = oSList.GetKey(0)
MsgBox sKey '"Key-1"'
End Sub

3.8. GetKeyList
oSList.GetKeyList

P a g e 85 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Trả về một đối tượng IList (System.Collections.IList) chứa toàn bộ Keys có trong SortedList.
Ví dụ:
Sub GetKeyListMethod()
'oSList.GetKeyList '
'Return an IList object (System.Collections.IList) containing the keys in the SortedList
object.'
Dim oSList As Object, i As Long, KeyList As Object
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add "Key-" & i, i
Next i
Set KeyList = oSList.GetKeyList
MsgBox KeyList.Item(0) '"Key-1"'
End Sub

3.9. GetValueList
oSList.GetValueList

Trả về một đối tượng IList (System.Collections.IList) chứa toàn bộ Items có trong SortedList.
Ví dụ:
Sub GetValueListMethod()
'oSList.GetValueList '
'Return an IList object (System.Collections.IList) containing the values in the SortedList
object.'
Dim oSList As Object, i As Long, ValueList As Object
Set oSList = CreateObject("System.Collections.SortedList")
For i = 1 To 5
oSList.Add "Key-" & i, i
Next i
Set ValueList = oSList.GetValueList
MsgBox ValueList.Item(4) '5'
End Sub

3.10. IndexOfKey
oSList.IndexOfKey(Key)

Trả về vị trí của Key chỉ định trong SortedList (FirstIndex = 0).
Nếu Key chỉ định không có trong SortedList thì kết quả trả về -1.

Các phần tử trong SortedList được sắp xếp chính xác theo Keys. Khi một phần tử được thêm,
nó được chèn vào SortedList theo thứ tự sắp xếp chính xác, và lập chỉ mục (Index) điều chỉnh
cho phù hợp. Khi một phần tử được loại bỏ, việc lập chỉ mục cũng điều chỉnh cho phù hợp. Do
đó, chỉ mục của cặp Key/ Item cụ thể có thể thay đổi khi các phần tử được thêm vào hoặc xoá
khỏi SortedList.
Ví dụ:
Sub IndexOfKeyMethod()
'oSList.IndexOfKey(Key)
Dim oSList As Object, idex As Long

P a g e 86 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Set oSList = CreateObject("System.Collections.SortedList")


oSList.Add "1", ""
oSList.Add "Z", ""
oSList.Add "A", ""
idex = oSList.IndexOfKey("1") 'idex=0'
MsgBox idex
idex = oSList.IndexOfKey("Z") 'idex=2'
MsgBox idex
idex = oSList.IndexOfKey("A") 'idex=1'
MsgBox idex
End Sub

3.11. IndexOfValue
oSList.IndexOfValue(Item)

Trả về vị trí của Item chỉ định trong SortedList (FirstIndex = 0).
Nếu Item chỉ định không có trong SortedList thì kết quả trả về -1.
Ví dụ:
Sub IndexOfValueMethod()
'oSList.IndexOfValue(Item)'
Dim oSList As Object, idex As Long
Set oSList = CreateObject("System.Collections.SortedList")
oSList.Add "1", 20
oSList.Add "Z", 20
oSList.Add "A", "Item3"
idex = oSList.IndexOfValue(20) 'idex=0'
MsgBox idex
idex = oSList.IndexOfValue("Item3") 'idex=1'
MsgBox idex
idex = oSList.IndexOfValue("Item4")
MsgBox idex 'idex=-1'
End Sub

3.12. Remove
oSList.Remove Key

Xóa một phần tử trong SortedList theo Key chỉ định. Nếu Key chưa tồn tại trong SortedList thì
không xảy ra lỗi.

Khi một phần tử được loại bỏ, việc lập chỉ mục (Index) của các phần tử được điều chỉnh cho
phù hợp. Do đó, chỉ mục của cặp Key/ Item cụ thể có thể thay đổi khi các phần tử được thêm
vào hoặc xoá khỏi SortedList.
Ví dụ:
Sub RemoveMethod()
'oSList.Remove Key'
Dim oSList As Object
Set oSList = CreateObject("System.Collections.SortedList")
oSList.Add "Key-1", ""
oSList.Add "Key-2", ""

P a g e 87 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

oSList.Remove "Key-1"
MsgBox oSList.GetKey(0) ' "Key-2" '
End Sub

3.13. RemoveAt
oSList.RemoveAt Index

Xóa một Item trong SortedList theo chỉ số Index chỉ định.
Index: Có giá trị từ 0 tới Count-1.
Ví dụ:
Sub RemoveAtMethod()
'oSList.RemoveAt Index //Index = 0 : Count-1 '
Dim oSList As Object
Set oSList = CreateObject("System.Collections.SortedList")
oSList.Add "1", ""
oSList.Add "Z", ""
oSList.Add "A", ""
oSList.RemoveAt 1
MsgBox oSList.GetKey(1) ' "Z" '
End Sub

3.14. SetByIndex
oSList.SetByIndex Index, Item

Thay đổi giá trị của Item trong SortedList theo chỉ mục (Index) chỉ định.
Ví dụ:
Sub SetByIndexMethod()
'oSList.SetByIndex Index, Item //Index = 0 : Count-1 '
Dim oSList As Object
Set oSList = CreateObject("System.Collections.SortedList")
oSList.Add 0, 100
oSList.Add 1, 500
oSList.Add 2, 10
oSList.SetByIndex 0, "Item-1"
MsgBox oSList.GetByIndex(0)
End Sub

3.15. ToString
oSList.ToString

Trả về tên đối tượng hiện hành, tức là “System.Collections.SortedList”.


Ví dụ:
Sub ToStringMethod()
'oSList.ToString '
Dim oSList As Object
Set oSList = CreateObject("System.Collections.SortedList")
MsgBox oSList.ToString '"System.Collections.SortedList"'
End Sub

P a g e 88 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

3.16. TrimToSize
oSList.TrimToSize

Thiết lập số phần tử tồn tại thực tế có trong SortedList.


Khi sử dụng phương thức TrimToSize thì Capacity = Count.

Để thiết lập lại SortedList về trạng thái ban đầu, ta sử dụng phương thức Clear trước khi gọi
TrimToSize. Việc cắt một SortedList trống sẽ đặt Capacity của SortedList về giá trị mặc định.
Ví dụ:
Sub TrimToSizeMethod()
'oSList.TrimToSize '
Dim oSList As Object
Set oSList = CreateObject("System.Collections.SortedList")
oSList.Add "Key-1", 1
oSList.Add "Key-2", 2
MsgBox "Count = " & oSList.Count & vbNewLine & _
"Capacity = " & oSList.capacity '2-16'
oSList.TrimToSize
MsgBox "Count = " & oSList.Count & vbNewLine & _
"Capacity = " & oSList.capacity '2-2'
End Sub

4. Ứng dụng
Lọc loại trùng, sort mảng, …
4.1. Một số hàm
Hàm lọc loại trùng 1 cột của Range
'// Loc loai trung mot cot'
Function UniqueColumnSortedList(ByVal Rng As Range) As Variant
If Rng.Count = 1 Then UniqueColumnSortedList = Rng.Value: Exit Function
Dim oSList As Object, i As Long, j As Long, Arr(), Result(), sKey As Variant
Set oSList = CreateObject("System.Collections.SortedList")
Arr = Rng.Value
For i = LBound(Arr, 1) To UBound(Arr, 1)
sKey = Arr(i, 1)
If sKey <> "" Then
If oSList.ContainsKey(sKey) = False Then
oSList.Add sKey, ""
j=j+1
ReDim Preserve Result(1 To j)
Result(j) = sKey
End If
End If
Next i
UniqueColumnSortedList = Result
End Function

Hàm lọc loại trùng và sort mảng 1 chiều

P a g e 89 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

'// Loc loai trung va sort mang 1 chieu'


Function Sort1DSortedList(ByVal Source1D, Optional ByVal IsNumber As Boolean = True, _
Optional ByVal Order As Boolean = True) As Variant
'IsNumber: True - Du lieu kieu so, False - Du lieu kieu chuoi'
'Order: True - Sort A-Z, False - Sort Z-A'
If IsArray(Source1D) = False Then Exit Function
Dim oSList As Object, iTemArr
Set oSList = CreateObject("System.Collections.SortedList")
For Each iTemArr In Source1D
If IsNumber = False Then
iTemArr = CStr(iTemArr)
Else
If IsNumeric(iTemArr) = False Then GoTo NextCode
End If
If oSList.ContainsKey(iTemArr) = False Then
oSList.Add iTemArr, ""
End If
NextCode:
Next iTemArr
Sort1DSortedList = GetKeysSortedList(oSList, Order)
End Function

Hàm lấy toàn bộ Keys trong SortedList vào mảng 1 chiều


'// Lay Keys trong SortedList vao array 1D'
Function GetKeysSortedList(oSList As Object, Optional ByVal Order As Boolean = True)
'Order: True - Sort A-Z, False - Sort Z-A'
Dim Result(), i As Long, index As Long, numKeys As Long
numKeys = oSList.Count
ReDim Result(1 To numKeys)
For i = 1 To numKeys
If Order = True Then index = i - 1 Else index = numKeys - i
Result(i) = oSList.GetKey(index)
Next i
GetKeysSortedList = Result
End Function

Hàm lấy toàn bộ Items trong SortedList vào mảng 1 chiều


'// Lay Items trong SortedList vao array 1D'
Function GetItemsSortedList(oSList As Object, Optional ByVal Order As Boolean = True)
'Order: True - Sort A-Z, False - Sort Z-A'
Dim Result(), i As Long, index As Long, numItems As Long
numItems = oSList.Count
ReDim Result(1 To numItems)
For i = 1 To numItems
If Order = True Then index = i - 1 Else index = numItems - i
Result(i) = oSList.Item(oSList.GetKey(index))
Next i
GetItemsSortedList = Result
End Function

P a g e 90 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Bài 18. ArrayList


>> Download: Arraylist object

ArrayList là một thư viện nằm trong “System.Collections” của .NET Framework. Cho phép lưu
trữ dữ liệu (items) có kích cỡ lớn, kích thước của mảng lưu trữ tự động tăng theo yêu cầu, cho
phép truy xuất tới các items, sắp xếp các items đã nạp vào ArrayLis.
Yêu cầu: Hệ thống phải cài đặt .NET Framework v1.1 trở lên.

1. Khai báo ArrayList

1.1. Kiểu khai báo sớm


(Không có Tooltip khi gọi ArrayList, phải thiết lập trong Tools/References)
- Trong cửa sổ VBA, Tools menu, References.
- Tìm và check vào mục “mscorlib.dll” trong cửa sổ References – VBAProject.
Khai báo trong code:
Dim oArrList As New ArrayList

1.2. Kiểu khai báo muộn


(Không có Tooltip khi gọi ArrayList, không cần thiết lập trong Tools/References).
Khai báo trong code:
Dim oArrList As Object
Set oArrList = CreateObject("System.Collections.ArrayList")

2. Các thuộc tính

2.1. Count
oArrList.Count

Trả về số lượng phần tử (Items) thực sự tồn tại trong ArrayList.


Ví dụ:
Sub CountProperty()
'oArrList.Count'
Dim oArrList As Object, i As Long, arr
Set oArrList = CreateObject("System.Collections.ArrayList")
arr = Array(20, 50)
For i = 1 To 5
oArrList.Add i
Next i
oArrList.Add arr
MsgBox oArrList.Count '6'
End Sub

2.2. Capacity
oArrList.Capacity

Trả về số lượng các phần tử hoặc đặt (thiết lập) số lượng các phần tử mà ArrayList có thể lưu
trữ.
+ Các lỗi xảy ra đặt số lượng các phần tử cho ArrayList:

P a g e 91 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

- Khi giá trị của Capacity nhỏ hơn số lượng phần từ đã tồn tại trong ArrayList (count).
- Khi giá trị của Capacity trả về ArrayList có kích thước vượt dung lượng bộ nhớ có thể dùng
của hệ thống (OutOfMemoryException).
+ Capacity luôn luôn lớn hơn hoặc bằng Count. Nếu Count vượt quá Capacity trong khi thêm
các phần tử, Capacity sẽ tự động tăng lên bằng cách tái phân bổ lại mảng nội bộ trước khi sao
chép các phần tử cũ và thêm các phần tử mới.
+ Có thể giảm Capacity bằng cách dùng phương thức TrimToSize hoặc bằng cách thiết lập giá
trị Capacity cụ thể (nhưng phải đảm bảo >= Count, nếu không sẽ xảy ra lỗi). Khi giá trị của
Capacity được xác định cụ thể, mảng nội bộ cũng được phân bổ lại để đáp ứng dung lượng đã
xác định.
Ví dụ:
Sub CapacityProperty()
'oArrList.Capacity'
Dim oArrList As Object, vCnt As Long, vCty As Long
Set oArrList = CreateObject("System.Collections.ArrayList")
For i = 1 To 5
oArrList.Add i
Next i
vCnt = oArrList.Count '5'
vCty = oArrList.Capacity '8'
oArrList.Capacity = 5
MsgBox oArrList.Capacity '5'
End Sub

2.3. Item
oArrList.Item(Index)

Trả về giá trị của Item theo chỉ số (index) chỉ định trong ArrayList, hoặc gán giá trị mới cho
Item theo chỉ số của Item đó.
Lưu ý: Chỉ số (index) của Item có giá trị từ 0 tới Count-1.
Ví dụ:
Sub ItemProperty()
'oArrList.Item(Index) -FirstIndex = 0'
Dim oArrList As Object
Set oArrList = CreateObject("System.Collections.ArrayList")
For i = 1 To 5
oArrList.Add "Value-" & i
Next i
oArrList.Item(4) = 100
MsgBox oArrList.Item(0) 'Value-1'
MsgBox oArrList.Item(4) '100'
End Sub

3. Các phương thức

3.1. Add
oArrayList.Add Item

Thêm một Item vào vị trí cuối cùng (end) của ArrayList.

P a g e 92 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Item có thể là một trị đơn, hoặc một mảng (array).


Item nhận kiểu dữ liệu bất kỳ (kiểu số hoặc chuỗi), giá trị của Items có thể trùng nhau.
Chỉ số đầu tiên của Item trong ArrayList bằng 0, cho dù Option Base 1.
Ví dụ:
Sub AddMethod()
'oArrList.Add Item -Adds a item to the end of the ArrayList'
'Item: number, string, array'
'First index = 0'
Dim oArrList As Object
Set oArrList = CreateObject("System.Collections.ArrayList")
Dim Arr1, Arr2(1 To 2, 1 To 1), itemArr, itemList
Arr1 = Array(10, 12)
Arr2(1, 1) = 50
Arr2(2, 1) = "Example"
'Adds items to oArrList:'
oArrList.Add 20
oArrList.Add "TextA"
oArrList.Add Arr1
oArrList.Add Arr2

For Each itemList In oArrList


If IsArray(itemList) = True Then
For Each itemArr In itemList
MsgBox itemArr
Next itemArr
Else
MsgBox itemList
End If
Next itemList
'Result: 20, "TextA", 10, 12, 50 , "Example" '
End Sub

3.2. AddRange
oArrList.AddRange ICollection

Thêm một đối tượng ICollection vào vị trí cuối cùng của ArrayList.
Icollection: Có thể là Stack, Queue, Hashtable, SortList, ArrayList
Ví dụ:
Sub AddRangeMethod()
'Adds the elements of an ICollection to the end of the ArrayList.'
'oArrList.AddRange ICollection'
Dim oArrList As Object, ArList1 As Object, itemList
Set oArrList = CreateObject("System.Collections.ArrayList")
Set ArList1 = CreateObject("System.Collections.ArrayList")
ArList1.Add 10
ArList1.Add 20
oArrList.Addrange ArList1
For Each itemList In oArrList
MsgBox itemList

P a g e 93 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Next
'Result: 10, 20'
End Sub

3.3. Clear
oArrayList.Clear

Xóa toàn bộ các Items trong ArrayList.


Ví dụ:
Sub ClearMethod()
'oArrList.Clear'
Dim oArrList As Object, i As Long
Set oArrList = CreateObject("System.Collections.ArrayList")
For i = 1 To 5
oArrList.Add i
Next i
oArrList.Clear
MsgBox oArrList.Count '0'
End Sub

3.4. Clone
oArrayList.Clone

Tạo một bản sao từ ArrayList đã có.


Ví dụ:
Sub CloneMethod()
'oArrList.Clone'
Dim oArrList As Object, i As Long, newArrList As Object
Set oArrList = CreateObject("System.Collections.ArrayList")
For i = 1 To 5
oArrList.Add i
Next i
Set newArrList = oArrList.Clone
MsgBox newArrList.Count '5'
End Sub

3.5. Contains
oArrList.Contains(Item)

Kiểm tra sự tồn tại của một Item trong ArrayList. Trả về True nếu Item đã tồn tại trong
ArrayList, ngược lại trả về False.
Ví dụ:
Sub ContainsMethod()
'oArrList.Contains(Item)'
Dim oArrList As Object, i As Long, valItem
Set oArrList = CreateObject("System.Collections.ArrayList")
For i = 1 To 5
oArrList.Add "Value-" & i
Next i

P a g e 94 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

valItem = oArrList(0)
MsgBox oArrList.Contains(valItem) 'True'
End Sub

3.6. IndexOf
oArrList.IndexOf(Item, index)

Trả về vị trí đầu tiên tìm thấy Item chỉ định, dò tìm từ vị trí Index chỉ định so với vị trí đầu tiên
trong ArrayList (FirstIndex = 0).
Ví dụ:
Sub IndexOf()
'oArrList.IndexOf(Item, index)'
Dim oArrList As Object, i As Long
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Add "Value-1"
oArrList.Add "Value-2"
oArrList.Add "Value-3"
oArrList.Add "Value-1"
oArrList.Add "Value-2"
oArrList.Add "Value-1"
i = oArrList.IndexOf("Value-1", 0) 'i=0'
i = oArrList.IndexOf("Value-1", 1) 'i=3'
i = oArrList.IndexOf("Value-1", 4) 'i=5'
End Sub

3.7. Insert
oArrList.Insert Index, Item

Chèn thêm một Item vào ArrayList theo vị trí (Index) chỉ định.
Index: Nhận giá trị từ 0 tới oArrList.Count. Gặp lỗi khi Index < 0 hoặc Index > Count.
Ví dụ:
Sub InsertMethod()
'oArrList.Insert Index, Item'
Dim oArrList As Object, i As Long
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Insert 0, 100
oArrList.Insert 1, 200
For i = 1 To 5
oArrList.Add i
Next i
oArrList.Insert 4, 30
oArrList.Insert oArrList.Count, 50
MsgBox oArrList.Item(oArrList.Count - 1) '50'
End Sub

3.8. InsertRange
oArrList.InsertRange Index, ICollection

Chèn thêm một đối tượng ICollection vào ArrayList theo vị trí (Index) chỉ định.

P a g e 95 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Index: Nhận giá trị từ 0 tới Count.


Ví dụ:
Sub InsertRangeMethod()
'Inserts the elements of an ICollection into the ArrayList at the specified index.'
'oArrList.InsertRange Index, ICollection'
Dim oArrList As Object, ArList1 As Object, itemList
Set oArrList = CreateObject("System.Collections.ArrayList")
Set ArList1 = CreateObject("System.Collections.ArrayList")
ArList1.Add 10
ArList1.Add 20
oArrList.Add "Item1"
oArrList.InsertRange 1, ArList1
For Each itemList In oArrList
MsgBox itemList
Next
'Result: "Item1", 10, 20'
End Sub

3.9. LastIndexOf
oArrList.LastIndexOf(Item)

Trả về vị trí (Index) cuối cùng của Item tìm thấy trong ArrayList.
Ví dụ:
Sub LastIndexOfMethod()
'oArrList.LastIndexOf(Item)'
Dim oArrList As Object, i As Long
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Add "Value-1"
oArrList.Add "Value-2"
oArrList.Add "Value-3"
oArrList.Add "Value-1"
oArrList.Add "Value-2"
oArrList.Add "Value-1"
i = oArrList.LastIndexOf("Value-1") 'i=5'
End Sub

3.10. Remove
oArrList.Remove Item

Xóa một Item chỉ định trong ArrayList. Nếu Item chưa tồn tại trong ArrayList thì không xảy ra
lỗi.
Nếu Item có nhiều giá trị như nhau thì sẽ xóa Item xuất hiện đầu tiên.
Ví dụ:
Sub RemoveMethod()
'oArrList.Remove Item'
Dim oArrList As Object
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Add "Value-1"
oArrList.Add "Value-2"

P a g e 96 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

oArrList.Add "Value-3"
oArrList.Add "Value-1"
oArrList.Add "Value-2"
oArrList.Add "Value-3"
oArrList.Remove "Value-1"
MsgBox oArrList.Item(0) ' "Value-2" '
End Sub

3.11. RemoveAt
oArrList.RemoveAt Index

Xóa một Item trong ArrayList theo chỉ số Index chỉ định.
Index: Có giá trị từ 0 tới Count-1.
Ví dụ:
Sub RemoveAtMethod()
'oArrList.RemoveAt Index'
Dim oArrList As Object
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Add "Value-1"
oArrList.Add "Value-2"
oArrList.Add "Value-3"
oArrList.Add "Value-4"
oArrList.RemoveAt 2
MsgBox oArrList.Item(2) ' "Value-4" '
End Sub

3.12. RemoveRange
oArrList.RemoveRange IndexFrom, NumberOfItems

Xóa các Items có trong ArrayList từ vị trí chỉ định, số lượng Items cần xóa được chỉ định.
IndexFrom: Vị trí Item đầu tiên cần xóa. Index có giá trị từ 0 tới Count-1.
NumberOfItems: Số Item cần xóa. NumberOfItems có giá trị từ 0 tới (Count - Index).
Ví dụ:
Sub RemoveRangeMethod()
'oArrList.RemoveRange IndexFrom, NumberOfItems '
Dim oArrList As Object
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Add "Value-1"
oArrList.Add "Value-2"
oArrList.Add "Value-3"
oArrList.Add "Value-4"
oArrList.RemoveRange 0, 2
MsgBox oArrList.Item(0) ' "Value-3" '
End Sub

3.13. Reverse
oArrList.Reverse

P a g e 97 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Đảo ngược vị trí toàn bộ các Items có trong ArrayList.


Ví dụ:
Sub ReverseMethod()
'oArrList.Reverse '
Dim oArrList As Object, i As Long
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Add "Value-1"
oArrList.Add "Value-2"
oArrList.Add "Value-3"
oArrList.Add "Value-4"
oArrList.Reverse
For i = 0 To oArrList.Count - 1
MsgBox oArrList.Item(i) ' "Value-4","Value-3","Value-2","Value-1" '
Next i
End Sub

3.14. Sort
oArrList.Sort

Sắp xếp các Items trong ArrayList theo thứ tự A-Z.


Ví dụ:
Sub SortMethod()
'oArrList.Sort '
Dim oArrList As Object, i As Long
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Add "Value-1"
oArrList.Add "Value-3"
oArrList.Add "Value-2"
oArrList.Add "Value-4"
oArrList.Add "Value-0"
oArrList.Sort
For i = 0 To oArrList.Count - 1
MsgBox oArrList.Item(i) '"Value-0", "Value-1","Value-2","Value-3","Value-4"'
Next i
End Sub

3.15. ToArray
oArrList.ToArray

Sao chép các Item trong ArrayList vào một mảng (Array). Mảng trả về là mảng một chiều, chỉ
số cận dưới của mảng luôn băng 0, cho dù thiết lập Option Base 1.
Ví dụ:
Sub ToArrayMethod()
'oArrList.ToArray '
Dim oArrList As Object, Arr()
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Add "Value-1"
oArrList.Add Array(15, 40)

P a g e 98 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

oArrList.Add 200
Arr = oArrList.ToArray
End Sub

3.16. ToString
oArrList.ToString

Trả về tên đối tượng hiện hành, tức là “System.Collections.ArrayList”.


Ví dụ:
Sub ToStringMethod()
'oArrList.ToString '
Dim oArrList As Object
Set oArrList = CreateObject("System.Collections.ArrayList")
MsgBox oArrList.ToString '"System.Collections.ArrayList"'
End Sub

3.17. TrimToSize
oArrList.TrimToSize

Sử dụng để giảm vùng nhớ của Collection nếu không có Item mới sẽ được thêm vào.
Khi sử dụng phương thức TrimToSize thì Capacity = Count.

Để thiết lập lại ArrayList về trạng thái ban đầu, ta sử dụng phương thức Clear trước khi gọi
TrimToSize. Việc cắt một ArrayList trống sẽ đặt Capacity của ArrayList về giá trị mặc định.
Ví dụ:
Sub TrimToSizeMethod()
'oArrList.TrimToSize '
Dim oArrList As Object
Set oArrList = CreateObject("System.Collections.ArrayList")
oArrList.Add "Value-1"
oArrList.Add "Value-2"
MsgBox "Count = " & oArrList.Count & vbNewLine & _
"Capacity = " & oArrList.Capacity '2-4'
oArrList.TrimToSize
MsgBox "Count = " & oArrList.Count & vbNewLine & _
"Capacity = " & oArrList.Capacity '2-2'
End Sub

4. Ứng dụng
Lọc loại trùng, sort mảng, tạo số ngẫu nhiên không trùng...

4.1. Một số hàm

Hàm lọc loại trùng 1 cột của Range


'// Loc loai trung mot cot'
Function UniqueColumnArrayList(ByVal Rng As Range) As Variant
If Rng.Count = 1 Then UniqueColumnArrayList = Rng.Value: Exit Function
Dim oArrList As Object, i As Long, j As Long, Arr(), Result(), sKey As Variant
Set oArrList = CreateObject("System.Collections.ArrayList")

P a g e 99 | 100
https://sites.google.com/site/exl2lab/vba-in-excel

Arr = Rng.Value
For i = LBound(Arr, 1) To UBound(Arr, 1)
sKey = Arr(i, 1)
If sKey <> "" Then
If oArrList.Contains(sKey) = False Then
oArrList.Add sKey
j=j+1
ReDim Preserve Result(1 To j)
Result(j) = sKey
End If
End If
Next i
UniqueColumnArrayList = Result
End Function

Hàm Sort mảng 1 chiều


'// Sort mang 1 chieu'
Function Sort1DArrayList(ByVal Source1D, Optional ByVal IsNumber As Boolean = True, _
Optional ByVal Order As Boolean = True) As Variant
'IsNumber: True - Du lieu kieu so, False - Du lieu kieu chuoi'
'Order: True - Sort A-Z, False - Sort Z-A'
If IsArray(Source1D) = False Then Exit Function
Dim oArrList As Object, itemArr
Set oArrList = CreateObject("System.Collections.ArrayList")
For Each itemArr In Source1D
If IsNumber = False Then itemArr = CStr(itemArr)
oArrList.Add itemArr
Next itemArr
oArrList.Sort
If Order = False Then oArrList.Reverse
Sort1DArrayList = oArrList.ToArray
End Function

P a g e 100 | 100

You might also like