Tạo và dùng Class Module

Liên hệ QC

levanduyet

Hãy để gió cuốn đi.
Thành viên danh dự
Tham gia
30/5/06
Bài viết
1,798
Được thích
4,704
Giới tính
Nam
Hiện tại với các nguồn trên internet các bạn dễ dàng tìm thấy các class module. Với các class module này các bạn sẽ dễ dàng trong việc tái sử dụng các đọan mã lập trình. Chính vì lý do này tôi mạn phép tổng hợp các tài liệu về class module. Hy vọng bài viết này sẽ giúp ích phần nào cho công việc lập trình của các bạn.

Sử dụng class module để tạo các đối tượng (Objects)
Class module được dùng để tạo một đối tượng. Đối với người phát triển một ứng dụng thì có nhiều lý do để thực hiện việc này, bao gồm các lý do sau:
_ Gói gọn VBA và Windows API để việc sử dụng được dễ dàng và có thể sử dụng lại. Các bạn có thể thấy ví dụ ở đây, Lập trình Windows API trong VB/VBA
_ Để bẫy các sự kiện. (To trap events)
_ Tạo các sự kiện. (To raise events).
_ Tạo các đối tượng của riêng bạn.

Các bạn có thể tham khảo các class module tại đây:
_Sưu tầm các class module.
_Class đọc công thức toán.

Giải thích thêm về class module tại đây:
_ Hỏi về module và class module.
_ Cũng hỏi về class module.
_ Tự tạo Object.
_ Hướng dẫn từng bước tạo thư viện.

Mục đích của bài viết này nhằm hướng dẫn bạn tạo đối tượng của riêng bạn.

Tạo đối tượng
Giả sử rằng chúng ta muốn phát triển một đọan mã nhằm phân tích một cell trong worksheet như sau:
Xem cell có :
_ Rổng hay không?
_Có chứa một nhãn hay không?
_Có chứa một giá trị số hay không?
_Có chứa công thức hay không?

Chúng ta có thể làm điều này bằng việc tạo một đối tượng mới với các phương thức và thuộc tính. Đối tượng mới của chúng ta sẽ là đối tượng Cell. Nó sẽ có phương thức Analyze nhằm định nghĩa kiểu của cell và đặt các thuộc tính CellType sang giá trị mà chúng ta có thể sử dụng được trong các đọan mã của chúng ta. Chúng ta cũng sẽ có thuộc tính DescriptiveCellType mà chúng ta có thể thể hiện kiểu của cell như là text (tôi muốn giữ nguyên bản).
Bên dưới đây là mã của class module CCell. Class module này được dùng để tạo ra một đối tượng Cell người dùng đại diện cho một dạng cell đặt biệt, phân tích các thành phần mà cell chứa đựng và trả về kiểu của cell như là một chuổi text thân thiện với người dùng hơn.

Mã:
Option Explicit

Public Enum anlCellType
    anlCellTypeEmpty
    anlCellTypeLabel
    anlCellTypeConstant
    anlCellTypeFormula
End Enum

Private muCellType As anlCellType
Private mrngCell As Excel.Range

Property Set Cell(ByRef rngCell As Excel.Range)
    Set mrngCell = rngCell
End Property

Property Get Cell() As Excel.Range
    Set Cell = mrngCell
End Property

Property Get CellType() As anlCellType
    CellType = muCellType
End Property

Property Get DescriptiveCellType() As String
    Select Case muCellType
        Case anlCellTypeEmpty
            DescriptiveCellType = "Empty"
        Case anlCellTypeFormula
            DescriptiveCellType = "Formula"
        Case anlCellTypeConstant
            DescriptiveCellType = "Constant"
        Case anlCellTypeLabel
            DescriptiveCellType = "Label"
    End Select
End Property

Public Sub Analyze()
    If IsEmpty(mrngCell) Then
        muCellType = anlCellTypeEmpty
    ElseIf mrngCell.HasFormula Then
        muCellType = anlCellTypeFormula
    ElseIf IsNumeric(mrngCell.Formula) Then
        muCellType = anlCellTypeConstant
    Else
        muCellType = anlCellTypeLabel
    End If
