Class module - Kỹ thuật Tạo và Wrap đối lượng (1 người xem)

Liên hệ QC

Người dùng đang xem chủ đề này

Nguyễn Duy Tuân

Nghị Hách
Thành viên danh dự
Tham gia
13/6/06
Bài viết
4,854
Được thích
10,345
Giới tính
Nam
Nghề nghiệp
Giáo viên, CEO tại Bluesofts
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 hay "bao" một đối tượng.
Có 2 lý do sau buộc bạn phải viết 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).

Xem file đính kèm dưới đây các bạn sẽ hiểu thêm ý nghĩa của nó.

(Để học cách viết code trong Class module, các bạn hãy tìm các bài viết đã có trên diễn đàn này hoặc tìm đọc tài liệu lập trình Class trong VB/VBA trên mạng)
 

File đính kèm

Kiểm soát nhập liệu trong Excel

Gửi các bạn một ví dụ về cách quản lý tất cả quá trình hoạt động của Excel.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
clsCommandButton

Nhân có ngươì bạn nhờ giúp về kỹ thuật CommandButton, tôi làm một ví dụ về kỹ thuật tạo và bao/Wrapping đối tượng CommandButton. Với file ví dụ "clsCommandButton.xls" chắc các bạn sẽ rất thú vị! Mong rằng sau này chúng ta sẽ có nhiều người coding nhiều với "Class module".

B1) Tạo một module (Trong VBE, vào menu Insert->Module) để test
Mã:
Option Explicit
'-------------------------------------------------
Const strClassObj As String = "Forms.CommandButton.1"
Public ctrlShNum() As clsCommandButton
Private CtrlCount As Integer
Public oldBtn As String
'-------------------------------------------------
Sub CreateCommandButtonOnSheet()
On Error GoTo Done

Dim cell As Range, objRanges As Range
Dim sh As Worksheet
Dim obj As OLEObject
Dim oldEvent As Boolean

oldEvent = Application.EnableEvents
Application.EnableEvents = False

    Set sh = ActiveSheet
    Set objRanges = Range("B3:B14")
    objRanges.RowHeight = 24
    
    CtrlCount = -1
    For Each cell In objRanges
        Set obj = sh.OLEObjects.Add(ClassType:=strClassObj, _
        Link:=False, DisplayAsIcon:=False, Left:=cell.Left, Top:=cell.Top, _
        Width:=cell.Width, Height:=cell.Height)
     
        CtrlCount = CtrlCount + 1
        ReDim Preserve ctrlShNum(CtrlCount) As clsCommandButton
        Set ctrlShNum(CtrlCount) = New clsCommandButton
        
        With ctrlShNum(CtrlCount)
            .Wrap obj.Object  
            .Caption = "CommandButton " & CtrlCount
        End With
        Set obj = Nothing
        Set cell = Nothing
    Next
Done:

Application.EnableEvents = oldEvent
    
    Set objRanges = Nothing
    Set sh = Nothing
If Err.Number <> 0 Then MsgBox Err.Description
End Sub
'-------------------------------------------------
Sub DeleteAllCommandButtons()
On Error Resume Next

Dim sh As Worksheet
Dim obj As OLEObject
Dim i As Integer
    Set sh = ActiveSheet
    For Each obj In sh.OLEObjects
        If obj.progID = strClassObj Then
            obj.Delete
        End If
    Next
    
    For i = LBound(ctrlShNum, 1) To UBound(ctrlShNum, 1)
        If Not ctrlShNum(i) Is Nothing Then
            Set ctrlShNum(i) = Nothing
        End If
    Next
    ReDim ctrlShNum(0) As clsCommandButton
    Set sh = Nothing

End Sub

B2) Tạo một Class/đối tượng (Trong VBE, vào menu Insert->Class module) , đặt tên là "clsCommandButton"

Mã:
'**************************************************************
Option Explicit
Private WithEvents ctrl As MSForms.CommandButton

'Constructor
Private Sub Class_Initialize()
    
End Sub

'FreeMem/Dispose
Private Sub Class_Terminate()
    If Not ctrl Is Nothing Then
        'ctrl.Delete
        Set ctrl = Nothing
    End If
End Sub
'-------------------------------------------------
'Methods
Public Sub Add(Form As MSForms.UserForm, Optional ByVal strCaption As String = "")
    Set ctrl = Form.Controls.Add("Forms.CommandButton.1")
    If strCaption <> "" Then
        ctrl.Caption = strCaption
    End If
End Sub
'-------------------------------------------------
Public Sub Wrap(ByVal ctrlCoomandButton As Object, Optional ByVal strCaption As String = "")
    Set ctrl = ctrlCoomandButton
    If strCaption <> "" Then
        ctrl.Caption = strCaption
    End If
End Sub
'-------------------------------------------------
'Properties

'Property Value
'-------------------------------------------------
Public Property Let Caption(ByVal vData As String)
'used when assigning a value to the property, on the left side of an assignment.
    ctrl.Caption = vData
End Property
Public Property Get Caption() As String
'used when retrieving value of a property, on the right side of an assignment.
    Caption = ctrl.Caption
End Property
'-------------------------------------------------
Public Property Let ForeColor(ByVal vData As Long)
'used when assigning a value to the property, on the left side of an assignment.
    ctrl.ForeColor = vData
