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

Liên hệ QC

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

anhtuan1066

Thành viên gạo cội
Tham gia
10/3/07
Bài viết
5,802
Được thích
6,912
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

Về kỹ thuật lập trình Class các thành viên cần hiểu tốt về đối tượng. Khởi tạo, Các thành phần, Giải phóng khỏi vùng nhớ....

Bài viết cũng như ví dụ của anh Tuấn thiếu một thủ tục rất quan trọng đó là giải phóng biến đối tượng khỏi vùng nhớ. Việc này sẽ dẫn tới Windows bị chiếm dụng vùng nhớ. Anh nên bổ sung vào bài viết và vào ví dụ không thì những thành viên mới học sẽ hiểu và làm sai dẫn tới ứng dụng sau này project của họ có thể "phá sản".

Các thành viên có thể tham khảo thêm bài viết và các ví dụ trong đường dẫn dưới đây:
http://www.giaiphapexcel.com/forum/showthread.php?3868-Class-module-Kỹ-thuật-Tạo-và-Wrap-đối-lượng

Một chút góp ý với mong muốn tất cả các thành viên cùng học để nâng cao kiến thức lập trình trong Excel.
(Hình như anh không đọc những bài em đã viết về Class).
 
Lần chỉnh sửa cuối:
Upvote 0
Về kỹ thuật lập trình Class các thành viên cần hiểu tốt về đối tượng. Khởi tạo, Các thành phần, Giải phóng khỏi vùng nhớ....

Bài viết cũng như ví dụ của anh Tuấn thiếu một thủ tục rất quan trọng đó là giải phóng biến đối tượng khỏi vùng nhớ. Việc này sẽ dẫn tới Windows bị chiếm dụng vùng nhớ. Anh nên bổ sung vào bài viết và vào ví dụ không thì những thành viên mới học sẽ hiểu và làm sai dẫn tới ứng dụng sau này project của họ có thể "phá sản".

Các thành viên có thể tham khảo bài viết và các ví dụ trong đường dẫn dưới đây:
http://www.giaiphapexcel.com/forum/showthread.php?3868-Class-module-K%E1%BB%B9-thu%E1%BA%ADt-T%E1%BA%A1o-v%C3%A0-Wrap-%C4%91%E1%BB%91i-l%C6%B0%E1%BB%A3ng
(Hình như anh không đọc những bài em đã viết về Class).

Vâng! Bởi vậy tôi rất muốn các cao thủ như bạn bổ sung thêm
Có điều nên viết ở mức đơn giản nhất để "tầm thấp" như tôi có thể hiểu và áp dụng được... Có hiểu được bước đầu thì mới có khả năng tự mình tùy biến như ý muốn, đúng không?
Nói ra bạn đừng cười, chứ bài viết của bạn cho trong link trên tôi cũng từng đọc qua mà... hỏng hiểu tí nào (cũng có thể vì tôi chưa từng được đào tạo qua các trường lớp chính quy)
Hi... Hi...
------------------------
Chân thành cảm ơn sự góp ý của bạn và cũng rất mong nhận được những bài viết "ngon, bổ" nhưng "rẻ" từ bạn và các cao thủ khác
------------------------
Mình hỏi thêm: Với code trên, ta phải sửa hoặc thêm gì vào thì mới hợp lý (giải phóng đối tượng khỏi vùng nhớ như thế nào?)
 
Lần chỉnh sửa cuối:
Upvote 0
Vâng! Bởi vậy tôi rất muốn các cao thủ như bạn bổ sung thêm
Có điều nên viết ở mức đơn giản nhất để "tầm thấp" như tôi có thể hiểu và áp dụng được... Có hiểu được bước đầu thì mới có khả năng tự mình tùy biến như ý muốn, đúng không?
Nói ra bạn đừng cười, chứ bài viết của bạn cho trong link trên tôi cũng từng đọc qua mà... hỏng hiểu tí nào (cũng có thể vì tôi chưa từng được đào tạo qua các trường lớp chính quy)
Hi... Hi...
------------------------
Chân thành cảm ơn sự góp ý của bạn và cũng rất mong nhận được những bài viết "ngon, bổ" nhưng "rẻ" từ bạn và các cao thủ khác
------------------------
Mình hỏi thêm: Với code trên, ta phải sửa hoặc thêm gì vào thì mới hợp lý (giải phóng đối tượng khỏi vùng nhớ như thế nào?)

Vì biết anh là "người truyền giáo" rất tốt nên cũng hy vọng anh giúp được rất nhiều thành viên GPE. Đúng là bài viết của em trong link trên mang tính giới thiệu như là "có một thứ như thế", anh có thể để ý về tạo và giải phóng đối tượng, dù là cơ bản nhưng cái đó không thể bỏ được anh ạ. Hy vọng bài viết này giúp ích cho nhiều người.
 
Upvote 0
1 bài tập

Gữi các bạn 1 bài tập nghiên cứu chơi
- Trên bảng tính, tôi có vài ComboBox và 1 SpinButton
- Các ComboBox này chuyên dùng để nhập các số nguyên(Number)
- Khi tôi đặt con trỏ chuột vào 1 ComboBox nào đó rồi bấm SpinButton thì giá trị trong ComboBox sẽ tăng hoặc giảm 1 đơn vị (tùy theo ta bấm SpinButton theo chiều nào)


untitled.JPG

------------------------------------
Xem như là 1 bài tập thực hành về Class Event, các bạn hãy nghiên cứu xem
 

File đính kèm

Upvote 0
Em có 1 điều này nói ra hơi khó nghe nhưng không nói thì hơi ấm ức.
Đồng ý là Class làm việc này rất tốt nhưng chưa đúng với nhiệm vụ của Class lắm.
Anh cần Sub cho ComandButton thì nếu có nhiều sheet thì quả thật sẽ có nhiều code phải chép đi chép lại thật. Nhưng vẫn còn cách khác như Hyperlink hay dùng Button của Form, như 2 đoạn code sau đây cũng vậy. Nó cũng ngắn gọn và có thể áp dụng cho bao nhiêu button cũng được.
Sheet Menu:
Mã:
Private Sub CommandButton1_Click()
If ComboBox1 = "" Then Exit Sub
Sheets(ComboBox1.Value).Select
End Sub
Module:
Mã:
Sub Menu()
Sheet1.Select
End Sub
Nói cho đúng thì Class phải làm và thay đổi gì đó mà ngay cả những lệnh bình thường thì Sub phải chịu thua thì nó mới có giá trị được.
Cũng như bài tiếp theo anh bảo dùng Class nhưng vẫn có cách đơn giản hơn là dùng Sub mà.
Mã:
Public combo As Byte
 
Private Sub SpinButton1_SpinDown()
Dim obj As OLEObjects
If combo = 0 Then Exit Sub
For i = 1 To ActiveSheet.OLEObjects.Count
    If ActiveSheet.OLEObjects(i).Name = "ComboBox" & combo Then Cells(3, i) = Cells(3, i) - 1
