Class module-Lập trình hướng đối tượng trong VBA

tuhocvba

Administrator
Thành viên BQT
Class module là một kỹ thuật nâng cao để người phát triển tạo thêm cho mình những class/đối tượng.
Có 2 lý do sau khiến chúng ta nên sử dụng class:
+ Tạo đối tượng giống nhau.
+ Gán thêm thuộc tính cho một control/đối tượng đã có (như là: Property, Method, Even).
Một ví dụ kinh điển nhất đó là trên Tool đặt phòng họp, trên UserForm nếu có ai đặt phòng họp thì sẽ sinh ra một label mới. Trên Label đó ghi các thông tin ngày giờ, phòng họp, ai đặt, số điện thoại.... Như vậy Label có rất nhiều thuộc tính. Ngoài ra còn có sự kiện double click vào label sẽ hiển thị thông tin này. Do số label là không thể kiểm soát ngay từ đầu, cho nên việc xây dựng hàm double click cho từng label là không khả thi. Lúc này chúng ta phải sử dụng class.

Chúng ta tạo class_sv
Bạn cần đăng nhập để thấy hình ảnh

trên đó viết code như sau:
Mã:
'===========PROPERTY
Private nme As String
Private diem As String
'-----------------------THUOC TINH: NAME
Public Property Let Name(s As String) 'Ham nhap thong tin cho doi tuong
    nme = s
End Property

Public Property Get Name() As String  'Ham truy xuat thong tin tu doi tuong
    Name = nme
End Property
'-----------------------THUOC TINH: MARK
Public Property Let Mark(s As String)
    diem = s
End Property

Public Property Get Mark() As String
    Mark = diem
End Property


Public Function danhgia() As String

    If Val(Mark) < 8 Then
        danhgia = "NG"
    Else
        danhgia = "OK"
    End If
    
End Function
'================METHOD
Public Function benkyou() As String 'Phuong thuc danh gia

    If danhgia = "NG" Then
        benkyou = "Hoan toan khong hoc gi"
    Else
        benkyou = "Da hoc rat cham chi"
    End If
    
End Function
Bạn cần đăng nhập để thấy hình ảnh

Trên Module 1, chúng ta viết code như sau và hãy thử chạy code nhé:
Mã:
Sub test()
    Dim sv  As class_sv
    Set sv = New class_sv
    
    sv.Name = "Tuhocvba.net"
    sv.Mark = "6"
 
    MsgBox sv.benkyou
    MsgBox sv.Name
    MsgBox sv.Mark
End Sub
Bạn cần đăng nhập để thấy hình ảnh

Ta được kết quả như sau:
Bạn cần đăng nhập để thấy hình ảnh
 

Euler

Mod
Thành viên BQT
Hôm nay chúng ta có một câu chuyện như sau:
Trên UserForm, tôi có 5 label. Và mỗi label, tôi muốn gán sự kiện click cho nó. Nếu click vào label thì sẽ hiển thị thông báo tên caption của label.
Bạn cần đăng nhập để thấy đính kèm

Nói đến đây, chắc là các bạn đã hình dung, ta sẽ phải viết 5 hàm click cho 5 cái label này. Nếu trong thực tế, ta có đến 200 cái label thì sẽ thật là vất vả. Vậy, hôm nay tôi sẽ giới thiệu mọi người cách sử dụng Class để gán sự kiện cho các label này một cách nhanh chóng.

1. Tôi tạo Class là: ClassLabelTHVBA
Mã:
Public WithEvents labelthvba As MSForms.Label
Private Sub labelthvba_Click()
    MsgBox labelthvba.Caption
End Sub
2. Tôi tạo Module1.
Ở đây tôi khai báo mảng public để lưu các label vào mảng này.
Mã:
Public mang_lbale()   As ClassLabelTHVBA
3. Tôi tạo UserForm1. Code cho UserForm1 là:
Mã:
Sub tao_label()

    Dim obj         As Object
    Dim cnt_temp    As Integer
    Dim lbl_temp    As MSForms.Label
    Dim i           As Integer
    'Phần code này để tạo ra 5 label, không liên quan gì tới class
    'Tham khảo: https://tuhocvba.net/threads/userform-add-label-for-userform-tu-dong-them-label-vao-userform.122/
    For i = 1 To 5 Step 1
        Set lbl_temp = UserForm1.Controls.Add("Forms.Label.1", "tuhocvba" & i, True) 'Add new label
        With lbl_temp
            lbl_temp.Caption = "Label" & i 'Set name for label
            lbl_temp.Top = 20 * i
            lbl_temp.left = 12
        End With
    Next i
    
    cnt_temp = 0
    For Each obj In UserForm1.Controls
        If InStr(1, obj.Name, "tuhocvba") > 0 Then
            cnt_temp = cnt_temp + 1
            ReDim Preserve mang_lbale(1 To cnt_temp)
            'Phần code này liên quan tới class, mục đích để gán sự kiện trong class cho label
            Set mang_lbale(cnt_temp) = New ClassLabelTHVBA
            Set mang_lbale(cnt_temp).labelthvba = obj
        End If
    Next obj

