Dùng Class Module để tạo sự kiện người dùng

Liên hệ QC

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,906
Tôi đang trong những bước đầu tiên nghiên cứu về Class Module nên sẽ viết theo sự hiểu biết của tôi. Nếu có sai sót, mong các cao thủ bổ sung thêm
Mục đích của bài viết này là:
- Tạo sự kiện người dùng khi mà các sự kiện cung cấp sẳn không đáp ứng được nhu cầu
- Khi mà chúng ta có nhu cầu "thu gom" tất cả các code của 1 số object (có cùng chức năng) về chung thành 1 code
------------------------------------------------------------------------------------------------
Giả định tình huống thế này:
- Tôi có 1 Workbook bao gồm 9 sheet, trong đó có 1 sheet Menu và 8 sheet con
- Tại sheet Menu, tôi vẽ 8 CommandButton để link đến 8 sheet con
- Tại các sheet con, mỗi sheet tôi vẽ 1 CommandButton để link đến sheet Menu
Thông thường bài toán này người ta sẽ viết cho mỗi CommandButton 1 đoạn code riêng lẻ. Như vậy, nếu số lượng object càng nhiều thì code của chúng ta sẽ trở nên dài dòng
Đàng nào thì các đoạn code ấy cũng có chung 1 mục đích... Vậy liệu có cách nào gom toàn bộ chúng thành 1 code duy nhất hay không? Câu trả lời là: Hoàn toàn có thể nếu biết dùng đến Class Module
Chúng ta cùng tiến hành giải pháp nhé
- Cứ cho rằng toàn bộ các CommandButton đã được vẽ xong
- Chuỗi mà ta gõ trên Caption của CommandButton chính là tên của sheet cần link
Vậy code của chúng ta sẽ bao gồm 2 phần
1> Trong Class Module
Hãy chèn 1 Class Module và nhớ đặt tên cho nó (trong file tôi đặt tên là MyClass) rồi đặt vào nó đoạn code này:
PHP:
Public WithEvents CB As CommandButton
Private Sub CB_Click()
  On Error Resume Next
  Sheets(CB.Caption).Select
End Sub
2> Trong Module
Chèn 1 Module và đặt vào nó đoạn code này:
PHP:
Public Button() As New MyClass
Sub Auto_Open()
  Dim i As Long, Obj As OLEObject, Ws As Worksheet
  For Each Ws In ThisWorkbook.Worksheets
    For Each Obj In Ws.OLEObjects
      If InStr(Obj.progID, "Forms.CommandButton") Then
        ReDim Preserve Button(i)
        Set Button(i).CB = Obj.Object
        i = i + 1
      End If
    Next Obj
  Next Ws
End Sub
Vậy là xong! Hãy chạy Auto_Open rồi nhấn nút thử
Nếu có ý định cho hiện 1 sheet duy nhất, các sheet khác ẩn thì sửa lại code trong Class Module như sau:
PHP:
Public WithEvents CB As CommandButton
Private Sub CB_Click()
  Dim Sh As Worksheet
  On Error Resume Next
  Application.ScreenUpdating = False
  Set Sh = ActiveSheet
  Sheets(CB.Caption).Visible = True
  Sheets(CB.Caption).Select
  Sh.Visible = 2
  Application.ScreenUpdating = True
End Sub
Cũng chạy Auto_Open và thử bấm các nút
Điểm mấu chốt mà ta cần ghi nhớ trong toàn bộ code chỉ có 2 đoạn:
Public WithEvents CB As CommandButton (Khai báo)

Set Button(i).CB = Obj.Object (thiết lập để chúng "bắt tay" nhau)
Không có chúng thì toàn bộ sẽ "tan rã"
------------------------------------------------------------------------------------------------
Tóm lại công việc của chúng ta chỉ là:
- Đặt 2 đoạn code vào đúng vị trí
- Đặt tên cho Class Module
- Vẽ các CommandButton và gõ tên sheet cần link vào caption của chúng
- Chạy Auto_Open để khởi động việc "thu gom"
Điểm thú vị ở đây là:
- Chỉ có các CommandButton (thuộc ActiveX Control) mới bị ảnh hưởng bởi code này (các object khác hoàn toàn không bị ảnh hưởng)
- Với các CommandButton, chỉ cái nào có caption là tên sheet mới bị ảnh hưởng bởi code này
------------------------------------------------------------------------------------------------
Xin lưu ý với các bạn rằng:
- Việc dùng CommandButton để link với các sheet không phải là mục đích chính của bài viết này (chỉ lấy ví dụ để minh họa), vì thế mà tôi đã không đặt nó vào chung với topic: Tạo nút nhấn để link đến các sheet
- Mục đích chính của bài viết này là hướng dẩn cách dùng Class Module để tự tạo 1 sự kiện người dùng
- Code này chỉ thuộc dạng cơ bản, có thể tùy biến đề áp dụng cho rất nhiều bài toán khác
------------------------------------------------------------------------------------------------
Chỉ với 1 bài viết thì chưa đủ để nói về EventClass, vậy nên rất mong các cao thủ khác cùng góp sức hoàn thiện bài viết này
 