Next
End Sub
 
Private Sub SpinButton1_SpinUp()
Dim obj As OLEObjects
If combo = 0 Then Exit Sub
For i = 1 To ActiveSheet.OLEObjects.Count
    If ActiveSheet.OLEObjects(i).Name = "ComboBox" & combo Then Cells(3, i) = Cells(3, i) + 1
Next
End Sub
 
Private Sub ComboBox1_GotFocus()
combo = 1
End Sub
 
Private Sub ComboBox2_GotFocus()
combo = 2
End Sub
 
Private Sub ComboBox3_GotFocus()
combo = 3
End Sub
Về phần đề và ý nghĩa ra đề thì hình như chưa ổn lắm.
Em thấy Class dùng để thay đổi thuộc tính như hàm Property gì đó thì hợp lý hơn.
Mã:
Property Get Names(intX As Integer, intY As Integer) As Variant
    ' Statement here.
    Names = intX + intY
End Property
Với Class thì em cũng đang tìm hiểu nhưng nó không hề giống với các hàm từ trước đến giờ. Chúng đều có cú pháp hay ví dụ gì đó để mình tìm hiểu sự thay đổi. Còn Class thì không như vậy. Nó mới và thay đổi rất kì lạ.
Cứ như là định nghĩa lại cho máy hiểu vậy?
Em nghĩ như vậy đó. Có gì mạo phạm xin lượng thứ cho. Em cũng muốn nâng cao thuật toán nhưng đến Class thì cũng hơi khó trèo qua thiệt.
Như muốn gọi 1 Class trong Module thì chỉ cần gọi tên của Class mà ta hay quên đặt là Class1, Class2 trong khung Project - VBAProject
Cách gọi thì dùng "Dim ikj As New Class1" như vậy.
Việc còn lại thì ikj.Name(3,4) vậy đó.
Module:
Mã:
Sub thu()
Dim ikj As New Class1
MsgBox ikj.Names(3, 4)
End Sub
Class:
Mã:
Property Get Names(intX As Integer, intY As Integer) As Variant
    Names = intX + intY
End Property
Khi viết xong tên biến cho Class. Mọi người thử nhập tên biến rồi chấm 1 cái sẽ thấy có 1 cái Name xuất hiện ra kế bên. Y như khi ta gọi hàm WorksheetFunction vậy đó. Đó gọi là Class đã được liên kết hoàn chỉnh và được gọi.
Giờ thì ta xây dựng lên từ đây. Và nếu có thể thì yêu cầu né né mấy cái nào có thể viết bằng Sub ra nha. Học vậy dễ bị tẩu lắm. Với lại làm giảm sự hứng thú với Class nhiều lắm. Ví dụ như những cái API hoặc Function nào quá đặc biệt và tổng quát (tức là quá dài) thì có thể đặt trong Class nhằm giúp gọi chúng ra dễ dàng hơn. Cũng dễ quản lý hơn nữa.

Tạm thời thì em chỉ mới hiểu đến đây. Từ từ bổ sung kiến thức tiếp sao nha! +-+-+-+
Thân.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Khai báo cho "i" một cái nhé, sẽ không bị lỗi tại File "Combo_Text1".
 
Upvote 0
Thằng Class vẫn khủng khiếp như ngày nào. Đây là 1 đoạn code về Class tạo Dialog để mở file dạng TXT. Nhìn vào ngâm cú mà cứ như đi vào rừng già ấy. Khiếp thật nhỉ?

Nhưng nó chưa hoàn hảo đâu. Vì còn thiếu Class đọc nhiều loại Font khác nữa. Thật là mê thì có nhưng để viết được thế này thì phải học tiếp như thế nào nhỉ?
Thôi ngồi cậm cụi đọc code típ.

Nguồn: http://www.vbaccelerator.com/home/V...Dialog_Minimum_Code_zip_cCommonDialog_cls.asp

Chúc buổi tối vui vẽ nha!
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Khai báo cho "i" một cái nhé, sẽ không bị lỗi tại File "Combo_Text1".

Tôi chạy chả có lỗi gì cả.
Lỗi hay không là do có câu Option Explicit hay không, và cái này là tuỳ thiết lập mỗi máy của mỗi người. Không thể chạy trên máy mình bị lỗi rồi kết luận được.
 
Upvote 0
Po-Pikachu đã viết:
Anh cần Sub cho ComandButton thì nếu có nhiều sheet thì quả thật sẽ có nhiều code phải chép đi chép lại thật. Nhưng vẫn còn cách khác như Hyperlink hay dùng Button của Form, như 2 đoạn code sau đây cũng vậy
Nói cho đúng thì Class phải làm và thay đổi gì đó mà ngay cả những lệnh bình thường thì Sub phải chịu thua thì nó mới có giá trị được.
Cũng như bài tiếp theo anh bảo dùng Class nhưng vẫn có cách đơn giản hơn là dùng Sub mà.

Có lẽ anhtuan muốn giới thiệu class cho mọi người tiếp cận từ dễ đến khó, từ đơn giản đến phức tạp.
Nhớ lại khi xưa, khi mình giới thiệu vòng lặp For - Next, bài đầu tiên là dùng For tính giai thừa của 1 số, trong khi Excel đã có hàm sẵn. Không phải ai cũng có thể chỉ cần đọc chăm chú vào những đoạn code làm sẵn dài ngoằng mà hiểu đâu Po à.
 
Upvote 0
Em có 1 điều này nói ra hơi khó nghe nhưng không nói thì hơi ấm ức.
.
Bạn hãy tưởng tượng thế này: Nếu có 100 ComboBox thì bạn sẽ viết code thế nào đây?
------------------
Gữi bạn 1 file ví dụ về Class Module!
Bạn hãy cho biết nếu viết bằng cách thông thường (không dùng Class) thì bạn sẽ viết thế nào?
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Thằng Class vẫn khủng khiếp như ngày nào. Đây là 1 đoạn code về Class tạo Dialog để mở file dạng TXT. Nhìn vào ngâm cú mà cứ như đi vào rừng già ấy. Khiếp thật nhỉ?

Nhưng nó chưa hoàn hảo đâu. Vì còn thiếu Class đọc nhiều loại Font khác nữa. Thật là mê thì có nhưng để viết được thế này thì phải học tiếp như thế nào nhỉ?
Thôi ngồi cậm cụi đọc code típ.

Nguồn: http://www.vbaccelerator.com/home/V...Dialog_Minimum_Code_zip_cCommonDialog_cls.asp

Chúc buổi tối vui vẽ nha!

Lập trình Class Module không hề khó đâu bạn. Về kỹ thuật của chỉ vài cái thôi: Property Get, Let; WithEvents...
Lập trình Class Module để tạo ra một đối tượng, đối tượng này để làm một việc gì đó. Các bạn vẫn dùng Range("A1").Value để gán giá trị hay RANGE("A1").Formula để gán công thức...Range là một Class làm việc với Cell trong Worksheet đó bạn à.
Lập trình Class Module để chúng ta tiếp cận lập trình .NET. Lập trình .NET tất cả đều là Class chứ không phải dạng viết thủ tục bình thường.
Độ khó của Class Module là do nghiệp vụ của nó mà thôi, ví dụ bạn viết class để tính 1 + 1 = 2, hay viết class để tính hàm tối ưu f(x) = 10 + 4x1 + 5 X2 - 7X3 => Min.