End Property
Public Property Get ForeColor() As Long
'used when retrieving value of a property, on the right side of an assignment.
    ForeColor = ctrl.ForeColor
End Property
'-------------------------------------------------
Public Property Let BackColor(ByVal vData As Long)
'used when assigning a value to the property, on the left side of an assignment.
    ctrl.BackColor = vData
End Property
Public Property Get BackColor() As Long
'used when retrieving value of a property, on the right side of an assignment.
    BackColor = ctrl.BackColor
End Property
'-------------------------------------------------
'Property Top
Public Property Let Top(ByVal vData As Integer)
'used when assigning a value to the property, on the left side of an assignment.
    ctrl.Top = vData
End Property
Public Property Get Top() As Integer
'used when retrieving value of a property, on the right side of an assignment.
    Top = ctrl.Top
End Property
'-------------------------------------------------
'Property Left
Public Property Let Left(ByVal vData As Integer)
'used when assigning a value to the property, on the left side of an assignment.
    ctrl.Left = vData
End Property
Public Property Get Left() As Integer
'used when retrieving value of a property, on the right side of an assignment.
    Left = ctrl.Left
End Property
'-------------------------------------------------
'Property Width
Public Property Let Width(ByVal vData As Integer)
'used when assigning a value to the property, on the left side of an assignment.
    ctrl.Width = vData
End Property
Public Property Get Width() As Integer
'used when retrieving value of a property, on the right side of an assignment.
    Width = ctrl.Width
End Property
'-------------------------------------------------
'Property Height
Public Property Let Height(ByVal vData As Integer)
'used when assigning a value to the property, on the left side of an assignment.
    ctrl.Height = vData
End Property
Public Property Get Height() As Integer
'used when retrieving value of a property, on the right side of an assignment.
    Height = ctrl.Height
End Property
'-------------------------------------------------

[COLOR="Green"]'Events[/COLOR]
Private Sub ctrl_Click()
    ctrl.ForeColor = vbBlue
    MsgBox ctrl.Caption, , oldBtn
End Sub
'-------------------------------------------------
Private Sub ctrl_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
Dim objCtrl As MSForms.CommandButton
    If oldBtn <> ctrl.Name Then
    '--Reset
        If oldBtn <> "" Then
            If TypeName(ctrl.Parent) = "Worksheet" Then '// Parent is Worksheet
                Set objCtrl = ctrl.Parent.OLEObjects(oldBtn).Object
            Else '// Parent is Userform
                Set objCtrl = ctrl.Parent.Controls(oldBtn)
            End If
            
            With objCtrl
                .ForeColor = vbBlack
                .BackColor = vb3DFace
                .Font.Bold = False
            End With
        End If
    '--Set New
        oldBtn = ctrl.Name
        ctrl.ForeColor = vbRed
        ctrl.Font.Bold = True
        ctrl.BackColor = vbYellow
    End If
End Sub

Các bạn tải file đính kèm tham khảo.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Không cho đóng và lưu các workbook đang mở!

Xin gửi thêm các bạn ví dụ về khóa tất cả các workbook đang mở. Chương trình rất dễ viết nhưng phải dùng Class Module.

Bước 1: Tạo Class Module, đặt tên là clsExcelApp.
Trong môi trường VBA/VBE, Vào menu Insert\Class Module. Đặt tên class là clsExcelApp.

Soạn các lệnh sau vào trong class clsExcelApp.
Mã:
Option Explicit

Private WithEvents MyExcelApp As Excel.Application
Private mCancelClose As Boolean
Private mCancelSave As Boolean

Private Sub Class_Initialize()
    
End Sub

Private Sub Class_Terminate()
    Destroy
End Sub

Public Sub Create(ByVal ExcelApplication As Excel.Application)
    If Not MyExcelApp Is Nothing Then Exit Sub
    Set MyExcelApp = ExcelApplication
End Sub

Public Sub Destroy()
    Set MyExcelApp = Nothing
End Sub

Private Sub MyExcelApp_WorkbookBeforeClose(ByVal Wb As Workbook, Cancel As Boolean)
    Cancel = mCancelClose
    If Cancel Then
        MsgBox "All workbook are locked!. To unlock them, you send bears to me now!", vbCritical, "Author: Nguyen Duy Tuan"
    End If
End Sub

Public Property Get CancelClose() As Boolean
    CancelClose = mCancelClose
End Property

Public Property Let CancelClose(ByVal bNewValue As Boolean)
    mCancelClose = bNewValue
End Property

Public Property Get CancelSave() As Boolean
    CancelSave = mCancelSave
End Property

Public Property Let CancelSave(ByVal bNewValue As Boolean)
    mCancelSave = bNewValue
End Property

Private Sub MyExcelApp_WorkbookBeforeSave(ByVal Wb As Workbook, ByVal SaveAsUI As Boolean, Cancel As Boolean)
    Cancel = mCancelSave
    SaveAsUI = Not Cancel
    If Cancel Then
        MsgBox """" & Wb.Name & """ can not save. You send bears to me for saving!", vbCritical, "Author: Nguyen Duy Tuan"
    End If
End Sub

Bước 2: Tạo Module để tạo các thủ tục chạy
Trong môi trường VBA/VBE, Vào menu Insert\Module.