File đính kèm

  • CmdEventClass_1.xls
    84 KB · Đọc: 575
  • CmdEventClass_2.xls
    86.5 KB · Đọc: 468
Bạn hơi bị lạ đời đấy! File bạn làm bị lỗi, thì bạn post cái file đó lên để người ta xem nó bị lỗi gì, tôi có làm cái file nào đâu mà bạn bảo tôi up file lên?

Cái file bạn up trả lại file cho mình học tập ấy thật mà!!! Mình mày mò cả tối nay đấy. đúng là ban đầu không vấn đề gì nhưng khi cần sửa số số lượng button và sheet là chết luôn. bạn thử dowload lại bài #53 và thử sóa đi 1 button !!!
 
Upvote 0
Khi chạy code của HOANG TRONG NGHIA không áp dụng được trong quá trình sửa chữa nhưng code của anh thì rất thuận lợi cho sửa chữa theo nhu cầu sử dụng ạ

Tôi hỏi bạn một câu nha, bạn có biết đặt NAME cho CommandButton không vậy? Với các câu hỏi của bạn, tôi hồ nghi bạn chẳng biết đặt tên chúng như thế nào nữa đấy!
 
Upvote 0
Tôi hỏi bạn một câu nha, bạn có biết đặt NAME cho CommandButton không vậy? Với các câu hỏi của bạn, tôi hồ nghi bạn chẳng biết đặt tên chúng như thế nào nữa đấy!

Bài này đặt tên commanbutton thi vào properties thay đổi tên ở dòng đầu name
còn đặt tên nhãn là dòng caption cũng trong properties không thì sửa trực tiếp trên commandbutton.
Thật mà bạn thử sem đi. Nếu code của bạn làm xong là cố dịnh không sửa số sheet, số button nữa thì không sao nhưng vì công việc phải thay đổi rất là khó. Có thể mình chưa biết cách sử lý tình hướng đó!!
 
Upvote 0
Bài này đặt tên commanbutton thi vào properties thay đổi tên ở dòng đầu name
còn đặt tên nhãn là dòng caption cũng trong properties không thì sửa trực tiếp trên commandbutton.
Thật mà bạn thử sem đi. Nếu code của bạn làm xong là cố dịnh không sửa số sheet, số button nữa thì không sao nhưng vì công việc phải thay đổi rất là khó. Có thể mình chưa biết cách sử lý tình hướng đó!!

Tôi lại nghĩ bạn sửa tên SHEET thì phải!

Tên sheet có 2 loại tên:

(1) Sheet Name là tên sheet mà ta có thể sửa trực tiếp trên sheet tab

(2) Sheet CodeName là tên mà ta chỉ sửa được trong properties của sheet

Liên quan đến bài tôi gửi lên cho bạn, tôi đang chọn kiểu (1) để select.

Bạn lưu ý cho vấn đề khai báo biến này:

Private MyCmdBttn(1 To 3) As New EventClass

Nếu bạn đặt 10 cái nút lệnh có tên CmdBttn1 đến CmdBttn10 thì bạn phải khai như sau:

Private MyCmdBttn(1 To 10) As New EventClass

Và vòng lặp For i =
1 To 10

------------------------------------------------------------------------------------

NẾU BẠN VẪN KHÔNG THỂ THỰC HIỆN ĐƯỢC, CỨ GỬI CÁI FILE LỖI ĐÓ LÊN, TÔI SẼ CHỈ CHO BẠN CHỖ BẠN LÀM CHƯA ĐÚNG.
 
Lần chỉnh sửa cuối:
Upvote 0
Tôi lại nghĩ bạn sửa tên SHEET thì phải!

Tên sheet có 2 loại tên:

(1) Sheet Name là tên sheet mà ta có thể sửa trực tiếp trên sheet tab

(2) Sheet CodeName là tên mà ta chỉ sửa được trong properties của sheet

Liên quan đến bài tôi gửi lên cho bạn, tôi đang chọn kiểu (1) để select.

Bạn lưu ý cho vấn đề khai báo biến này:

Private MyCmdBttn(1 To 3) As New EventClass