File "Dialog" bạn gửi là người ta dùng các hàm Windows API để lập trình, với dân lập trình API thì mấy cái đó không có gì khó cả vì nó mới chỉ là khai báo kiểu dữ liệu rồi lắp vào hàm API của Windows là xong thôi chứ chưa phải luồn các ngóc ngách gì.

Để học Class căn bản các bạn tạm đừng xem code từ các trang nước ngoài như vbaccelerator rồi để mà sợ, vì nó là ứng dụng nhỏ hoàn chỉnh. Họ không phải viết để học class. Nó dành cho những nhà phát triển, mà những nhà phát triển thì Class đương nhiên ai cũng hiểu rồi. Nó giống như đi học tiếng Anh, mới đi học bạn đã vào lớp bằng C rồi thì sao mà học được.

Tôi chắc chắn rằng, những ai đã biết lập trình VBA (không phải chuyên gia) thì cũng sẽ biết lập trình Class Module vì nó không khó, nó là một dạng lập trình đối tượng các bạn chịu khó đọc tài liệu học về nó là được.
Đừng nhìn kêu khó mà phải tìm hiểu nó thực sự đã!
 
Lần chỉnh sửa cuối:
Upvote 0
Chuyện gì mới thì cũng khó bác ah. Thôi làm quen dần dần tới khi nào rành rồi thì lại thấy mấy bài viết hôm nay thật ngớ ngẩn. hihi :D
Nếu nhiều commandbutton thì em sẽ dùng đến "frmClr.ActiveControl.Name" thằng này dùng cũng được đó. Nhưng phải có lệnh kích hoạt nó.
Để tự động thì em kèm vào sự kiện UserForm_MouseMove(..).
Các code sau khi hình thành thì sẽ như sau:
Mã:
Private Sub NoColor_Click()
  frmClr.Sample.BackStyle = 0
End Sub
 
Private Sub UserForm_Initialize()
  Dim Cmd As Control, iColor, i As Long
  iColor = Array(1, 53, 52, 51, 49, 11, 55, 56, 9, 46, 12, 10, 14, 5, _
                 47, 16, 3, 45, 43, 50, 42, 41, 13, 48, 7, 44, 6, 4, _
                 8, 33, 54, 15, 38, 40, 36, 35, 34, 37, 39, 2, 17, 18, _
                 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)
  For Each Cmd In frmClr.Controls
    If Cmd.Tag = "ColorCB" Then
      Cmd.BackColor = ThisWorkbook.Colors(iColor(i))
      i = i + 1
    End If
  Next Cmd
End Sub
Private Sub cmdExit_Click()
  Unload Me
End Sub
 
Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
frmClr.Sample.BackColor = frmClr.Controls(frmClr.ActiveControl.Name).BackColor
End Sub
Ah quên, dùng thằng ActiveControl thì không thể có Frame được. Vì nó sẽ đọc thấy cái Frame chứ không thấy Command.
Bác nói là can thiệp cell trên bảng tính được. Vậy nếu em cần thay đổi màu Cell theo giá trị của nó thì sao?
Tức là nếu ô [C3]=3 hoặc bằng 4,v.v.v... thì màu của ô này ([C3].InteriorColorIndex) bằng đúng giá trị tại ô đó luôn.
Thì viết Class chuyển màu thế nào hả bác?
Giống như vầy nè. Nhưng không dựa vào hàm thời gian hay kích hoạt Select từ bên ngoài.
Thân.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Chuyện gì mới thì cũng khó bác ah. Thôi làm quen dần dần tới khi nào rành rồi thì lại thấy mấy bài viết hôm nay thật ngớ ngẩn. hihi :D
Nếu nhiều commandbutton thì em sẽ dùng đến "frmClr.ActiveControl.Name" thằng này dùng cũng được đó. Nhưng phải có lệnh kích hoạt nó.
Để tự động thì em kèm vào sự kiện UserForm_MouseMove(..).
Các code sau khi hình thành thì sẽ như sau:
Mã:
Private Sub UserForm_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
frmClr.Sample.BackColor = frmClr.Controls(frmClr.ActiveControl.Name).BackColor
End Sub
Ah quên, dùng thằng ActiveControl thì không thể có Frame được. Vì nó sẽ đọc thấy cái Frame chứ không thấy Command.
Bác nói là can thiệp cell trên bảng tính được. Vậy nếu em cần thay đổi màu Cell theo giá trị của nó thì sao?
Tức là nếu ô [C3]=3 hoặc bằng 4,v.v.v... thì màu của ô này ([C3].InteriorColorIndex) bằng đúng giá trị tại ô đó luôn.
Thì viết Class chuyển màu thế nào hả bác?
Giống như vầy nè. Nhưng không dựa vào hàm thời gian hay kích hoạt Select từ bên ngoài.
Thân.
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é
 
Lần chỉnh sửa cuối:
Upvote 0
File ColorPicker_Class.xls chạy được mà. Em đã thử và thấy nó chạy đó thôi. Sự kiện MoveMouse hơi chậm hơn dùng Class thiệt. Không tin thì thử khoá dòng "frmClr.Sample.BackColor = frmClr.Controls(frmClr.ActiveControl.Name).BackColor" trong Form thử xem. Nó sẽ Break liền đó.

Em thử bài tập 2 bằng Class như sau nó không nhận nhỉ? Em hiểu sai ở chổ nào vậy? Giải thích cụ thể được không?
Thân.
 

File đính kèm

Upvote 0
ColorPicker - Chọn màu từ Userform

Bạn hãy tưởng tượng thế này: Nếu có 100 ComboBox thì bạn sẽ viết code thế nào đây?
------------------
Gữi bạn 1 file ví dụ về Class Module!
Bạn hãy cho biết nếu viết bằng cách thông thường (không dùng Class) thì bạn sẽ viết thế nào?

Từ file gốc của bác anhtuan1066 tôi nâng cấp thêm như sau:
+ Khi mở form, tự nhận màu trong vùng lựa chọn cho nút bám và cửa sổ "Sample"
+ Khi di chuột trên các nút màu, vùng lựa chọn và cửa sổ Sample tạm nhận màu luôn. Chỉ nhận chính thức khi nhấn chuột vào nút đó, giống như Office 2007.
+ Code trong Class sửa lại để phù hợp với nâng cấp.

File này ngoài mục đích ứng dụng, tôi muốn nhấn mạnh vai trò của việc dùng Class Module.
 

File đính kèm