Soạn các lệnh sau vào trong module
Mã:
Option Explicit
Dim MyExcelApp As clsExcelApp
Sub LockAllWorkbook()
    
    If Not MyExcelApp Is Nothing Then Exit Sub
    
    Set MyExcelApp = New clsExcelApp
    With MyExcelApp
        .Create Application
        .CancelClose = True
        .CancelSave = True
    End With
    
    MsgBox "All workbook are locked from this time!" & Chr(13) & _
            "To unlock, click ""StopLock"" button.", vbExclamation
    
End Sub

Sub CancelLoking()
    If MyExcelApp Is Nothing Then Exit Sub
    MyExcelApp.CancelClose = False
    MyExcelApp.CancelSave = False
End Sub

Sub StopLock()
    Set MyExcelApp = Nothing
    MsgBox "All workbook are free (unlock)!", vbInformation
End Sub

Toàn bộ mã nguồn có trong file đính kèm.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Forms And NumPad

Các bạn tham khảo ví dụ tôi viết trong bài này "Forms And NumPad". Xem bài số #8
 
Upvote 0
Mình tải file của bạn về mở chỉ xuất hiện một hộp thoại à
 
Upvote 0
Mình đang tìm tòi học hỏi về VBA này, mình thấy khi tạo CommandButtons hơn 15 cái thì UserForm không độ dài.Minh có cách làm làm 1 cái Scroll để thấy được những
CommandButtons bị quá size UserForm không ạ? Xin Anh/Chị/Em trong nhóm hỗ trợ giúp ! Cám ơn nhiều ạ
 

File đính kèm

  • Untitled.jpg
    Untitled.jpg
    39.5 KB · Đọc: 69
Upvote 0
Các anh chị giúp em sửa code để code chỉ chạy trên file "cExcelApp" được không ạ?. Tức là khi em đang sử dụng file này thì nó chạy, khi mở file khác lên thì nó dừng lại ạ
 

File đính kèm

Upvote 0
Các anh chị giúp em sửa code để code chỉ chạy trên file "cExcelApp" được không ạ?. Tức là khi em đang sử dụng file này thì nó chạy, khi mở file khác lên thì nó dừng lại ạ

Nếu bạn muốn chỉ chạy trong file thì lập trình thẳng vào các sự kiện trong ThisWorkbook nhé. Không cần khởi tạo clsExcelApp.
 
Upvote 0
Thầy ơi, giả sử em vẫn muốn khởi tạo clsExcelApp thì có được không ạ?

Được. Em thay ExcelApp As Application thành MyWB As Workbook
Khi trỏ đổi đượng Set ExcelApp = Application thì đổi thành
Set MyWB = ThisWorkbook

Cơ bản là vậy.
 
Upvote 0
em chào thầy Nguyễn Duy Tuân, thầy có thể giúp em chỗ này được không ạ, em có tham khảo tại bài #3
và sửa lại theo cách em hiểu được để làm một listbox thay thế listbox truyền thống
trong lúc vận hành thì có truyền vào mảng Arr của listbox như trong hình
1640568693213.png
nếu vậy thì nó thêm mảng theo từng ctrl, vào lúc thêm như vậy thì ở ctrl khác cũng phải thêm, như vậy là mỗi ctrl đều có mảng riêng , vậy làm sao để chỉ thêm mảng 1 lần để dùng chung cho class đó được
em có dùng cách này để lưu mảng vào dùng chung
1640568878920.png
đó là ở vấn đề mảng cố định, còn chưa tính đến lọc cái mảng đó thì làm sao để thay đổi được ạ
tóm lại là thầy có thể gợi ý hoặc giúp em làm sao để việc truyền mảng vào linh hoạt được không ạ, với việc tô màu các label đó nhìn sao sao ấy ạ
Liên kết: https://youtu.be/J8lPM1fhmoo
 

File đính kèm

  • 1640568967846.png
    1640568967846.png
    58.5 KB · Đọc: 18
  • 1640569027432.png
    1640569027432.png
    14.1 KB · Đọc: 18
  • 1640569054318.png
    1640569054318.png
    31.6 KB · Đọc: 19
  • cListBox_Tan.xls
    cListBox_Tan.xls
    164.5 KB · Đọc: 24
Lần chỉnh sửa cuối:
Upvote 0
em chào thầy Nguyễn Duy Tuân, thầy có thể giúp em chỗ này được không ạ, em có tham khảo tại bài #3
và sửa lại theo cách em hiểu được để làm một listbox thay thế listbox truyền thống
trong lúc vận hành thì có truyền vào mảng Arr của listbox như trong hình
View attachment 270802
nếu vậy thì nó thêm mảng theo từng ctrl, vào lúc thêm như vậy thì ở ctrl khác cũng phải thêm, như vậy là mỗi ctrl đều có mảng riêng , vậy làm sao để chỉ thêm mảng 1 lần để dùng chung cho class đó được
em có dùng cách này để lưu mảng vào dùng chung
View attachment 270803
đó là ở vấn đề mảng cố định, còn chưa tính đến lọc cái mảng đó thì làm sao để thay đổi được ạ
tóm lại là thầy có thể gợi ý hoặc giúp em làm sao để việc truyền mảng vào linh hoạt được không ạ, với việc tô màu các label đó nhìn sao sao ấy ạ
Liên kết: https://youtu.be/J8lPM1fhmoo

Nếu mảng bạn muốn dùng chung co các class thì khai báo Public ở một Module nhé. Còn vấn đề tô mầu, bản thân ListBox của VBA không tô mầu tuỳ ý vài item được, ai đó làm thì có thể nhái theo kiêir ListBox.
 