Nếu bạn đặt 10 cái nút lệnh có tên CmdBttn1 đến CmdBttn10 thì bạn phải khai như sau:

Private MyCmdBttn(1 To 10) As New EventClass

Và vòng lặp For i =
1 To 10

------------------------------------------------------------------------------------

NẾU BẠN VẪN KHÔNG THỂ THỰC HIỆN ĐƯỢC, CỨ GỬI CÁI FILE LỖI ĐÓ LÊN, TÔI SẼ CHỈ CHO BẠN CHỖ BẠN LÀM CHƯA ĐÚNG.

Ai biểu SET "Cứng ngắt" làm chi cho người ta không tùy biến được
Mà dân mới học, đừng nói là Class, ngay cả 1 code bình thường nhất cũng chắc gì đã biết đường mà lần
Tôi thì khác: Tác giả chưa cần nói đến vụ đổi caption tôi cũng đã lường trước vụ này (thậm chí lường trước luôn vụ sheet ẩn) ---> Bấm vào không thấy sheet thì.. im re
Và cuối cùng, cái tôi chưa thể nghĩ ra để lường trước thì... On Error Resume Next
 
Upvote 0
Ai biểu SET "Cứng ngắt" làm chi cho người ta không tùy biến được
Mà dân mới học, đừng nói là Class, ngay cả 1 code bình thường nhất cũng chắc gì đã biết đường mà lần
Tôi thì khác: Tác giả chưa cần nói đến vụ đổi caption tôi cũng đã lường trước vụ này (thậm chí lường trước luôn vụ sheet ẩn) ---> Bấm vào không thấy sheet thì.. im re
Và cuối cùng, cái tôi chưa thể nghĩ ra để lường trước thì... On Error Resume Next

Theo thiển ý của em, người học code trước hết phải có tư duy, từ tư duy dẫn đến có logic. Không biết thì hỏi, muốn giỏi phải học, bản thân em luôn xem tất cả các giải của rất nhiều Thầy cho một trường hợp, từ đó nghiền ngẫm, mày mò cho đến khi chúng là kiến thức của mình; rồi từ đó phân biệt được giải pháp nào hữu hiệu, giải pháp nào đơn giản, giải pháp nào dài dòng v.v...

Với code của Thầy, nếu chọn sheet không thôi thì không nói làm gì, thêm vài nút lệnh có chức năng khác như show thêm vài cái form, rồi nút thoát, rồi X nút v.v... Thì thằng em nó điếc luôn. Thử hỏi cách của em vừa gọn vừa chuẩn (có bao nhiêu nút ta duyệt đúng bấy nhiêu nút) chứ đâu thể vơ hết các nút lệnh trên form chỉ thực hiện việc chọn sheet đâu? Nếu tác giả muốn thì cứ thử xem, thêm 1 nút lệnh làm chức năng gì đó mà khác với việc chọn sheet thì sẽ phát sinh lỗi hoặc code chồng code hay không biết liền chứ gì!
 
Lần chỉnh sửa cuối:
Upvote 0
Với code của Thầy, nếu chọn sheet không thôi thì không nói làm gì, thêm vài nút lệnh có chức năng khác như show thêm vài cái form, rồi nút thoát, rồi X nút v.v... Thì thằng em nó điếc luôn.

Tầm bậy tầm bạ không?
Nếu có nút khác, với công năng khác thì ai dại gì để chung 1 đống trên UserForm chứ ---> Tôi sẽ cho những nút cùng tính năng vào 1 Frame ---> Vây thì mấy nút show, nút X gì gì đó mắc mớ gì đến class của tôi
Nghĩa chưa xem bài này sao:
http://www.giaiphapexcel.com/forum/...để-tạo-sự-kiện-người-dùng&p=259558#post259558
Cũng quá trời control đấy nhưng có chạy bậy đâu
 
Lần chỉnh sửa cuối:
Upvote 0
Em đã làm theo mà không biết sai cái gì nhấn hoài nó không ra ai chỉ giúp em. Cám ơn nhiều nhiều ạ.
 

File đính kèm

  • Book4.xls
    48.5 KB · Đọc: 24
Upvote 0
Em vận dụng class mục đích là sau khi thoát khỏi Textbox thì textbox sẽ định dạng về dạng số. Nhưng em làm hoài không ra, không biết có sai chỗ nào không ?, mong Anh( Chị ) xem qua và hướng dẫn giúp e ,Em xin cám ơn !

Code e trong Class1
Mã:
Public WithEvents Txt As MSForms.TextBox
Private Sub Txt_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    Txt.Value = Format(Txt.Value, "#,###.000")
End Sub

