Tặng các bạn phần nhỏ này nhé... Mình muốn VBulletin có thể đinh dạng đẹp như Word nhưng nỏ được...
đành phải dùng biện pháp này vậy.
Lập trình với đối tượng VBA
Mục lục
Mục lục 1
Để bắt đầu, các bạn cần phải tham chiếu đến bộ thư viện mở rộng của VBA 2
Các đối tượng VBE 2
Khai báo tham chiếu đối tượng 3
Thêm một Module vào một bảng tính 4
Xoá module khỏi bảng tính 4
Thêm thủ tục vào một Module 4
Creating An Event Procedure 5
Xoá một thủ tục trong một Module 5
Xoá toàn bộ mã chương trình trong một Module 6
Liệt kê tất cả các Module trong một bảng tính (WorkBook) hoặc tài liệu (Document) 6
Liệt kê tất cả các thủ tục trong một Module 7
Truy xuất tất cả các Modules trong dự án VBA 7
Xoá toàn bộ mã VBA trong một dự án VBA 8
Sao chép Module giữa các dự án VBA 8
Kiểm tra sự tồn tại của một thủ tục hoặc Module 9
Bộ soạn thảo VBE là một công cụ dùng để tạo lập, sửa đổi và khai thác các thủ tục và mô đun trong các ứng dụng Office. Thông qua môi trường soạn thảo, chúng ta có thể tạo ra các ứng dụng VBA bao gồm nhiều đối tượng ví dụ Form, báo cáo, module, bảng tính, tài liệu ... trong tất cả các ứng dụng sẵn có hiện nay của bộ Office như Access, Word, Excel. giống như chúng ta vẫn thao tác thông qua giao diện sử dụng của các ứng dụng đó. Không những thế VBA còn cho phép chúng ta sửa đổi các đối tượng và các module mã giống như chúng ta dùng giao diện của bộ soạn thảo VBE IDE. Tuy nhiên những khả năng này chỉ có từ các phiên bản Office 97 trở lên.
Có khá nhiều câu hỏi liên quan đến vấn đề làm thế nào để có thể phát sinh ra các mã chương trình từ chính các ứng dụng giống như ta dùng công cụ ghi Macro. Để đáp ứng vấn đề này, tôi xin phép được trích dẫn một số tài liệu và đưa ra một cách đơn giản để những ai có mong muốn có thể thực hiện được.
Trong phạm vi bài viết này, chúng ta cùng bàn về một số đối tượng, cách thức và các thuộc tính mà qua đó VBE cho phép chúng ta quản lý môi trường VBA. Microsoft quả là rất cẩn thận khi họ chú trọng đưa những hỗ trợ về vấn đề này vào ngay trong bộ trợ giúp. Với tất cả các phiên bản Office từ 2000 trở lên, các bạn có thể tìm được những hỗ trợ cần thiết chỉ bằng phím F1. Đối với phiên bản 97, để có được những trợ giúp này, chúng ta cần phải tìm trong bộ hỗ trợ nằm trong một đĩa CD khác không thuộc bộ cài đặt Office.
Để bắt đầu, các bạn cần phải tham chiếu đến bộ thư viện mở rộng của VBA
Trong màn hình soạn thảo VBA, chọn Tools, chọn mục Reference và chọn thư viện "Microsoft Visual Basic For Applications Extensibility" qua hộp kiểm bên cạnh. Công việc này sẽ cho phép VBA tìm ra những định nghĩa cần thiết của các đối tượng thuộc VBA như Module, Component...
Nếu các bạn đang dùng các phiên bản Office 2000 hay 2002, tên bộ thư viện sẽ kèm theo số phiên bản. Ví dụ "Microsoft Visual Basic For Applications Extensibility 5.3". Điều này rất quan trọng bởi nếu bạn chỉ ra không đúng bộ thư viện, các bước sau của bạn sẽ gặp rất nhiều lỗi, một trong những lỗi cơ bản là "Type Mismatch" (Không hợp kiểu). Nếu bạn không trỏ tham chiếu, bạn sẽ nhận được thông bào "User Defined Type Not Defined"( Kiểu người dùng định nghĩa chưa được định nghĩa).
Do những cải thiện về an ninh trong các phiên bản Office, để có thể bắt đầu khai thác tính năng này, hãy điều chỉnh cấp an ninh trong thực đơn Tools>Macros>Security thuộc Tab Trust "Trusted Sources" về mức "Trust access to Visual Basic Project".
Lưu ý: Trong tất cả các phiên bản Office đặc biệt là trong Excel, không được khoá các dự án VBProject. Nếu bạn khoá các dự án này thì các công đoạn sẽ bàn đến sau đây đều không thể thực hiện được và bạn sẽ nhận được báo lỗi.
Ngoài ra, bạn cũng sẽ nhận được những thông báo lỗi hoặc những kết quả không mong đợi nếu cố gắng sửa chữa mã chương trình trong chính Module chúng ta đang làm việc. Ví dụ ta đang thực thi chương trình trong Module 1 thì tránh không chỉ thị cho chươn trình thực hiện thay đổi với Module 1 này.
Thêm một vấn đề khác: Nhiều loại mã độc hại hoặc virus cũng lây lan trên cơ chế mà chúng ta sắp bàn này. Vì vậy hầu hết các chương trình quét Virus đều dựa vào đặc điểm này để xoá đi các đoạn mã dùng để sản sinh mã VBA, một số khác thì có thể xoá tất cả. Vì vậy cần phải tắt các chức năng cảnh báo hoặc quét virus của chương trình quét virus trước khi bước vào thực hiện các bước sẽ miêu tả dưới đây.
Các đối tượng VBE
Về cơ bản, chúng ta chỉ cần đến 3 đối tượng dưới đây trong các module của mình:
VBProject: Đây là toàn bộ các module VBA và tham chiếu liên quan đến một bảng tính hoặc một cơ sở dữ liệu hoặc một tài liệu Word cũng như một Slide trong Powerpoint ....
VBComponent: Đây là các thành phần thuộc một dự án VBProject. Ví dụ đó có thể là một Form, một module mã chương trình. Và bộ các thành phần VBComponents sẽ là nơi chứa các thành phần đơn lẻ VBComponent trong dự án của chúng ta.
CodeModule: Đây là đối tượng chỉ ra các đoạn mã thực tế nằm trong một thành phần. Ví dụ khi bạn vào viết mã vào Module 1, điều đó có nghĩa là bạn đang viết mã vào đối tượng CodeModule của thành phần VBComponent có tên là "Module1".
Sau đây chúng ta sẽ đi qua các đối tượng này xét trên ví dụ về đối tượng bảng tính của Excel. Tất nhiên, bạn cũng có thể tiếp cận các đối tượng này thông qua việc gọi trực tiếp VBE từ cấp ứng dụng dưới dạng Application.VBE.
VBA xây dựng bộ định dạng kiểu cho các thành phần này, chúng ta có thể thấy rõ trong phần mô tả dưới đây.
Kiểu Miêu tả
vbext_ct_ClassModule Đây là module lớp được dùng để tạo các đối tượng cho riêng bạn.
vbext_ct_Document
Đây là thành phần giúp chúng ta tạo các bảng tính, tài liệu, biểu đồ...
vbext_ct_MSForm Đây là thành phần giúp ta tạo các đối tượng form
vbext_ct_StdModule
Kiểu định dạng này giúp chúng ta tạo các module mã và các thủ tục cho nó.
Khai báo tham chiếu đối tượng
Chắc hẳn chúng ta cũng đã quen thuộc với các từ khoá khai báo Dim, Public, Private trong môi trường lập trình. Để có thể sử dụng các thành phần và đối tượng, chúng ta cần khai báo để khởi tạo tham chiếu đến chúng trước. Dưới đây là một số cách khai báo và tham chiếu đối tượng
Để có một cách hiểu khái quát, VBA tham chiếu đến các thành phần của chúng thông qua các từ khoá đặc tả, ví dụ với Word đó là ThisDocument, Excel là ThisWorkbook.... Để tham chiếu trực tiếp đến các đối tượng thuộc nó, ta chỉ cần đưa ra từ khoá trên và gõ thêm VBProject
VBProject
Khai báo tham chiếu như thế này
Dim VBProj As VBProject
Dim VBComp As VBComponent
Dim VBCodeMod As CodeModule
Khởi tạo biến đối tượng thế này (Vì đây là biến đối tượng nên muốn gán giá trị ta phải dùng từ khoá Set). Nếu muốn gán trực tiếp cho một đối tượng hiện hữu ta có thể viết lệnh như trong phần được đánh dấu [*]
Set VBProj = ThisWorkbook.VBProject
Set VBComp = ThisWorkbook.VBProject.VBComponents("Module1")*
Set VBCodeMod = ThisWorkbook.VBProject.VBComponents("Module1").CodeModule
Để các bạn tiện theo dõi, chúng ta xét đến ví dụ với đối tượng làm việc là ThisWorkbook, tất nhiên bạn cũng có thể làm việc với ThisDocument hoặc bất kỳ một đối tượng nào khác bằng các mở đối tượng đó ra hoặc tham chiếu trực tiếp đến Active[Workbook hoặc Document] hoặc cũng có thể tham chiếu bằng từ khoá WorkBooks([“Tên WorkBook”] hoặc [Tên tài liệu Word, PowerPoint]).
Thêm một Module vào một bảng tính
Thủ tục dưới đây sẽ giúp bạn thêm một module mới vào ThisWorkBook. Thủ tục đó có tên là "TestModule".
Sub AddModule()
Dim VBComp As VBComponent
Set VBComp = ThisWorkbook.VBProject.VBComponents.Add(vbext_ct_StdModule)
VBComp.Name = "TestModule"
Application.Visible = True
End Sub
Tất nhiên khi bạn thực thi đoạn code này trong Excel lúc màn hình soạn thảo VBE đang mở, bạn sẽ được chuyển tới màn hình chứa Module mới này và mã thực thi kết thúc. Khi bạn thực thi gián tiếp không mở màn hình VBE, Excel sẽ vẫn kích hoạt song không nhận được trỏ kích hoạt (Focus Pointer), sau khi thực hiện xong, Excel sẽ lại có trỏ kích hoạt.
Xoá module khỏi bảng tính
Tương tự chúng ta cũng có thể tiến hành xoá module khỏi bảng tính
Sub DeleteModule()
Dim VBComp As VBComponent
Set VBComp = ThisWorkbook.VBProject.VBComponents("TestModule")
ThisWorkbook.VBProject.VBComponents.Remove VBComp
End Sub
Bạn không thể xoá được Module mã chương trình của đối tượng ThisWorkBook hoặc ThisDocument hoặc các đoạn code module của đối tượng như WorkSheet, Chart ....
Thêm thủ tục vào một Module
Đoạn mã sau sẽ thêm một thủ tục TestProc vào Module TestModule sau khi nó được tạo ra.
Sub AddProcedure()
Dim VBCodeMod As CodeModule
Dim LineNum As Long
Set VBCodeMod = ThisWorkbook.VBProject.VBComponents("TestModule").CodeModule
With VBCodeMod
LineNum = .CountOfLines + 1
.InsertLines LineNum, _
"Sub TestProc()" & Chr(13) & _
" Msgbox ""Hi, this is my first test!"" " & Chr(13) & _
"End Sub"
End With
Application.Run "TestProc"
End Sub
Cần chú ý đến cách gọi thủ tục .InsertLines. Toàn bộ thủ tục được gửi vào 1 dòng lệnh, hàm Chr(13) hoặc hằng vbCrlf sẽ là dấu ngắt xuống dòng cho thủ tục. Bạn cũng có thể kèm thêm các hằng ví dụ như vbTab chẳng hạn để định dạng thủ tục cho đẹp
Câu lệnh Application.Run "TestProc" sẽ thực thi thủ tục sau khi bạn khởi tạo xong.
Bạn phải dùng cấu trúc Application.Run để thực thi thay vì gọi tên thủ tục, vì điều này sẽ gây phát sinh lỗi khi gọi đến một thủ tục chưa tồn tại. Thủ tục này sẽ thực thi thành công nếu bạn thêm mã chương trình vào một module khác không nằm trong module hiện thời.
Nếu bạn thêm code vào cùng module thì phải dùng thủ tục Application.OnTime, điều này giúp trả về trỏ kích hoạt cho Excel và Excel sẽ dịch lại đoạn mã và thực thi.
Tuy nhiên, cũng cần chú ý là việc sử dụng Application.OnTime có thể dẫn đến một số trục trặc liên quan đến việc dịch và thực thi. Bạn cần tránh gọi thủ tục mà bạn vừa thêm vào cùng Module khi các thủ tục VBA chưa hoàn toàn kết thúc.
Trong trường hợp này, hãy dùng Application.OnTime Now,"TestProc"
Creating An Event Procedure
Đối tượng CodeModule có một thủ tục gọi là CreateEventProc, thủ tục này cho phép bạn tạo ra một thủ tục sự kiện trong một module lớp, module của Sheet hoặc của ThisWorkbook hay ThisDocument. Điểm hay của thủ tục này là cho phép tự động thêm các khai báo hoàn chỉnh của một thủ tục bao gồm cả tham số ta muốn bổ sung, trong khi đó InsertLines không thể làm được điều đó. Thủ tục này sẽ trả về số thứ tự dòng bắt đầu thủ tục. Do đó sau khi tạo thủ tục bạn có thể dùng InsertLines để thêm thân thủ tục. Dưới đây là một ví dụ trong đó Excel sẽ tạo ra thủ tục sự kiện Workbook_Open trong đó phần thân là mệnh đề Msgbox.
Sub AddEventProc()
Dim StartLine As Long
With ActiveWorkbook.VBProject.VBComponents("ThisWorkbook").CodeModule
StartLine = .CreateEventProc("Open", "Workbook") + 1
.InsertLines StartLine, _
"Msgbox ""Hey guys! You made it!!!"",vbOkOnly"
End With
End Sub
Xoá một thủ tục trong một Module
The procedure below will delete the procedure called "MyTestProc" from the module named "TestModule" in ThisWorkbook.
Sub DelProcedure()
Dim VBCodeMod As CodeModule
Dim StartLine As Long
Dim HowManyLines As Long
Set VBCodeMod = ThisWorkbook.VBProject.VBComponents("TestModule").CodeModule
With VBCodeMod
StartLine = .ProcStartLine("MyTestProc", vbext_pk_Proc)
HowManyLines = .ProcCountLines("MyTestProc", vbext_pk_Proc)
.DeleteLines StartLine, HowManyLines
End With
End Sub
Xoá toàn bộ mã chương trình trong một Module
Thủ tục dưới đây sẽ xoá toàn bộ mã chương trình trong module tên là "TestModule".
Sub DelAllCodeInModule()
Dim VBCodeMod As CodeModule
Dim StartLine As Long
Dim HowManyLines As Long
Set VBCodeMod = ThisWorkbook.VBProject.VBComponents("TestModule").CodeModule
With VBCodeMod
StartLine = 1
HowManyLines = .CountOfLines
.DeleteLines StartLine, HowManyLines
End With
End Sub
Liệt kê tất cả các Module trong một bảng tính (WorkBook) hoặc tài liệu (Document)
Thủ tục sau đây sẽ liệt kê toàn bộ các thủ tục trong Module ThisWorkbook. Có một hàm con được dùng để đưa về kiểu của thủ tục.
Sub ListModules()
Dim VBComp As VBComponent
Dim Msg As String
For Each VBComp In ThisWorkbook.VBProject.VBComponents
Msg = Msg & VBComp.Name & " Type: " & ObjType(VBComp) & vbCrlf
Next VBComp
MsgBox Msg
End Sub
Function ObjType(VBComp As VBComponent) As String
Select Case VBComp.Type
Case vbext_ct_ActiveXDesigner
ObjType = "ActiveX Designer"
Case vbext_ct_ClassModule
ObjType = "Class Module"
Case vbext_ct_Document
ObjType = "Document"
Case vbext_ct_MSForm
ObjType = "MS Form"
Case vbext_ct_StdModule
ObjType = "Standard Module"
Case Else
End Select
End Function
Liệt kê tất cả các thủ tục trong một Module
Sau đây là một ví dụ trong đó tất cả các thủ tục trong Module "MyModule" thuộc ThisWorkbook sẽ được liệt kê ra.
Sub ListProcs()
Dim VBCodeMod As CodeModule
Dim StartLine As Long
Dim Msg As String
Dim ProcName As String
Set VBCodeMod = ThisWorkbook.VBProject.VBComponents("MyModule").CodeModule
With VBCodeMod
StartLine = .CountOfDeclarationLines + 1
Do Until StartLine >= .CountOfLines
Msg = Msg & .ProcOfLine(StartLine, vbext_pk_Proc) & vbCrlf
StartLine = StartLine + .ProcCountLines(.ProcOfLine(StartLine, _
vbext_pk_Proc), vbext_pk_Proc)
Loop
End With
MsgBox Msg
End Sub
Truy xuất tất cả các Modules trong dự án VBA
Ví dụ dưới đây sẽ truy xuất tất cả cá module trong một dự án và lưu thành các tập tin dạng VB. Trong chừng mực nào đó, bạn có thể sử dụng cá mã naỳ để lưu lại công việc của mìnhđể khi cần thiết có thể sử dụng lại.
Sub ExportModules()
Dim VBComp As VBIDE.VBComponent
Dim ObjType As String
For Each VBComp In ActiveWorkbook.VBProject.VBComponents
Select Case VBComp.Type
Case vbext_ct_ClassModule, vbext_ct_Document
ObjType = ".cls"
Case vbext_ct_MSForm
ObjType = ".frm"
Case vbext_ct_StdModule
ObjType = ".bas"
Case Else
ObjType = ""
End Select
If ObjType <> "" Then
VBComp.Export Filename:=ActiveWorkbook.Path & "\" & _
VBComp.Name & ObjType
End If
Next VBComp
End Sub
Xoá toàn bộ mã VBA trong một dự án VBA
Sub DeleteAllVBA()
Dim VBComp As VBIDE.VBComponent
Dim VBComps As VBIDE.VBComponents
Set VBComps = ActiveWorkbook.VBProject.VBComponents
For Each VBComp In VBComps
Select Case VBComp.Type
Case vbext_ct_StdModule, vbext_ct_MSForm, vbext_ct_ClassModule
VBComps.Remove VBComp
Case Else
With VBComp.CodeModule
.DeleteLines 1, .CountOfLines
End With
End Select
Next VBComp
End Sub
Sao chép Module giữa các dự án VBA
Hiện tại không có chức năng này trong trình soạn thảo VBE nhưng chúng ta có thể tự làm điều đó bằng đoạn ví dụ này.
Cách làm là: truy xuất Module của một dự án và sau đó đưa vào một dự án khác. Thủ tục ví dụ này sẽ chép Module1 từ bảng tính Book2 sang Book1.
Sub CopyModule()
Dim FName As String
With Workbooks("Book2")
FName = .Path & "\bkMdl.txt"
.VBProject.VBComponents("Module1").Export Fname
End With
Workbooks("book1").VBProject.VBComponents.Import Fname
Kill FName
End Sub
Bạn có thể cải biến ví dụ này và sao chép toàn bộ các module của một bảng tính sang bảng tính khác. Tất nhiên là ngoại trừ mã chương trính của đối tượng Sheet và ThisWorkbook thông qua vòng lặp như sau:
For Each VBComp In Workbooks("Book2").VBProject.VBComponents
If VBComp.Type <> vbext_ct_Document Then
VBComp.Export Fname
Workbooks("book1").VBProject.VBComponents.Import Fname
Kill Fname
End If
Next VBComp
Kiểm tra sự tồn tại của một thủ tục hoặc Module
Bạn có thể sử dụng công cụ VBA mở rộng để làm điều này thông qua thủ tục như sau.
Function MdlExists(MdlName As String) As Boolean
On Error Resume Next
MdlExists = Len(ThisWorkbook.VBProject.VBComponents(MdlName).Name) <> 0
End Function
Function ProcExists(ProcName As String, MdlName As String) As Boolean
On Error Resume Next
If MdlExists(MdlName) = True Then
ProcExists = ThisWorkbook.VBProject.VBComponents(MdlName) _
.CodeModule.ProcStartLine(ProcName, vbext_pk_Proc) <> 0
End If
End Function