Upvote 0
Nếu mảng bạn muốn dùng chung co các class thì khai báo Public ở một Module nhé. Còn vấn đề tô mầu, bản thân ListBox của VBA không tô mầu tuỳ ý vài item được, ai đó làm thì có thể nhái theo kiêir ListBox.
vậy mảng đó không truyền vào khi chạy form được sao thầy. (hiện mảng e có khai báo ở trên form từ đó truyền vào class để chạy), nếu khai báo ở module biến mảng đó thì phải khai báo nhiều biến.
trong code của thầy có mục Wrap. vậy mục đó để làm gì vậy thầy nhỉ? e thử debug thì không thấy code tại mục đó được sử dụng. còn left, top, right, height thì thấy có.
Mã:
Public Sub Wrap(ByVal ctrlCoomandButton As Object, Optional ByVal strCaption As String = "")
    Set ctrl = ctrlCoomandButton
    If strCaption <> "" Then
        ctrl.Caption = strCaption
    End If
End Sub
code này để gán top cho đối tượng hay sao thầy
Mã:
Public Property Let Top(ByVal vData As Integer): ctrl.Top = vData: End Property
còn code này trong form lấy top của đối tượng?
Mã:
Public Property Get Top() As Integer: Top = ctrl.Top: End Property

vụ class về đối tượng e chỉ mò được vài hôm nay chứ không biết nhiều
thầy có file mẫu hay gì thì cho e xin
em có xem file mẫu của anh thaipv bên bài này thì thấy thích kiểu giao diện như vậy?
nếu sử dụng giao diện bằng class như thế liệu có ảnh hưởng đến việc sử lý trong một dự án lớn không?
 
Upvote 0
VBA không phải là ngôn ngữ hướng đối tượng cho nên Class Module của nó không đạt đủ tiêu chuẩn hướng đối tượng. VBA không cho cách nào để tạo thuộc tính và phương thức riêng của class.

Tuy nhiên, trường hợp cần "chia sẻ" một array thì có thể tạm dùng phương pháp đi vòng:
- tạo một class module, ví dụ là X, với thuộc tính là cái array sẽ chia sẻ.
- trong các class modules cần làm việc với array trên. Tạo một thuộc tính có kiểu là Object
- lúc dùng, dựng một đối tượng với kiểu X. Và nạp dữ liệu nếu cần.
- các đối tượng của các class modules kia, lúc cần đến array thì gọi một phương thức KetNoiArray, Set thuộc tính đã định trên cho nó tham chiếu đến đối tượng đã dựng của kiểu X.

Lý thuyết: VBA không có con trỏ hay cách tham chiếu trực tiếp. Cách duy nhất để nhiều biến có thể cùng tham chiếu đến một trị là qua đối tượng.
 
Upvote 0
VBA không phải là ngôn ngữ hướng đối tượng cho nên Class Module của nó không đạt đủ tiêu chuẩn hướng đối tượng. VBA không cho cách nào để tạo thuộc tính và phương thức riêng của class.

Tuy nhiên, trường hợp cần "chia sẻ" một array thì có thể tạm dùng phương pháp đi vòng:
- tạo một class module, ví dụ là X, với thuộc tính là cái array sẽ chia sẻ.
- trong các class modules cần làm việc với array trên. Tạo một thuộc tính có kiểu là Object
- lúc dùng, dựng một đối tượng với kiểu X. Và nạp dữ liệu nếu cần.
- các đối tượng của các class modules kia, lúc cần đến array thì gọi một phương thức KetNoiArray, Set thuộc tính đã định trên cho nó tham chiếu đến đối tượng đã dựng của kiểu X.

Lý thuyết: VBA không có con trỏ hay cách tham chiếu trực tiếp. Cách duy nhất để nhiều biến có thể cùng tham chiếu đến một trị là qua đối tượng.
vâng e cảm ơn nhiều ạ, vậy chắc chỉ có cách này, theo file bên trên thì e truyền cho mỗi Ctrl 1 mảng Arr y chang (như vậy sẽ chiếm nhiều bộ nhớ nếu mảng lớn), em cũng không biết viết class, cái này e xem code mẫu rồi sửa lại, với cho em hỏi thêm nếu áp dụng cái list giả này vào một form xử lý nhiều dữ liệu thì có làm treo hay xử lý chậm không? nếu có mà ko có cách khắc phục thì thôi chắc em dừng lại không làm tiếp nữa.
còn nếu phát triển thêm chắc làm được thêm cái vụ thay đổi chiều rộng cột, còn lăn chuột chắc thua.
 
Upvote 0
trong lúc vận hành thì có truyền vào mảng Arr của listbox như trong hình
Nếu vậy thì nó thêm mảng theo từng ctrl, vào lúc thêm như vậy thì ở ctrl khác cũng phải thêm, như vậy là mỗi ctrl đều có mảng riêng , vậy làm sao để chỉ thêm mảng 1 lần để dùng chung cho class đó được
đó là ở vấn đề mảng cố định, còn chưa tính đến lọc cái mảng đó thì làm sao để thay đổi được ạ
tóm lại là thầy có thể gợi ý hoặc giúp em làm sao để việc truyền mảng vào linh hoạt được không ạ,
Tôi chỉ muốn tham gia 1 lần thôi. Vấn đề của bạn mà tham gia tới cùng thì chỉ còn nước viết cho bạn từ A tới Z.