End Sub

Class module CCell có chứa một public enumeration với bốn thành phần, một thành phần sẽ đại diện cho một kiểu của cell. Mặc định chúng có các giá trị từ 0 đến 3. (Giải thích sơ về enumeration: các bạn để ý rằng khi các bạn lập trình trong VBA, một khi các bạn gõ Application.Calculation. thì các bạn sẽ thấy hiện ra như hình sau:

enum.jpg

Đó chính là Enumeration.

Enumeration sẽ giúp cho các đọan mã của chúng ta dễ đọc và dễ sửa chữa hơn.
Chúng ta hãy xem thủ tục AnalyzeActiveCell

Mã:
Public Sub AnalyzeActiveCell()

    Dim clsCell As CCell

    ' Create new instance of Cell object
    Set clsCell = New CCell

    ' Determine cell type and display it
    Set clsCell.Cell = Application.ActiveCell
    clsCell.Analyze
    MsgBox clsCell.DescriptiveCellType

End Sub

Nếu bạn chọn một cell trên worksheet và thực hiện thủ tục trên, nó sẽ tạo một instance mới của class module CCell để lưu trữ biến đối tượng clsCell. Thủ tục sẽ gán active cell cho thuộc tính Cell của đối tượng Cell, thực hiện phương thức Analyze và hiện thông báo thuộc tính DescriptiveCellType.

Cấu trúc của một Class Module
Một class module chứa đựng chi tiết (blueprint) của một đối tượng. Bạn có thể sử dụng class module để tạo nhiều instance của đối tượng tùy thuộc vào nhu cầu của bạn. Class module định nghĩa các phương thức và các thuộc tính của đối tượng. Bất kỳ một thủ tục (subroutine) họăc hàm (function) trong class module sẽ trở nên các phương thức của đối tượng. Bất kỳ public variables (biến tòan cục) hoặc property procedures (thủ tục thuộc tính) sẽ trở nên các thuộc tính của đối tượng.

Thủ tục thuộc tính (Property Procedures)
Thay vì phải dựa vào các public variables để định nghĩa các thuộc tính, chúng ta sẽ dùng property procedures để định nghĩa các thuộc tính của đối tượng. Nó sẽ giúp bạn dễ dàng điều khiển hơn trong việc gán các giá trị và trả về các giá trị. Thủ tục thuộc tính cho phép bạn kiểm tra các giá trị được truyền cho đối tượng và thực hiện các hành động thích hợp. Chúng cũng cho phép bạn tạo các thuộc tính chỉ đọc (read only) hoặc chỉ ghi (write only).

Class CCell sử dụng hai biến cục bộ (private module level variables) để lưu các thuộc tính nội bộ (properties internally). muCellType chứa đựng kiểu cell trong danh sách của enumeration anlCellType. mrngCell tham chiếu đến single-cell Range mà một đối tượng được tạo ra từ class CCell sẽ đại diện.

Thủ tục thuộc tính quản lý giao diện (interface) giữa các biến này với thế giới bên ngòai (tức là bên ngòai class module này). Thủ tục thuộc tính nó có ba dạng:
_ Property Let dùng để gán giá trị cho một thuộc tính.
_ Property Set dùng để gán một đối tượng cho một thuộc tính.
_ Property Get dùng để trả về giá trị hoặc đối tượng tham chiếu (object reference) trong một thuộc tính cho thế giới bên ngòai.

Tên của thuộc tính (thủ tục thuộc tính) là tên mà thế giới bên ngòai có thể gọi. Class CCell sử dụng Property Set Cell để cho phép bạn gán một Range tham chiếu cho thuộc tính Cell của đối tượng Cell. Thủ tục thuộc tính lưu tham chiếu đến biến mrnCell. Thủ tục có thể có kiểm tra giá trị để chắc chắn rằng chỉ có thể làm việc với single-cell range. Thủ tục Property Get Cell cho phép thuộc tính này được đọc.

Class CCell dùng hai thủ tục Property Get để trả về kiểu cell. Các thuộc tính này là thuộc tính chỉ đọc bởi vì nó không có thủ tục Property Let.

Phương thúc (Methods)
Class CCell có một phương thức được định bởi thủ tục Analyze. Nó định nghĩa kiểu dữ liệu trong một cell tham chiếu bởi biến mrngCell. Bởi vì đây là thủ tục nên phương thức này của class CCell không trả về giá trị cho bên ngòai. Nếu phương thức được tạo bởi một hàm (function), thì gía trị sẽ được trả về cho bên ngòai.
Phương thức Analyze sẽ trả về kiểu chuổi tùy thuộc vào giá trị của cell.

Tạo Collection
Bây giờ chúng ta đã có đối tượng Cell, chúng ta sẽ tạo nhiều instance object qua đó chúng ta có thể phân tích một worksheet hoặc tập họp các cell. Cách dễ nhất để quản lý các đối tượng này là lưu chúng trong một collection (tập họp). VBA cung cấp một đối tượng Collection mà bạn có thể dùng để lưu các đối tượng và dữ liệu. Một đối tượng Collection có bốn phương thức:
_ Add – Thêm
_ Count – Đếm
_ Item
_ Remove – Xóa

Không có sự giới hạn (no restriction) về kiểu dữ liệu được lưu trữ trong một Collection, các mục (items) với các kiểu dữ liệu khác nhau được lưu trong cùng một Collection.
Trong trường hợp của chúng ta, chúng ta muốn lưu chỉ đối tượng Cell trong cùng một Collection.
Để tạo một Collection mới, bước đầu tiên là thêm vào một module standart mới. Module này có tên MGlobals. Bước kế tiếp thêm vào khai báo biến như sau vào module MGlobals để khai báo biến đối tượng Collection dạng global.

Mã:
Public gcolCells As Collection

Sẽ tiếp tục ở bài sau.

Lê Văn Duyệt
 
Lần chỉnh sửa cuối:
Bây giờ chúng ta thêm thủ tục CreateCellsCollection vào module MEntryPoints.

Tòan bộ code của module MEntryPoints như sau:
Mã:
'
' Description:  This module contains all entry points into the
'               application.
'
' Authors:      Stephen Bullen, www.oaltd.co.uk
'               Rob Bovey, www.appspro.com
'
Option Explicit

'
' Comments: This procedure creates a collection of Cell objects
'           referring to the selected cells on the active sheet.
'
' Date        Developer       Action
' --------------------------------------------------------------
' 05 Mar 04   John Green      Created
'
Public Sub CreateCellsCollection()

    Dim clsCell As CCell
    Dim rngCell As Range
    
    ' Create new Cells collection
    Set gcolCells = New Collection
    
    ' Create Cell objects for each cell in Selection
    For Each rngCell In Application.Selection
        Set clsCell = New CCell
        Set clsCell.Cell = rngCell
        clsCell.Analyze
        'Add the Cell to the collection
        gcolCells.Add Item:=clsCell, Key:=rngCell.Address
    Next rngCell
    
    ' Display the number of Cell objects stored
    MsgBox "Number of cells stored: " & CStr(gcolCells.Count)

End Sub
Chúng ta khai báo gcolCells là biến đối tượng ở mức public, do đó nó sẽ tồn tại trong khi workbook vẫn mở và có thể được sử dụng trong các thủ tục khác trong VBA Project.
Thủ tục CreateCellsCollection tạo một instance mới cho Collection và duyệt qua các cell được chọn, tạo một instance mới của đối tượng Cell cho mỗi cell và thêm chúng vào collection. Địa chỉ của mỗi cell (kiểu $A$1 style) được dùng làm khóa (key) nhằm nhận biết tính duy nhất của nó và cung cấp cách truy cập vào đối tượng Cell sau này.

Chúng ta có thể duyệt qua các đối tượng trong collection bằng việc dùng vòng lập For…Each…

Chúng ta truy cập vào từng đối tượng Cell bằng vị trí của nó trong collection hoặc bằng khóa mà chúng ta đã đề cập ở trên. Bởi vì phương thức Item là phương thức mặc định cho collection, chúng ta có thể dùng mã như sau để truy cập vào từng đối tượng Cell riêng rẻ.

Mã:
Set rngCell = gcolCells(3)
Set rngCell = gcolCells("$A$3")

Tạo một đối tượng Collection

Collection chúng ta vừa tạo dễ sử dụng nhưng nó thiếu một số chức năng mà chúng ta muốn có. Không có control thông qua kiểu của đối tượng được thêm vào collection. Chúng ta cũng muốn thêm phương thức vào collection cho phép chúng ta đánh dấu (highlight) cell hoặc ngược lại xóa việc đánh dấu này.

Đầu tiên chúng ta thêm hai phương thức vào class module CCell.
Phương thức Highlight tô màu cho đối tượng Cell tùy thuộc vào CellType. Phương thức UnHighlight làm việc ngược lại.

Chú ý chúng ta đang dùng nguyên tắc tóm lược. Tất cả các mã liên qua đến đối tượng Cell được chứa trong class module CCell, mà không chứa trong các module khác. Làm như vậy giúp cho chúng ta dễ dàng tìm các đọan mã và chỉnh sửa chúng.

Hai phương thức trên có mã như sau:

Mã:
Public Sub Highlight()
  Cell.Interior.ColorIndex = Choose(muCellType + 1, 5, 6, 7, 8)
End Sub

Public Sub UnHighlight()
  Cell.Interior.ColorIndex = xlNone
End Sub

Cuối cùng mã của class module CCell như sau:
Mã:
Option Explicit

Private mcolCells As Collection

Property Get Count() As Long
    Count = mcolCells.Count
End Property

Property Get Item(ByVal vID As Variant) As CCell
    Set Item = mcolCells(vID)
End Property
Private Sub Class_Initialize()
    Set mcolCells = New Collection
End Sub

Public Sub Add(ByRef rngCell As Range)
    Dim clsCell As CCell
    Set clsCell = New CCell
    Set clsCell.Cell = rngCell
    clsCell.Analyze
    mcolCells.Add Item:=clsCell, Key:=rngCell.Address
End Sub

Public Function NewEnum() As IUnknown
    Set NewEnum = mcolCells.[_NewEnum]
End Function

Public Sub Highlight(ByVal uCellType As anlCellType)
    Dim clsCell As CCell
    For Each clsCell In mcolCells
        If clsCell.CellType = uCellType Then
            clsCell.Highlight
        End If
    Next clsCell
End Sub

Public Sub UnHighlight(ByVal uCellType As anlCellType)
    Dim clsCell As CCell
    For Each clsCell In mcolCells
        If clsCell.CellType = uCellType Then
            clsCell.UnHighlight
        End If
    Next clsCell
End Sub

Lê Văn Duyệt
 
Lần chỉnh sửa cuối:
Upvote 0
ongtrungducmx25 đã viết:
Anh việt nè class module có gì khác với module không zây !
Bạn vui lòng đừng sửa tên mình !
Bạn đọc ở bài #1, tôi có đưa đường link bạn có thể tìm câu trả lời ở đó.

Lê Văn Duyệt
 
Upvote 0
Thấy rất hay và bổ ích nhưng cao siêu quá, không hiểu.
Phải chi anh Duyệt có file kèm, vd nhỏ, và có so sánh giữa class và no class thì hay biết mấy.


From AnhTuan1066
ThuNghi mà còn nói "hổng có hiểu" thì ngoại đạo như tôi chắc đành "bó bột" quá.. Hic.. Hic..
ANH TUẤN
 
Upvote 0
ThuNghi đã viết:
Thấy rất hay và bổ ích nhưng cao siêu quá, không hiểu.
Phải chi anh Duyệt có file kèm, vd nhỏ, và có so sánh giữa class và no class thì hay biết mấy.
To: ThuNghi,
Như tôi đã có đề cập ở phần #1, tôi có đưa ra các link để tìm hiểu thêm.

Khi viết bài này tôi giả sử rằng các bạn đã quen với các khái niệm thuộc tính, phương thức, bạn đã viết các code cho module, worksheet (class module),...
Nhiều khái niệm tôi chỉ muốn giữ nguyên để các bạn tìm hiểu thêm ở tài liệu khác. Ví dụ như khái niệm new instance chẳng hạn.

Thôi ráng nha, từ từ bài viết sẽ hướng dẫn cho các bạn.


Lê Văn Duỵêt
 
Upvote 0
Thien đã viết:
Mình cũng có bài nhờ A.Duyệt làm dùm file mẫu, nhưng vẫn chưa có hồi âm.
TC.

Xin lỗi chắc có lẻ nhiều quá. Bạn nên post trên box Lập trình với Excel để các bạn khác cùng giúp bạn.

Lê Văn Duyệt
 
Upvote 0
Tôi xin bổ sung thêm 1 chút về class module vì bác Duyệt nói cao siêu quá, em còn đang tiêu hóa.

Tôi tạo một đối tượng có tên là LyLich trong class module. Đối tượng Lylich đó 3 phương thức Ten, Tuoi, Nghenghiep. Các bạn nhớ chạy thủ tục trong standard module nhé!
Các bạn tải file kèm theo...

Bác Duyệt ơi, bác tiếp tục với ví dụ đơn giản nhất về set và get cho thuộc tính (tự tạo) của đối tượng trong class module đi.
 

File đính kèm

  • Tạo Class.xls
    30.5 KB · Đọc: 325
Chỉnh sửa lần cuối bởi điều hành viên:
Upvote 0
Upvote 0
các bác giải thích giúp em: Property Let và Property Get có ý nghĩa thế nào? cảm ơn!
 
Upvote 0
Duong_VBA đã viết:
các bác giải thích giúp em: Property Let và Property Get có ý nghĩa thế nào? cảm ơn!

Đơn giản vô cùng.

Khi bạn gán Text1.Text = "ABC" thì tức là bạn đang dùng đến Property Let đấy. Còn khi bạn lấy dữ liệu strText = Text1.Text thì tức là bạn đang dùng đến Property Get đấy. Bạn có thấy đơn giản khi chỉ cần dịch chữ Get và chữ Let từ tiếng anh sang tiếng Việt là đã có thể hiểu được về ý nghĩa của nó thế nào rồi.

Hope that helps!
 
Upvote 0
@levanduyet sau mấy hôm nghiên cứu bài viết và các ví dụ trong bài của anh, em có mấy câu hỏi mong anh giải đáp ạ.
1) Trong phần ví dụ class đầu tiên, em có ghép phương thức Analyze thành một thuộc tính DescriptiveCellType duy nhất và khi chạy vẫn ra kết quả như mong muốn vậy thì có nhất thiết phải tách thanh phương thức và thuộc tính riêng như vậy không a?
2) Trong module MEntryPoints biến mcolCells đã là collection thì sao mình không dùng phương thức có sẵn mà phải khai báo lại thuộc tính add thế ạ? và hình như mình chưa dùng hết các chức năng khai báo trong class đúng không ạ?
 
Upvote 0
1. Đó là một trong những điểm hay của LT HĐT.
Nếu không thấy cần Analyze thì cứ việc đặt nó là Private.
Đối với thiết kế class, cái phần cần gọn là giao diện (các phương thức/thuộc tính public). Phần Private còn cần để cải tiến, không nên "gộp cho gọn".

2. Phương thức khai báo lại sẽ chồng lên phương thức có sẵn của thuộc tính. Người ta dùng để làm thêm một vài việc phụ mà phương thức có sẵn không làm. Tỷ dụ như Add là thêm dữ liệu thì phương thức mới có thể kiểm soát dữ liệu theo điều kiện nào đó trước khi "Add". Điển hình nhất là Collection chính thức của VBA không có bảng tra, nhiều người sẽ viết thêm để tạo bảng tra.
 
Upvote 0
Web KT
Back
Top Bottom