Code e để trong Form
Mã:
Dim DKien() As New Class1
Private Sub UserForm_Initialize()
 Dim Ctrl As Control, i
  For Each Ctrl In Me.Controls
    If TypeOf Ctrl Is MSForms.TextBox Then
      ReDim Preserve DKien(i)
      Set DKien(i).Txt = Ctrl
      i = i + 1
    End If
  Next
End Sub
 
Upvote 0
Em vận dụng class mục đích là sau khi thoát khỏi Textbox thì textbox sẽ định dạng về dạng số. Nhưng em làm hoài không ra, không biết có sai chỗ nào không ?, mong Anh( Chị ) xem qua và hướng dẫn giúp e ,Em xin cám ơn !

Code e trong Class1
Mã:
Public WithEvents Txt As MSForms.TextBox
Private Sub Txt_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    Txt.Value = Format(Txt.Value, "#,###.000")
End Sub

Code e để trong Form
Mã:
Dim DKien() As New Class1
Private Sub UserForm_Initialize()
 Dim Ctrl As Control, i
  For Each Ctrl In Me.Controls
    If TypeOf Ctrl Is MSForms.TextBox Then
      ReDim Preserve DKien(i)
      Set DKien(i).Txt = Ctrl
      i = i + 1
    End If
  Next
End Sub
Làm gì có sự kiện Txt_Exit đâu mà chạy hả bạn?
Chỉ có bi nhiêu đây sự kiện thôi (trong khung màu đỏ ấy)

Untitled.jpg

















Vậy bạn muốn sự kiện nào?
 
Upvote 0
Dạ, em cám ơn Thầy. E cũng mới tìm hiểu là nó không có sự kiện này. Để em vận dụng sự kiện khác xem sao !
 
Upvote 0
Ndu à, cái Topic này có từ lâu rồi nên cũng không mấy ai để ý cái tiêu đề. Nhưng nội dung và tiêu đề có chút sai khác:

-Tạo sự kiện người dùng (User Event) là Event do người dùng tạo ra chứ không phải là các Event đã được thiết lập. Trên 1 số Page có ví dụ tạo sự kiên Combobox_ItemAdd chẳng hạn để kiểm tra nếu chưa có trong Combobox.Item mới Add. Người dùng sẽ thiết lập cơ chế để Raise Event hoặc nhờ vào event khác để phát sinh sự kiện.

-Ở đây là dùng Class Module để quản lý sự kiện của hàng loạt các Control đồng loại.

Vậy Ndu liên hệ xem xét điều chỉnh cho phù hợp vì Topic này sẽ còn được tìm đến lâu dài
 
Lần chỉnh sửa cuối:
Upvote 0
Chào anh chị
Em có 1 class module có tên BC_tonghop và em muốn chèn vào sheet1 trên VBA thì code viết như thế nào nhờ anh chị hỗ trơ.
Em đang tập viết bằng VBA nên chưa rành
Em cám ơn
 

File đính kèm

  • hinh minh   hoa.jpg
    hinh minh hoa.jpg
    61.1 KB · Đọc: 27
Upvote 0
Tôi đang trong những bước đầu tiên nghiên cứu về Class Module nên sẽ viết theo sự hiểu biết của tôi. Nếu có sai sót, mong các cao thủ bổ sung thêm
Mục đích của bài viết này là:
- Tạo sự kiện người dùng khi mà các sự kiện cung cấp sẳn không đáp ứng được nhu cầu
- Khi mà chúng ta có nhu cầu "thu gom" tất cả các code của 1 số object (có cùng chức năng) về chung thành 1 code

------------------------------------------------------------------------------------------------
Giả định tình huống thế này:
- Tôi có 1 Workbook bao gồm 9 sheet, trong đó có 1 sheet Menu và 8 sheet con
- Tại sheet Menu, tôi vẽ 8 CommandButton để link đến 8 sheet con
- Tại các sheet con, mỗi sheet tôi vẽ 1 CommandButton để link đến sheet Menu
Thông thường bài toán này người ta sẽ viết cho mỗi CommandButton 1 đoạn code riêng lẻ. Như vậy, nếu số lượng object càng nhiều thì code của chúng ta sẽ trở nên dài dòng
Đàng nào thì các đoạn code ấy cũng có chung 1 mục đích... Vậy liệu có cách nào gom toàn bộ chúng thành 1 code duy nhất hay không? Câu trả lời là: Hoàn toàn có thể nếu biết dùng đến Class Module
Chúng ta cùng tiến hành giải pháp nhé
- Cứ cho rằng toàn bộ các CommandButton đã được vẽ xong
- Chuỗi mà ta gõ trên Caption của CommandButton chính là tên của sheet cần link
Vậy code của chúng ta sẽ bao gồm 2 phần
1> Trong Class Module
Hãy chèn 1 Class Module và nhớ đặt tên cho nó (trong file tôi đặt tên là MyClass) rồi đặt vào nó đoạn code này:
PHP:
Public WithEvents CB As CommandButton
Private Sub CB_Click()
  On Error Resume Next
  Sheets(CB.Caption).Select