Bạn dùng class clsCommandButton thực ra chỉ để tạo đối tượng và phục vụ cho mỗi Label thôi. Và cứ 4 Label thì đại diện cho 1 dòng. Nếu bạn muốn tạo ListBox thì nên có thêm vd. class clsMyListBox. Class này có vd. trường dulieu, và có phương thức vd. Create, với ít nhất 2 parameter: Owner - chủ nhân của ListBox, và Arr - mảng dữ liệu mà từ đó tạo các dòng cột của ListBox.

Mỗi khi cần tạo ListBox thì tạo đối tượng class clsMyListBox -> gọi phương thức Create của nó. Create sẽ lưu mảng Arr trong trường dulieu, Owner lưu trong vd. OwnerObj và tiếp theo gọi CreateListBox với tham số là mảng dulieu -> CreateListBox duyệt từng dòng của dulieu (tham số) -> với mỗi dòng duyệt từng cột của dulieu -> mỗi lần duyệt từng cột của dulieu trong mỗi lần duyệt dòng thì tạo đối tượng clsCommandButton -> thiết lập Caption của Label bằng giá trị dulieu(r, c) -> định vị Label dựa vào r và c -> những Label được tạo sẽ có Set ctrl = OwnerObj.Controls.Add("Forms.Label.1"). Tùy theo nhu cầu mà truyền Owner = Form hoặc Owner = Frame khi gọi Create. Tóm lại phương thức CreateListBox sẽ tạo UBound(dulieu, 1) hàng Label, mỗi hàng Label có UBound(dulieu, 2) Label, nằm trong Owner, mỗi Label có Caption = dulieu(r, c).

clsCommandButton chỉ để phục vụ mọi cái liên quan tới Label thôi. Tất nhiên đã sinh ra clsMyListBox thì phải sửa clsCommandButton. clsMyListBox thì phục vụ mọi cái liên quan tới ListBox.

Code chính sẽ tạo clsMyListBox và gọi phương thức Create của nó. Create lưu Arr trong trường dulieu và gọi phương thức CreateListBox với tham số dulieu. Chính CreateListBox mới tạo các đối tượng clsCommandButton ...

Lọc có thể như sau: khi bắt đầu thì hủy các Label -> lọc -> kết quả lọc trong mảng vd. dulieu_loc (có thể là 1 trường của clsMyListBox). Nếu dulieu_loc có dữ liệu thì gọi CreateListBox và truyền mảng dulieu_loc để tạo ListBox mới tương ứng với mảng lọc.

Không có chuyện Arr nằm trong Module với tư cách Public. Mảng nằm trong class clsMyListBox và được truyền vào 1 lần ở Create. Nếu có nhu cầu thay đổi mảng cho ListBox trong quá trình hoạt động của ListBox thì tốt nhất tạo thuộc tính read/write ListBox cho clsMyListBox. Set sẽ lưu Arr vào dulieu và gọi CreateListBox với tham số dulieu để tạo mới ListBox. Get thì trả về mảng dulieu. Lúc đó thì sau khi tạo đối tượng clsMyListBox thì dùng SET để thiết lập thuộc tính ListBox của nó.

Đại loại mọi cái là như trên. Mọi dữ liệu nằm gói gọn trong các class, không có chuyện nằm ở ngoài sheet, module.
 
Upvote 0
Tôi chỉ muốn tham gia 1 lần thôi. Vấn đề của bạn mà tham gia tới cùng thì chỉ còn nước viết cho bạn từ A tới Z.

Bạn dùng class clsCommandButton thực ra chỉ để tạo đối tượng và phục vụ cho mỗi Label thôi. Và cứ 4 Label thì đại diện cho 1 dòng. Nếu bạn muốn tạo ListBox thì nên có thêm vd. class clsMyListBox. Class này có vd. trường dulieu, và có phương thức vd. Create, với ít nhất 2 parameter: Owner - chủ nhân của ListBox, và Arr - mảng dữ liệu mà từ đó tạo các dòng cột của ListBox.

Mỗi khi cần tạo ListBox thì tạo đối tượng class clsMyListBox -> gọi phương thức Create của nó. Create sẽ lưu mảng Arr trong trường dulieu, Owner lưu trong vd. OwnerObj và tiếp theo gọi CreateListBox với tham số là mảng dulieu -> CreateListBox duyệt từng dòng của dulieu (tham số) -> với mỗi dòng duyệt từng cột của dulieu -> mỗi lần duyệt từng cột của dulieu trong mỗi lần duyệt dòng thì tạo đối tượng clsCommandButton -> thiết lập Caption của Label bằng giá trị dulieu(r, c) -> định vị Label dựa vào r và c -> những Label được tạo sẽ có Set ctrl = OwnerObj.Controls.Add("Forms.Label.1"). Tùy theo nhu cầu mà truyền Owner = Form hoặc Owner = Frame khi gọi Create. Tóm lại phương thức CreateListBox sẽ tạo UBound(dulieu, 1) hàng Label, mỗi hàng Label có UBound(dulieu, 2) Label, nằm trong Owner, mỗi Label có Caption = dulieu(r, c).

clsCommandButton chỉ để phục vụ mọi cái liên quan tới Label thôi. Tất nhiên đã sinh ra clsMyListBox thì phải sửa clsCommandButton. clsMyListBox thì phục vụ mọi cái liên quan tới ListBox.