Upvote 0
File ColorPicker_Class.xls chạy được mà. Em đã thử và thấy nó chạy đó thôi. Sự kiện MoveMouse hơi chậm hơn dùng Class thiệt. Không tin thì thử khoá dòng "frmClr.Sample.BackColor = frmClr.Controls(frmClr.ActiveControl.Name).BackColor" trong Form thử xem. Nó sẽ Break liền đó..
Tôi đâu có nói là chạy không được!
Tôi nói nó chạy không giống!
Hình như bạn chưa hiểu ý tôi thì phải
???
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"
Nếu bắt buộc phải làm GIỐNG Y CHANG với file của tôi thì bạn làm sao?

Em thử bài tập 2 bằng Class như sau nó không nhận nhỉ? Em hiểu sai ở chổ nào vậy? Giải thích cụ thể được không?
Thân.
Nghiên cứu tiếp đi
- Sao lại cho code vào sự kiện Workbook_SheetSelectionChange nhỉ? Lý ra bạn phải cho vào Auto_Open để tự kích hoạt nó chứ
- Bạn viết Public WithEvents CB As ComboBox thì CB làm gì có sự kiện GotFocus ?? Có chăng là dùng MouseUp
- Khi đặt con trỏ vào Combo, hãy Set Combo mà ta thu gom chính = với Combo trong Class
 
Upvote 0
Em thử bài tập 2 bằng Class như sau nó không nhận nhỉ? Em hiểu sai ở chổ nào vậy? Giải thích cụ thể được không?
Thân.
Mình gợi ý thế này:
1> Trong Class Module
PHP:
Public WithEvents CB As ComboBox
Private Sub CB_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
  Set Cbo = CB
End Sub
2> Trong Module
PHP:
Public Combo() As New Class1, Cbo As ComboBox
Sub Auto_Open()
  Dim i As Long, Obj As OLEObject
  For Each Obj In ActiveSheet.OLEObjects
    If TypeOf Obj.Object Is ComboBox Then
      ReDim Preserve Combo(i)
      Set Combo(i).CB = Obj.Object
      i = i + 1
    End If
  Next
End Sub
Phần còn lại để điểu khiển SpinButton bạn tự làm nhé! Chỉ là Cbo.Value = Val(Cbo.Value) + 1 (hoặc -1) thôi
 
Upvote 0
Nếu bắt buộc phải làm GIỐNG Y CHANG với file của tôi thì bạn làm sao?


Nghiên cứu tiếp đi
- Sao lại cho code vào sự kiện Workbook_SheetSelectionChange nhỉ? Lý ra bạn phải cho vào Auto_Open để tự kích hoạt nó chứ
- Bạn viết Public WithEvents CB As ComboBox thì CB làm gì có sự kiện GotFocus ?? Có chăng là dùng MouseUp
- Khi đặt con trỏ vào Combo, hãy Set Combo mà ta thu gom chính = với Combo trong Class

Giờ em chẳng biết phải làm sao nữa rùi. Thôi quay lại hỏi vài cái chưa biết cái đã.
Khi nào thông rồi chắc chắn nó sẽ ra thôi.
Trường PrevInterior dùng để nạp dữ liệu vào đâu vậy?
Sao em không thấy nó bên Class vậy?
Còn khi nhấn vào No Color thì Sample im re luôn. Có MouseMove cũng không được nữa. Vậy phải khắc phục sao nhỉ?
Sau khi bỏ bớt vài thứ chẳng hiểu để làm gì thì code chạy như sau:
+Nạp màu lên Button dựa trên ArraryColor.
+Tự chọn màu khi chuột chạy hiện cả trên Form và trên Selection. Nếu Click chọn 1 màu thì nó sẽ ngừng trên Selection.
+Nạp lại chế độ NoColor cho Sample.
Thân.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Giờ em chẳng biết phải làm sao nữa rùi. Thôi quay lại hỏi vài cái chưa biết cái đã.
Khi nào thông rồi chắc chắn nó sẽ ra thôi.
Trường PrevInterior dùng để nạp dữ liệu vào đâu vậy?
Sao em không thấy nó bên Class vậy?
Còn khi nhấn vào No Color thì Sample im re luôn. Có MouseMove cũng không được nữa. Vậy phải khắc phục sao nhỉ?
hân.
Nếu là tôi thì tôi làm vầy
1> Trong Class Module
PHP:
Public WithEvents CB As CommandButton
Private Sub CB_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
  frmClr.Sample.BackColor = CB.BackColor
  frmClr.Sample.BackStyle = 1
  Selection.Interior.Color = CB.BackColor
End Sub
2> Trong Form
PHP:
Dim Buttons() As New MyClass, CllColor As Long
PHP:
Private Sub NoColor_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
  frmClr.Sample.BackStyle = 0
End Sub
PHP:
Private Sub UserForm_Initialize()
  Dim Cmd As Control, iColor, i As Long
  On Error Resume Next
  CllColor = Selection(1, 1).Interior.Color
  iColor = Array(1, 53, 52, 51, 49, 11, 55, 56, 9, 46, 12, 10, 14, 5, _
                 47, 16, 3, 45, 43, 50, 42, 41, 13, 48, 7, 44, 6, 4, _
                 8, 33, 54, 15, 38, 40, 36, 35, 34, 37, 39, 2, 17, 18, _
                 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32)
  For Each Cmd In frmClr.Patt.Controls
    If Cmd.Tag = "ColorCB" Then
      Cmd.BackColor = ThisWorkbook.Colors(iColor(i))
      ReDim Preserve Buttons(i)
      Set Buttons(i).CB = Cmd
      i = i + 1
    End If
  Next Cmd
  frmClr.Sample.BackColor = CllColor
End Sub
Lưu ý: Code của Nguyễn Duy Tuân vẫn bị 1 lỗi khi vùng Selection có chứa 2 màu đấy nhé
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Còn khi nhấn vào No Color thì Sample im re luôn. Có MouseMove cũng không được nữa. Vậy phải khắc phục sao nhỉ?
hân.
Trong Class Moduel có đoạn:
Mã:
Private Sub CB_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    If CB.Caption = "No Color" Then Exit Sub
    If MyFrm.Sample.BackColor <> CB.BackColor Then
        MyFrm.Sample.BackColor = CB.BackColor
        If Not MyFrm.IsOk Then Selection.Interior.Color = CB.BackColor
    End If