End Sub
2> Trong Module
Chèn 1 Module và đặt vào nó đoạn code này:
PHP:
Public Button() As New MyClass
Sub Auto_Open()
  Dim i As Long, Obj As OLEObject, Ws As Worksheet
  For Each Ws In ThisWorkbook.Worksheets
    For Each Obj In Ws.OLEObjects
      If InStr(Obj.progID, "Forms.CommandButton") Then
        ReDim Preserve Button(i)
        Set Button(i).CB = Obj.Object
        i = i + 1
      End If
    Next Obj
  Next Ws
End Sub
Vậy là xong! Hãy chạy Auto_Open rồi nhấn nút thử
Nếu có ý định cho hiện 1 sheet duy nhất, các sheet khác ẩn thì sửa lại code trong Class Module như sau:
PHP:
Public WithEvents CB As CommandButton
Private Sub CB_Click()
  Dim Sh As Worksheet
  On Error Resume Next
  Application.ScreenUpdating = False
  Set Sh = ActiveSheet
  Sheets(CB.Caption).Visible = True
  Sheets(CB.Caption).Select
  Sh.Visible = 2
  Application.ScreenUpdating = True
End Sub
Cũng chạy Auto_Open và thử bấm các nút
Điểm mấu chốt mà ta cần ghi nhớ trong toàn bộ code chỉ có 2 đoạn:
Public WithEvents CB As CommandButton (Khai báo)

Set Button(i).CB = Obj.Object (thiết lập để chúng "bắt tay" nhau)
Không có chúng thì toàn bộ sẽ "tan rã"
------------------------------------------------------------------------------------------------
Tóm lại công việc của chúng ta chỉ là:
- Đặt 2 đoạn code vào đúng vị trí
- Đặt tên cho Class Module
- Vẽ các CommandButton và gõ tên sheet cần link vào caption của chúng
- Chạy Auto_Open để khởi động việc "thu gom"
Điểm thú vị ở đây là:
- Chỉ có các CommandButton (thuộc ActiveX Control) mới bị ảnh hưởng bởi code này (các object khác hoàn toàn không bị ảnh hưởng)
- Với các CommandButton, chỉ cái nào có caption là tên sheet mới bị ảnh hưởng bởi code này
------------------------------------------------------------------------------------------------
Xin lưu ý với các bạn rằng:
- Việc dùng CommandButton để link với các sheet không phải là mục đích chính của bài viết này (chỉ lấy ví dụ để minh họa), vì thế mà tôi đã không đặt nó vào chung với topic: Tạo nút nhấn để link đến các sheet
- Mục đích chính của bài viết này là hướng dẩn cách dùng Class Module để tự tạo 1 sự kiện người dùng
- Code này chỉ thuộc dạng cơ bản, có thể tùy biến đề áp dụng cho rất nhiều bài toán khác

------------------------------------------------------------------------------------------------
Chỉ với 1 bài viết thì chưa đủ để nói về EventClass, vậy nên rất mong các cao thủ khác cùng góp sức hoàn thiện bài viết này
Anh ơi cho e hỏi "OLEObject " là gì ạ.. nó khác gì với object ạ? và khi nào thì dùng nó ạ?
 
Upvote 0
Bạn xem lại đi! Nó hoạt động đâu có giống cái tôi đã gữi!
Ý tôi không phải bảo bạn giải quyết bài toán này (vì có nhiều cách) mà muốn nhấn mạnh với bạn rằng: "Trong 1 số trường hợp cụ thể nào đó, nếu không dùng Class thì sẽ tự mình gây khó khăn cho mình... Trong khi với Class, ta giải quyết nhanh gọn"
Với bài này, nếu không dùng Class mà bạn làm được y chang như file tôi gữi thì.... Hi... hi...
------------------------------------
Nhắc lại: Các bạn hãy xem bài số #5 như là 1 bài tập và hãy giải quyết nó bằng cách dùng Class Module nhé
cho e hỏi là tìm " bài số #5 " như thế nào ạ.. e bấm vào phần seach mà ko tìm được :)
 
Upvote 0
Web KT
Back
Top Bottom