Code chính sẽ tạo clsMyListBox và gọi phương thức Create của nó. Create lưu Arr trong trường dulieu và gọi phương thức CreateListBox với tham số dulieu. Chính CreateListBox mới tạo các đối tượng clsCommandButton ...

Lọc có thể như sau: khi bắt đầu thì hủy các Label -> lọc -> kết quả lọc trong mảng vd. dulieu_loc (có thể là 1 trường của clsMyListBox). Nếu dulieu_loc có dữ liệu thì gọi CreateListBox và truyền mảng dulieu_loc để tạo ListBox mới tương ứng với mảng lọc.

Không có chuyện Arr nằm trong Module với tư cách Public. Mảng nằm trong class clsMyListBox và được truyền vào 1 lần ở Create. Nếu có nhu cầu thay đổi mảng cho ListBox trong quá trình hoạt động của ListBox thì tốt nhất tạo thuộc tính read/write ListBox cho clsMyListBox. Set sẽ lưu Arr vào dulieu và gọi CreateListBox với tham số dulieu để tạo mới ListBox. Get thì trả về mảng dulieu. Lúc đó thì sau khi tạo đối tượng clsMyListBox thì dùng SET để thiết lập thuộc tính ListBox của nó.

Đại loại mọi cái là như trên. Mọi dữ liệu nằm gói gọn trong các class, không có chuyện nằm ở ngoài sheet, module.
vâng em cảm ơn ạ, nếu đây là các bước để nó hoạt động thì em nghiêm cứu xem sao. chứ vụ class em mới đụng vô 1 tuần nay, hoàn toàn không có căn bản gì về class hết ạ.
 
Upvote 0
Không có căn bản gì về class thì không nên theo chủ đề này.
Kỹ thuật "wrap đối tượng (theo tiêu đề thớt)" đòi hỏi trình độ tối thiểu là đã biết kha khá về lý thuyết lập trình hướng đối tượng.
 
Upvote 0
Không có căn bản gì về class thì không nên theo chủ đề này.
Kỹ thuật "wrap đối tượng (theo tiêu đề thớt)" đòi hỏi trình độ tối thiểu là đã biết kha khá về lý thuyết lập trình hướng đối tượng.
tới tận bây giờ em vẫn còn gà mờ đa xạ đa hình và tương ứng bội, em học cái này học tới học lui học suôi học ngược mà vẫn không tài nào hiểu rõ
 
Upvote 0
tới tận bây giờ em vẫn còn gà mờ đa xạ đa hình và tương ứng bội, em học cái này học tới học lui học suôi học ngược mà vẫn không tài nào hiểu rõ
Đa xạ (Interface?) là phần nối thêm của HĐT. Người ta thêm vào vì nó giải quyết được một số ngõ bí. Nó không hẳn là căn bản của HĐT.
Đa hình là phần khá khó ứng dụng. Lý thuyết thì dễ, nhưng thực hành cần khá nhiều kinh nghiệm.
Trong HĐT, cần nhất là tập trung vào tính chất đóng gói và tính trừu tượng.

Tính trưu tượng là cái bị hiểu lầm nhiều nhất, và vì hiểu lầm cho nên nó rất ít khi được áp dụng một cách hữu hiệu.
Điểm khó hiểu của tính trừu tượng là do từ "abstraction" dịch ra bị mất một phần ý nghĩa.
Bạn chỉ cần hiểu nó có nghĩa là "không mang hình tượng, thể chất cứng nhắc". Như khi sử dụng thành ngữ "đẹp như tiên"; bạn chỉ cần biết tiên có tính chất "đẹp" thôi. Việc cô tiên ở đâu ra không thành vấn đề.
Ví dụ tôi có lớp HocSinh, với các thuộc tính Toan, Ly, Hoa, Van, và TrungBinh.
Lớp này cho bạn biết rằng các thuộc tính kia sẽ là dạng số thực, và ở trong khoảng 0-10. Như vậy, lúc nạp thì bạn nạp số thực trong khoảng 0-10, và lúc truy xuất thì biết là mình sẽ nhận được số thực 0-10.
Nhưng bên trong, lớp HocSinh không hề hứa là nó sẽ chứa các điểm kia ở dạng gì. Là người thiết kế lớp, tôi có thể chứa nó ở dạng 5 biến. Một ngày đẹp trời, tôi đổi thành chỉ chứa 4 biến, và để cho TrungBinh tính từ 4 cái kia. Một ngày mưa, tôi lại đổi chứa chúng trong array. Một chiều nọ thua đề đậm, tôi đổi kiểu chứa thành dạng chuỗi. Là người sử dụng lớp, bạn không cần biết tôi thích mưa hay nắng, mê đề hay cá độ. Đối với bên ngoài, HocSinh luôn có 5 thuộc tính kiểu số thực 0-10; 4 có thể thay đổi được và 1 là trung bình của 4 cái kia.
Cái hay của "trừu tượng" là vậy. Nó cho phép bên thiết kế thay đổi thiết kế mà bên sủ dụng không cần biết tới.
 