End Sub
Private Sub UserForm_Initialize()
    Call tao_label
End Sub
Download file demo:
 

phivinhtuan

Thành viên mới
Mình có 1 File, khi Click vào Sheet thì nó sẽ hiển thị thông báo Tên Sheet được Select, và mình vào từng Sheet để khai báo sự kiện "Private Sub Worksheet_Activate" , tuy nhiên khi thêm một Sheet mới thì lại phải vào Sheet đó để khai báo sự kiện, 1 vài sheet thì được chứ 10 sheet chắc cũng hơi nản. Mình thấy Class có thể giải quyết bài toán này nhưng chưa biết phải khai báo thế nào:
1. khi workbook open thì khai báo gì
2. trong module class thì khai báo gì
3. Trong Module thường thì khai báo gì
Cám ơn bạn.
 

Ngày Mới

Thành viên tích cực
@phivinhtuan Bạn viết Code trong Class Module đặt tên SheetEvent, Bạn có thể thay thế nội dung Code trong 2 Sub Sheet_ActivateSheet_Deactivate để phù hợp công việc cá nhân.
Mã:
Public WithEvents Sheet As Worksheet

Public Sub Capture(ByVal Worksheet As Worksheet)
Set Sheet = Worksheet
End Sub

Private Sub Class_Terminate()
Set Sheet = Nothing
End Sub

Private Sub Sheet_Activate()
'Noi dung Code khi Activate Sheet
MsgBox Sheet.Name & " Activate"
End Sub

Private Sub Sheet_Deactivate()
'Noi dung Code khi Deactivate Sheet
MsgBox Sheet.Name & " Deactivate"
End Sub
Mình giả sử bạn muốn Code cho 2 Sheet là "Sheet1" và "Sheet2" khi Activate và Deactivate, nếu muốn nhiều hơn thì thêm vào nhiều biến Ws hơn. Trong Module bạn viết Code như thế này:
Mã:
Public Ws1, Ws2 As SheetEvent

Sub Auto_Open()
Set Ws1 = New SheetEvent
Set Ws2 = New SheetEvent
Ws1.Capture ThisWorkbook.Worksheets("Sheet1")
Ws2.Capture ThisWorkbook.Worksheets("Sheet2")
End Sub
 
Sửa lần cuối:

phivinhtuan

Thành viên mới
Mình đã thử và chạy được. Mình có thử code thêm, nếu click vào ô "A1:A10" của Sheet1 thì mới hiển thị thông báo
Private Sub Sheet_SelectionChange(ByVal Target As Range)
If Sheet.Name = "Sheet1" Then
MsgBox Sheet.Name & " Activate"
End If
End Sub
Tuy nhiên, chưa biết khai báo vùng "A1:A10" trong code thế nào
Cám ơn bạn!
 

Ngày Mới

Thành viên tích cực
@phivinhtuan Khi bài viết có Code, bạn hãy để trong thẻ code. Nếu chưa biết cách để Code trong thẻ, hãy đọc .

Trong Class Module, Bạn thử sửa code như bên dưới:
Mã:
Private Sub Sheet_SelectionChange(ByVal Target As Range)
If Sheet.Name <> "Sheet1" Then Exit Sub
If Not Intersect(Target, Range("A1:A10")) Is Nothing Then MsgBox Sheet.Name & " Selection " & Target.Address
End Sub
 

phivinhtuan

Thành viên mới
Mình mới thử sử dụng class, thấy nó rất tiện, tuy nhiên dường như mình thấy nó liên tục kiểm tra hành thao tác của mình trên sheet để chạy lệnh tuơng ứng, không biết như vậy nó có chiếm tài nguyên hệ thống không bạn nhỉ, mình sợ nhất lỗi out of memory vì không biết dính lỗi chỗ nào mà lần
 
Top