End Sub
Sửa thành vầy là được:
Mã:
Private Sub CB_MouseMove(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    If CB.Caption = "No Color" Then Exit Sub
    If MyFrm.Sample.BackColor <> CB.BackColor Then
        MyFrm.Sample.BackColor = CB.BackColor
        [COLOR=Red][B]MyFrm.Sample.BackStyle = 1[/B][/COLOR]
        If Not MyFrm.IsOk Then Selection.Interior.Color = CB.BackColor
    End If
End Sub
 
Upvote 0
Tải lại xem nha!
ColorPicker.rar
Em chỉnh hơi bị nhiều nên cũng không biết nói sao nữa.
Thân.
 
Upvote 0
Xin lỗi bác nha. Em không cố ý làm bác giận đâu.
Chỉ là em thấy chỉ cần như vậy là chạy được theo yêu cầu rùi.
Méo mó nghề nghiệp tý thui. hihi :D
Bác đừng giận nha! :D
Thân.
 
Upvote 0
Xin lỗi bác nha. Em không cố ý làm bác giận đâu.
Chỉ là em thấy chỉ cần như vậy là chạy được theo yêu cầu rùi.
Méo mó nghề nghiệp tý thui. hihi :D
Bác đừng giận nha! :D
Thân.

Thấy bạn bỏ code vô lý quá. Code tôi viết trong ColorPicker là không thừa không thiếu đâu bạn ạ. Nó làm theo các yêu cầu dưới đây:
...tôi nâng cấp thêm như sau:
+ Khi mở form, tự nhận màu trong vùng lựa chọn cho nút bấm và cửa sổ "Sample"
+ Khi di chuột trên các nút màu, vùng lựa chọn và cửa sổ Sample tạm nhận màu luôn. Chỉ nhận chính thức khi nhấn chuột vào nút đó, giống như Office 2007.
+ Code trong Class sửa lại để phù hợp với nâng cấp.

Thêm nữa là bấm vào nút chọn màu là thoát form luôn và xác lập nhận màu (IsOk = True), nếu bấm vào nút "Exit" hoặc dấu (X) là thoát và khôi phục lại mầu trước khi mở form.

Nếu bạn có ý tưởng nào khác thì có thể làm mẫu một file khác gửi lên tôi sẽ tìm giải pháp cùng bạn.
 
Upvote 0
Tải lại xem nha!
ColorPicker.rar
Em chỉnh hơi bị nhiều nên cũng không biết nói sao nữa.
Thân.
Code này vẫn còn lỗi ---> Khi bấm nút "No Color" thì nó hết tô màu cho cell luôn!
----------------------
Xin lỗi Tuân trước, mình thấy cách viết code của Tuân là cách viết chuyên nghiệp... chính thế mà những người không chuyên như mình rất khó theo kịp
Chẳng trách gì Po lại "phá" tùm lum ---> Mục đích cũng là tìm ra "chân lý" từ những cái đơn giản trước
----------------------
...tôi nâng cấp thêm như sau:
+ Khi mở form, tự nhận màu trong vùng lựa chọn cho nút bấm và cửa sổ "Sample"
+ Khi di chuột trên các nút màu, vùng lựa chọn và cửa sổ Sample tạm nhận màu luôn. Chỉ nhận chính thức khi nhấn chuột vào nút đó, giống như Office 2007.
+ Code trong Class sửa lại để phù hợp với nâng cấp..
Bây giờ mới hiểu tính phức tạp của vấn đề đây!
Cảm ơn bạn!
 
Lần chỉnh sửa cuối:
Upvote 0
Cải tiến file ColorPicker

Nhân dịp bạn Nguyễn Duy Tuân nâng cấp file ColorPicker, tôi muốn làm thêm 1 số cải tiến nữa:
- Có khả năng hoạt động với vùng dữ liệu không liên tục
- Có khả năng nhận biết được nhiều màu sắc có trong 1 vùng
---------------
Xin mời xem file! Ưu điểm của nó là code ngắn gọn
---------------
Ngoài ra, các bạn nhớ nghiên cứu bài số #5 và gữi lên đây nhé
 

File đính kèm

Upvote 0
Nhân dịp bạn Nguyễn Duy Tuân nâng cấp file ColorPicker, tôi muốn làm thêm 1 số cải tiến nữa:
- Có khả năng hoạt động với vùng dữ liệu không liên tục
- Có khả năng nhận biết được nhiều màu sắc có trong 1 vùng
---------------
Xin mời xem file! Ưu điểm của nó là code ngắn gọn
---------------
Ngoài ra, các bạn nhớ nghiên cứu bài số #5 và gữi lên đây nhé

Anh Tuấn ơi, trong file anh sử dụng thư viện "Office Web component". Một số máy không cài nên lỗi ở đối tượng Spreadsheat1. Anh có thể dùng biến mảng để ghi lại màu.
 
Upvote 0
Anh Tuấn ơi, trong file anh sử dụng thư viện "Office Web component". Một số máy không cài nên lỗi ở đối tượng Spreadsheat1. Anh có thể dùng biến mảng để ghi lại màu.
Vâng! Lúc đầu tôi cũng định vậy, nhưng chợt phát hiện ra trong VBA có đối tượng SpreadSheet, tại sao ta không dùng nhỉ?
Chỉ thêm có 1 đối tượng mà đã khiến cho code ngắn gọn và linh hoạt tuyệt vời rồi! Khi ta chọn vùng không liên tục mà đưa chúng vào mảng là khá nhiêu khê đấy
Mà việc cài thêm nó hầu như không gây khó khăn gì (nếu không nói là hầu hết các máy đều có sẳn khi cài Office)
 
Upvote 0
Tôi ưng cái Class này cho việc của mình quá, nó thật hiệu quả, khoa học và gọn gàng. nhưng khi chuyển từ Module sang Class không được.

Yêu cầu là:
Trên 1 Form có 8 TextBox, không có Label:
-Khi TextBox nhận Focus thì: Hiện lời nhắc thay Label nếu TextBox trống. Nền vàng, Chữ đỏ.
-Khi TextBox mất Focus thì: Nếu Nội dung là lời nhắc thì xoá. Nền xanh nhạt, chữ xanh dương.

Trong File None Class là cơ bản kết quả
Trong file Class là mình đã chuyển sang Class nhưng không thành công. (Dùng sự kiện Enter và Exit tương tự như TextBox với Module)
Nhờ anh em hướng dẫn giùm.
Mình muốn gửi bài này vào đây chứ không mở bài riêng vì thực chất đây cũng là ví dụ rất cụ thể cho bài này và vận dụng cơ bản lý thuyết bài này.
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Tôi ưng cái Class này cho việc của mình quá, nó thật hiệu quả, khoa học và gọn gàng. nhưng khi chuyển từ Module sang Class không được.

Yêu cầu là:
Trên 1 Form có 8 TextBox, không có Label:
-Khi TextBox nhận Focus thì: Hiện lời nhắc thay Label nếu TextBox trống. Nền vàng, Chữ đỏ.
-Khi TextBox mất Focus thì: Nếu Nội dung là lời nhắc thì xoá. Nền xanh nhạt, chữ xanh dương.

Trong File None Class là cơ bản kết quả
Trong file Class là mình đã chuyển sang Class nhưng không thành công. (Dùng sự kiện Enter và Exit tương tự như TextBox với Module)
Nhờ anh em hướng dẫn giùm.
Mình muốn gửi bài này vào đây chứ không mở bài riêng vì thực chất đây cũng là ví dụ rất cụ thể cho bài này và vận dụng cơ bản lý thuyết bài này.
Em sửa lại vầy:
- Đầu tiên em cho mấy thông tin trong Info vào trong Tag
- Code sửa lại như sau:
1> Trong UserForm
PHP:
Dim dkhien() As New Sea
Private Sub UserForm_Initialize()
  Dim Ctrl As Control, i
  For Each Ctrl In Me.Controls
    If TypeOf Ctrl Is MSForms.TextBox Then
      Ctrl.ForeColor = &HFF0000
      Ctrl.BackColor = &HFFFFC0
      ReDim Preserve dkhien(i)
      Set dkhien(i).DK = Ctrl
      i = i + 1
    End If
  Next
End Sub
2> Trong Class Module
PHP:
Public WithEvents DK As MSForms.TextBox
Private Sub DK_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  Dim tb As MSForms.Control
  For Each tb In UserForm1.Controls
    If TypeOf tb Is MSForms.TextBox Then
      If tb <> DK Then
      tb.ForeColor = &HFF0000
      tb.BackColor = &HFFFFC0
      If tb.Text = tb.Tag Then tb.Text = ""
      End If
    End If
  Next
  DK.ForeColor = &HFF&
  DK.BackColor = &HC0FFFF
  If DK.Text = "" Then
    DK.Text = DK.Tag
    DK.SelStart = 0
    DK.SelLength = Len(DK.Text)
  End If
End Sub
Khai báo kiểu Public WithEvents DK As MSForms.TextBox thì DK sẽ không có sự kiện EnterExit đâu anh à!
Code này chỉ có tác dụng khi anh dùng chuột chọn vào TextBox ---> Để có thể xài luôn được với phím Enter và phím Tab, anh cho nguyên code trên vào sự kiện DK_KeyUp nữa là ăn tiền
 

File đính kèm

Lần chỉnh sửa cuối:
Upvote 0
Rút gọn code

Em rút gọn code trong Class Module thế này:
PHP:
Public WithEvents DK As MSForms.TextBox

PHP:
Private Sub DK_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
  ObjColor DK
End Sub
PHP:
Private Sub DK_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
  ObjColor DK
End Sub
PHP:
Private Sub ObjColor(Mytb As MSForms.TextBox)
  Dim tb As MSForms.Control
  For Each tb In UserForm1.Controls
    If TypeOf tb Is MSForms.TextBox Then
      tb.ForeColor = &HFF0000
      tb.BackColor = &HFFFFC0
      If tb.Text = tb.Tag Then tb.Text = ""
    End If
  Next
  Mytb.ForeColor = &HFF&
  Mytb.BackColor = &HC0FFFF
  If Mytb.Text = "" Then
    Mytb.Text = DK.Tag
    Mytb.SelStart = 0
    Mytb.SelLength = Len(Mytb.Text)
  End If
End Sub
anh kiểm tra xem có chổ nào không ổn giúp em với
 

File đính kèm

Upvote 0
Quá hay, riêng Form này bỏ đi gần 20 cái Sub. Chỉ còn một điều là khi thoát TextBox cuối nó chưa reset lại nó là có thể áp dụng cho các Form. Quan sát thấy Form thân thiện và Pro hơn.
Từ đây cũng có điều rút ra là kiểm tra Class có thể có 2 trường hợp sau:
-Không phải Class hỗ trợ tất cả các Event, Property, Method mà đối tượng có.
-Chưa tìm ra cách sử dung nó.
Mong anh em có khả năng chỉ dẫn giùm.
 
Upvote 0
Tức là khi con trỏ rời TextBox8 sang nút Exit thì TextBox8 vẫn còn nguyên nền vàng và lời nhắc. Đáng lẽ không nhập gì thì nó bị xoá và chuyển về nền xanh nhạt và chữ xanh dương.
Lưu ý: TextBox1 (Khi lùi) và TextBox8(Khi tiến) Focus sang đối tượng khác loại nên không gọi Class
 
Lần chỉnh sửa cuối:
Upvote 0
Tức là khi con trỏ rời TextBox8 sang nút Exit thì TextBox8 vẫn còn nguyên nền vàng và lời nhắc. Đáng lẽ không nhập gì thì nó bị xoá và chuyển về nền xanh nhạt và chữ xanh dương.
Lưu ý: TextBox1 (Khi lùi) và TextBox8(Khi tiến) Focus sang đối tượng khác loại nên không gọi Class
Để viết thêm cái này chắc không khó... nhưng e rằng hơi mất công!
Anh thí nghiệm xem
Lưu ý: TextBox1 (Khi lùi) và TextBox8(Khi tiến) Focus sang đối tượng khác loại nên không gọi Class
Muốn vậy anh phải viết thêm code cho các đối tượng khác nữa thì mới xong!
 
Upvote 0
Mình nêu lên vậy nếu sử lý được trong Class thì tốt còn không thì tạm gài vào đối tượng có TabStop=Tabstop cua Text box8 +1 cũng ổn.
 
Upvote 0
File tham khảo cho bài #5

Về câu hỏi tại bài số #5 tôi xin gữi 1 code tham khảo
1> Trong Module
PHP:
Public Button() As New MyClass
Public CB As ComboBox
Sub Auto_Open()
  Dim Obj As OLEObject, i As Long
  For Each Obj In Sheet1.OLEObjects
    If InStr(Obj.progID, "Forms.ComboBox") Then
      ReDim Preserve Button(i)
      Set Button(i).cbBox = Obj.Object
      i = i + 1
    End If
  Next
End Sub
2> Trong Class Module
PHP:
Public WithEvents cbBox As ComboBox
Private Sub cbBox_MouseUp(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
  Set CB = cbBox
End Sub
Xin mời xem file và cải tiến tiếp nếu có thể được
Tôi vẫn chưa nghĩ ra cách viết code trong trường hợp Object là TextBox (chứ không phải ComboBox)...
Các bạn thử nghiên cứu xem
 

File đính kèm

Lần chỉnh sửa cuối:
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

Em làm đúng như bác nói,nhưng nó báo lỗi: Compile error
invalid use of ..keyword

Mong sự giúp đỡ
 
Upvote 0
khi làm các thao tác như bài trước em nói và ấn F5 thì dòng lệnh bị báo lỗi:
Public Button() As New MyClass (từ but...myclass)
và hộp thoại cảnh báo lỗi:

Compile error
invalid use of ..keyword
 
Upvote 0
khi làm các thao tác như bài trước em nói và ấn F5 thì dòng lệnh bị báo lỗi:
Public Button() As New MyClass (từ but...myclass)
và hộp thoại cảnh báo lỗi:

Compile error
invalid use of ..keyword
Thì bạn cứ làm xong hết đi, báo lỗi thế nào cứ mặc kệ, post file lên để mọi người tim nguyên nhân nhé
 
Upvote 0
Bạn làm bước này chưa, nhất là chỗ màu đỏ:

1> Trong Class Module
Hãy chèn 1 Class Modulenhớ đặ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:
 
Upvote 0
Giờ lại được rùi, cảm ơn tất cả các huynh tỷ

Chắc em Inset/class module mới và đặt tên cho class2 trong khi Code là class1.

Không phải "chắc là lỗi do ..." theo kiểu đoán mò mà phải nói chinh xác "Rõ ràng là lỗi do ..."

Bởi vì báo lỗi compile Error ngay dòng code sau:

Public Button() As New MyClass

Chữ Public là từ khoá nên không thể sai, chữ Button là tên biến đang khai báo và có quyền khai báo tuỳ ý, nên không ai bắt sai, As New là từ khoá nên không thể sai.

Chỉ còn chữ MyClass. Bắt lỗi MyClass thì chỉ có 1 lỗi duy nhất là "MyClass" chưa khai báo. Hoặc khai báo 1 đằng sử dụng 1 nẻo.

 
Lần chỉnh sửa cuối:
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

Xin cho em hỏi lại về vấn đề này ạ. Nếu giờ thay bằng tạo một sheet menu như trên em muốn là form có tên menu " trên đó chứa các commanbutton link tới các sheet như sheet menu kia" thì có làm được không ạ
--------------------------------------
Ở trên code viết vào module class
Mã:
[COLOR=#000000][COLOR=#0000BB]Sheets[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000BB]CB[/COLOR][COLOR=#007700].[/COLOR][COLOR=#0000BB]Caption[/COLOR][COLOR=#007700]).[/COLOR][COLOR=#0000BB]Select[/COLOR][/COLOR]
giờ em thay bằng
Mã:
userforms(CB.caption).select
thì có chạy được không hả anh?
em đã thay nhưng không được?
vậy nếu được thì phải làm như thế nào ạh???
 
Upvote 0
Xin cho em hỏi lại về vấn đề này ạ. Nếu giờ thay bằng tạo một sheet menu như trên em muốn là form có tên menu " trên đó chứa các commanbutton link tới các sheet như sheet menu kia" thì có làm được không ạ
--------------------------------------
Ở trên code viết vào module class
Mã:
[COLOR=#000000][COLOR=#0000BB]Sheets[/COLOR][COLOR=#007700]([/COLOR][COLOR=#0000BB]CB[/COLOR][COLOR=#007700].[/COLOR][COLOR=#0000BB]Caption[/COLOR][COLOR=#007700]).[/COLOR][COLOR=#0000BB]Select[/COLOR][/COLOR]
giờ em thay bằng
Mã:
userforms(CB.caption).select
thì có chạy được không hả anh?
em đã thay nhưng không được?
vậy nếu được thì phải làm như thế nào ạh???

Muốn thế nào bạn phải cho file lên đây chứ (chẳng lẽ tôi phải giả lập file để test giúp bạn sao)
 
Upvote 0
Muốn thế nào bạn phải cho file lên đây chứ (chẳng lẽ tôi phải giả lập file để test giúp bạn sao)
Anh giúp em bài này theo modulle class và thay bằng dùng sheet menu như trên mà em muốn thay bằng form menu như trong file đính kèm ạ.
 

File đính kèm

Upvote 0
Anh giúp em bài này theo modulle class và thay bằng dùng sheet menu như trên mà em muốn thay bằng form menu như trong file đính kèm ạ.

Với 3 cái sheet, làm class chi cho mệt vậy bạn? Làm hẳn trên form với sự kiện Click của các nút được rồi!
 
Lần chỉnh sửa cuối:
Upvote 0
Anh giúp em bài này theo modulle class và thay bằng dùng sheet menu như trên mà em muốn thay bằng form menu như trong file đính kèm ạ.

Chèn 1 Class (tên mặc định của nó là Class1) với code:
Mã:
Public WithEvents cmd As MSForms.CommandButton
Private Sub cmd_Click()
  On Error Resume Next
  With ThisWorkbook.Worksheets(cmd.Caption)
    .Visible = -1
    .Activate
  End With
End Sub
Code trong UserForm menu
Mã:
Dim Buttons() As New [COLOR=#ff0000][B]Class1[/B][/COLOR]
Private Sub UserForm_Initialize()
  Dim Ctrl As Control, n As Long
  For Each Ctrl In Me.Controls
    If TypeOf Ctrl Is MSForms.CommandButton Then
      n = n + 1
      ReDim Preserve Buttons(1 To n)
      Set Buttons(n).cmd = Ctrl
    End If
  Next
End Sub
 
Upvote 0
Đó là file test thôi mà bạn. Hơn nữa mình muốn học hỏi là chính mà!!!!
OK, nó cũng chỉ đơn giản vậy thôi:

1) Code trong Class Module:

[GPECODE=vb]Option Explicit
Public WithEvents CmdBttn As MSForms.CommandButton

Private Sub CmdBttn_Click()
Sheets(CmdBttn.Caption).Select
Range("A1").Select
Unload menu
End Sub
[/GPECODE]

2) Code trong UserForm Module:

Mã:
Option Explicit
Private MyCmdBttn(1 To 3) As New EventClass

Private Sub UserForm_Initialize()
    Dim i As Long
    For i = 1 To 3
        Set MyCmdBttn(i).CmdBttn = Me("CommandButton" & i)
    Next
End Sub
 

File đính kèm

Upvote 0
OK, nó cũng chỉ đơn giản vậy thôi:

1) Code trong Class Module:

[GPECODE=vb]Option Explicit
Public WithEvents CmdBttn As MSForms.CommandButton

Private Sub CmdBttn_Click()
Sheets(CmdBttn.Caption).Select
Range("A1").Select
Unload menu
End Sub
[/GPECODE]

2) Code trong UserForm Module:

Mã:
Option Explicit
Private MyCmdBttn(1 To 3) As New EventClass

Private Sub UserForm_Initialize()
    Dim i As Long
    For i = 1 To 3
        Set MyCmdBttn(i).CmdBttn = Me("CommandButton" & i)
    Next
End Sub
Mã:
CmdBttn As MSForms.CommandButton
Cái này mình hiểu là: Cmdbttn có kiểu của commandbutton trên form đúng không vây?
Mã:
Private Sub UserForm_Initialize()
Giải thích giúp mình tẹo ý nghĩa của nó "Initialize"
Mã:
For i = 1 To 3
        Set MyCmdBttn(i).CmdBttn = Me("CommandButton" & i)
    Next
Mình không hiểu câu lệnh này, giải thích giúp thêm với bạn?
 
Upvote 0
Mã:
CmdBttn As MSForms.CommandButton
Cái này mình hiểu là: Cmdbttn có kiểu của commandbutton trên form đúng không vây?
Mã:
Private Sub UserForm_Initialize()
Giải thích giúp mình tẹo ý nghĩa của nó "Initialize"
Mã:
For i = 1 To 3
        Set MyCmdBttn(i).CmdBttn = Me("CommandButton" & i)
    Next
Mình không hiểu câu lệnh này, giải thích giúp thêm với bạn?

Private Sub UserForm_Initialize()

Nếu như các controls trên UserForm đều có sự kiện, thì UserForm cũng có sự kiện. Câu lệnh trên là một trong các sự kiện mà khi bắt đầu load form (form show), trước khi sự kiện Activate của form xảy ra thì xuất hiện sự kiện Initialize. Đây là sự kiện đầu tiên của UserForm, các thủ tục trong sự kiện này chạy ngầm cho đến khi form hiện trước mặt chúng ta là đã kết thúc.

Private MyCmdBttn(1 To 3) As New EventClass

MyCmdBttn là một mảng 1 chiều, tôi tạo ra mảng này nhằm mục đích để nó là mảng kiểu Object Data, nó có 3 phần tử (nếu ta chắc chắn biết số phần tử nằm bên trong nó, trong trường hợp này ta biết chắc có 3 nút lệnh), mỗi phần tử là một object. Mảng này được điều khiển bởi ClassModule EventClass.

Set MyCmdBttn(i).CmdBttn = Me("CommandButton" & i)

Khi chạy vòng lặp i từ 1 đến 3, vì mỗi phần tử là một object nên chúng ta phải SET chúng, và gán chúng có thuộc tính mà ta đã thực hiện trong ClassModule, đó chính là CmdBttn.

Me("CommandButton" & i) Ở đây Me là đại diện cho UserForm, thay vì ta viết Controls("CommandButton" & i) thì ta viết như thế. Bởi các Button có Name giống nhau (CommandButton) chỉ khác số cuối nên ta lợi dụng điểm này mà thực hiện vòng lặp.

Thay vì ta SET đến 3 lần, mỗi lần như sau:

Set MyCmdBttn(1).CmdBttn = CommandButton1
Set MyCmdBttn(2).CmdBttn = CommandButton2
Set MyCmdBttn(3).CmdBttn = CommandButton3

Thì chúng ta dùng vòng lặp cho nó gọn lại.

Hy vọng tôi nói nôm na như thế bạn sẽ hiểu được những gì tôi nói.
 
Lần chỉnh sửa cuối:
Upvote 0
Mã:
Public WithEvents cmd As MSForms.CommandButton
Private Sub cmd_Click()
  On Error Resume Next
  With ThisWorkbook.Worksheets(cmd.Caption)
    .Visible = -1
    .Activate
  End With
End Sub
Mã:
Dim Buttons() As New [COLOR=#ff0000][B]Class1[/B][/COLOR]
Private Sub UserForm_Initialize()
  Dim Ctrl As Control, n As Long
  For Each Ctrl In Me.Controls
    If TypeOf Ctrl Is MSForms.CommandButton Then
      n = n + 1
      ReDim Preserve Buttons(1 To n)
      Set Buttons(n).cmd = Ctrl
    End If
  Next
End Sub
Mã:
Option Explicit
Private MyCmdBttn(1 To 3) As New EventClass

Private Sub UserForm_Initialize()
    Dim i As Long
    For i = 1 To 3
        Set MyCmdBttn(i).CmdBttn = Me("CommandButton" & i)
    Next
End Sub
Cảm ơn 2 anh nhé! 2 code đều cho kết qquar đúng ạ
 
Upvote 0
Cảm ơn 2 anh nhé! 2 code đều cho kết qquar đúng ạ

Tùy theo trường hợp mà dùng 2 thủ tục vòng lặp, nếu tất cả các nút lệnh đều là nút mà chọn sheet thì vòng lặp For Each ... Next sẽ thực hiện đúng, giả sử có nhiếu nút lệnh với các chức năng khác nhau, thì vô hình chung vòng lặp loại này sẽ mang thuộc tính của sự kiện mà ta vừa tạo tại ClassModule. Đồng thời ta có trên form nào là label, nào là textbox, combobox, frame, v.v... thì vòng lặp này quét qua tất cả để chỉ tìm đúng loại CommandButton thôi nên sẽ "phí" thời gian.

Với trường hợp vòng lặp For i ... Next thì không hữu dụng với các Name không có điểm chung. Với tôi sẽ chọn cách này và đặt tên cho chúng giống nhau, chỉ khác số cuối cùng (chẳng hạn cmdSheet1, cmdSheet2, v.v...) thì sẽ làm cho code gọn đi rất nhiều.
 
Upvote 0
Tùy theo trường hợp mà dùng 2 thủ tục vòng lặp, nếu tất cả các nút lệnh đều là nút mà chọn sheet thì vòng lặp For Each ... Next sẽ thực hiện đúng, giả sử có nhiếu nút lệnh với các chức năng khác nhau, thì vô hình chung vòng lặp loại này sẽ mang thuộc tính của sự kiện mà ta vừa tạo tại ClassModule. Đồng thời ta có trên form nào là label, nào là textbox, combobox, frame, v.v... thì vòng lặp này quét qua tất cả để chỉ tìm đúng loại CommandButton thôi nên sẽ "phí" thời gian.

Với trường hợp vòng lặp For i ... Next thì không hữu dụng với các Name không có điểm chung. Với tôi sẽ chọn cách này và đặt tên cho chúng giống nhau, chỉ khác số cuối cùng (chẳng hạn cmdSheet1, cmdSheet2, v.v...) thì sẽ làm cho code gọn đi rất nhiều.

Mình gặp phải vấn đề không biết xử lý sao
Mình vào vấn đề luôn, xóa một commandbutton chạy trương trình báo lỗi dù đã thử nhiều cách:
1> Bổ xung lại commandbutton với tên đúng như tên đã sóa nhưng không được
2> Sóa nốt sheet tương ứng tên của commandbutton đó cũng không được
gặp phải cái này mình phải xử lý như thế nào ? bạn có thể thử trên file bạn up cho mình!!!
 
Upvote 0
Mình gặp phải vấn đề không biết xử lý sao
Mình vào vấn đề luôn, xóa một commandbutton chạy trương trình báo lỗi dù đã thử nhiều cách:
1> Bổ xung lại commandbutton với tên đúng như tên đã sóa nhưng không được
2> Sóa nốt sheet tương ứng tên của commandbutton đó cũng không được
gặp phải cái này mình phải xử lý như thế nào ? bạn có thể thử trên file bạn up cho mình!!!


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?
 
Upvote 0
Chèn 1 Class (tên mặc định của nó là Class1) với code:
Mã:
Public WithEvents cmd As MSForms.CommandButton
Private Sub cmd_Click()
  On Error Resume Next
  With ThisWorkbook.Worksheets(cmd.Caption)
    .Visible = -1
    .Activate
  End With
End Sub
Code trong UserForm menu
Mã:
Dim Buttons() As New [COLOR=#ff0000][B]Class1[/B][/COLOR]
Private Sub UserForm_Initialize()
  Dim Ctrl As Control, n As Long
  For Each Ctrl In Me.Controls
    If TypeOf Ctrl Is MSForms.CommandButton Then
      n = n + 1
      ReDim Preserve Buttons(1 To n)
      Set Buttons(n).cmd = Ctrl
    End If
  Next
End Sub
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 ạ
 
Upvote 0
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

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

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

Back
Top Bottom