Upvote 0
Đa hình là phần khá khó ứng dụng. Lý thuyết thì dễ, nhưng thực hành cần khá nhiều kinh nghiệm.
Có vẻ ông chú có định kiến với lập trình hướng đối tượng (OOP) nên thường nhìn tiêu cực cái hay của OOP. Theo tôi thì đa hình lại là cái vô cùng dễ ứng dụng và cho nhiều cảm hứng nhất khi làm việc trong lập trình hướng đối tượng vì nó tạo ra sự tương đồng với tư duy ngôn ngữ con người. Sự tương đồng ở đây chính là ý nghĩa của lệnh theo ngữ cảnh.

Trong ngôn ngữ con người, tùy theo ngữ cảch, từ "chạy" sẽ mang ý nghĩa là chuyển động cơ thể bằng chân, hoặc chuyển động của một cái xe. hay hoạt động của một cỗ máy... Với đa hình trong OOP, cùng một function, tùy vào dữ liệu đầu vào mà nó sẽ có những bước tính toán, thực thi tương ứng.

Chẳng hạn tôi lập function tính diện tích tam giác theo 2 cách:
  1. Theo chiều cao và cạnh đáy (2 tham số)
  2. Theo độ dài 3 cạnh (3 tham số)
Lập trình kiểu cũ, tôi sẽ phải nhớ đến 2 hàm tính riêng rẽ. Nhưng với tính đa hình của OOP thì tôi chỉ cần nhớ tới duy nhất một hàm tính diện tích và cái hàm ấy vô cùng ăn ý khi dựa vào dữ liệu đầu vào (dùng 2 hay 3 tham số) để tính sao cho phù hợp.
 
Lần chỉnh sửa cuối:
Upvote 0
...

Chẳng hạn tôi lập function tính diện tích tam giác theo 2 cách:
  1. Theo chiều cao và cạnh đáy (2 tham số)
  2. Theo độ dài 3 cạnh (3 tham số)
Lập trình kiểu cũ, tôi sẽ phải nhớ đến 2 hàm tính riêng rẽ. Nhưng với tính đa hình của OOP thì tôi chỉ cần nhớ tới duy nhất một hàm tính diện tích và cái hàm ấy vô cùng ăn ý khi dựa vào dữ liệu đầu vào (dùng 2 hay 3 tham số) để tính sao cho phù hợp.
Đó là hàm. Liên quan gì đến đối tượng của tôi?

Nếu tôi có lớp gì đó thể hiện được tam giác. Thì chưa chắc tôi đã cần biết nó có mấy hàm, bao nhiêu răng.
Rất có thể người thiết kế lớp này có một thuộc tính DienTich. Tôi chỉ cần truy vấn thuộc tính ấy. Chuyện nó dùng hàm gì để tính không phải là nơi tôi quan tâm.

Hay bạn muốn nói phương thức lớp (Static)?
Tôi không gọi tính chất hàm chồng là đa hình.
Đa hình đối với tôi tối thiểu phải là loại lớp đa giác. Đối tượng có thể là tam giác, tứ giác,... Và tuỳ theo nó là cái gì mà nó tự có cách tính diện tích khác nhau. (đây là mới nói hình học phẳng thôi)
 
Upvote 0
Đó là hàm. Liên quan gì đến đối tượng của tôi?
...
Hay bạn muốn nói phương thức lớp (Static)?
Tôi không gọi tính chất hàm chồng là đa hình.
Trước tiên cần nhắc lại là tôi chỉ đề cập về "Tính đa hình" cái mà được VetMini cho là "phần khá khó ứng dụng" chứ tôi chả lạm bàn về các vấn đề kỹ thuật khác trong OOP vì điều này ngoài khả năng của tôi.

Để tránh phán bậy về OOP do đọc đã quá lâu, tôi đã phải search "tính đa hình" để bảo đảm là những thông tin tôi nói ở đây là đủ tin cậy. Tôi xin dẫn một đoạn tài liệu về khái niệm "tính đa hình" để mọi người có thể đối chiếu với ý niệm cũng như minh họa của tôi ở # trên:
From Google đã viết:
Trong tiếng Hy Lạp, thuật ngữ “polymorphism” mang ý nghĩa là “có nhiều dạng”. Tương tự, trong lập trình thuật ngữ này dùng để ám chỉ đến việc một biến, một hàm hoặc một phương thức có thể tồn tại ở nhiều dạng khác nhau. Tức là nhiều hàm hoặc phương thức có thể cùng một tên nhưng chức năng thực sự của chúng lại khác nhau.
Không biết là khái niệm về "tính đa hình" nầy có khác những gì mà chú VetMini vẫn đinh ninh lâu nay không?
 
Lần chỉnh sửa cuối:
Upvote 0
Đa hình đối với tôi tối thiểu phải là loại lớp đa giác. Đối tượng có thể là tam giác, tứ giác,... Và tuỳ theo nó là cái gì mà nó tự có cách tính diện tích khác nhau. (đây là mới nói hình học phẳng thôi)
dạ theo hiểu biết tạm tạm của em thì ý của em cũng giống như của thầy. Em có xem các clip này thầy Khang cũng giảng giống như ý thầy. mà do em còn gà mờ quá nên học hoài vẫn chưa thông nên phải làm trâu gặm nhắm từ từ
Liên kết: https://www.youtube.com/watch?v=pDY8rREVJ6s&list=PLjzaUXKQiFUTUjmu0Z8Sp2-gf0hzIxXbZ&index=28
 
Upvote 0
dạ theo hiểu biết tạm tạm của em thì ý của em cũng giống như của thầy. Em có xem các clip này thầy Khang cũng giảng giống như ý thầy. mà do em còn gà mờ quá nên học hoài vẫn chưa thông nên phải làm trâu gặm nhắm từ từ
...
Cha nội TS này nói tiếng Anh khá dở mà lúc nói bày đặt ô kê, ô kiếc tùm lum.
Người Việt có tật hay chêm tiếng ngoại vào câu nói mà nhiều lúc không biết rằng những tiếng ấy là cách dùng của dân đầu trâu mặt ngựa.

poly = nhiều
morph = cách trình bày tắt của metamorphosis = thay đổi hình dạng
ism = tiếp vỹ ngữ dùng để chỉ phương cách, đường lối, chính sách,...
Như vậy polymorphism dịch là đa hình đủ rồi. Mấy cha nội bày đặt đa xạ, tương ứng bội,... càng làm rối rắm.
Cũng như "trừu tượng" tôi nêu ra trước đây, có dịch hơi trệch chút cũng chả chết ai, cái quan trọng là "biết nó như vậy". Chiếc xe hơi ai cũng biết nó là xe hơi - cần gì phải chứng mình nó "hơi" ở đâu.

Bạn thấy khó hiểu bởi vì cái cơ líp trên dùng ví dụ trong C++. Trong các ngôn ngữ HĐT thì C++ là khó sử dụng nhất. Chọn cái khó để dạy cái khó hiểu thì chết học sinh. Vậy thôi.
(ngày xưa, chỉ để hiểu lớp ảo và bảng ảo tôi đã phải điên đầu với nó)

Bạn học cách áp dụng đa hình của các ngôn ngữ cận đại hơn (như Python) sẽ thấy dễ hiểu hơn nhiều.
 
Upvote 0
Bạn học cách áp dụng đa hình của các ngôn ngữ cận đại hơn (như Python) sẽ thấy dễ hiểu hơn nhiều.
Cận đại chắc là gần như hiện đại chăng ? Vậy có ngôn ngữ nào hiện đại hẳn hoi luôn không anh, để em dễ hiểu hơn nữa ạ ?
 
Upvote 0
Cận đại chắc là gần như hiện đại chăng ? Vậy có ngôn ngữ nào hiện đại hẳn hoi luôn không anh, để em dễ hiểu hơn nữa ạ ?
Hiện đại là up-to-date. Cận đại là recent. Muốn diễn đạt thằng nào thì diễn.

Trong ngữ cảnh của ngôn ngữ thì cận đại có nghĩa là trẻ hơn (more recent/modern), hiện đại có nghĩa gần như đang được hâm mộ (curently in favour).
 
Upvote 0
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 hay "bao" một đối tượng.
Có 2 lý do sau buộc bạn phải viết 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).

Xem file đính kèm dưới đây các bạn sẽ hiểu thêm ý nghĩa của nó.

(Để học cách viết code trong Class module, các bạn hãy tìm các bài viết đã có trên diễn đàn này hoặc tìm đọc tài liệu lập trình Class trong VB/VBA trên mạng)
e chào anh, e đã đọc được tính ưu việt mà class module có thể mang lại, nhưng trên mạng tài liệu về class module cho VBA khó kiếm quá,
anh có thể chia sẻ cho em tài liệu này được không ah, (email của e là nguyenxuanvung@gmail.com)
 
Upvote 0
Tiếp tục đào lại "tính đa hình" trong OOP thì tôi thấy có nguồn tài liệu phân chia nó thành 2 loại:

[1] Compile time Polymorphism. sử dụng bằng cách nạp chồng hàm hoặc nạp chồng toán tử.
Đây chính là "tính đa hình" mà tôi đã đề cập tới và có tính ứng dụng rất cao nhưng lại được chú VetMini chê bai . Rất nhiều các hàm trong .NET, Java và MQL4 chấp nhận các hình thức truyền tham số khác nhau cho cùng một hàm. Nó rất hữu ích vì coder sẽ không cần phải nhớ quá nhiều tên hàm. Với một tên hàm, chỉ cần gõ cái dấu mở ngoặc tròn thì sẽ có nhiều gợi ý truyền tham số để ta thoải mái lựa chọn thích hợp với dữ liệu đang có. Viết các dạng hàm, toán tử loại này cũng tương tự như viết các hàm thông thường chứ không có gì phức tạp hơn.​
[2] Runtime Polymorphism. nẩy sinh khi tạo ra một lớp kế thừa (?).
Có lẽ chú VetMini bị đóng đinh vào cái "đa hình"này nên quên luôn "tính đa hình" lý thú ở trên tuy nhiên cũng phải nói là nó không đến nỗi khó hiểu. Đúng là loại đa hình này ít có ứng dụng với khi viết app vừa vừa, thông thường.​
 
Upvote 0
e chào anh, e đã đọc được tính ưu việt mà class module có thể mang lại, nhưng trên mạng tài liệu về class module cho VBA khó kiếm quá,
anh có thể chia sẻ cho em tài liệu này được không ah, (email của e là nguyenxuanvung@gmail.com)

Bạn tải các ví dụ tôi gửi ở các bài trên cùng, với từ khoá “class in VB6” bạn chịu tìm trên Google để tự học thêm nhé.
 
Lần chỉnh sửa cuối:
Upvote 0

Bài viết mới nhất

Back
Top Bottom