Sự kiện WithEvents không hoạt động đúng

Liên hệ QC

tuannguyen789

Thành viên mới
Tham gia
19/4/10
Bài viết
29
Được thích
1
Xin chào mọi người, tôi đang gặp vấn đề về withevwnts nhu sau:

- khỏi tạo các combobox khi chạy userform, sau đó, chọn sự kiện tại một trong combobox (ví dụ: xóa dữ lieu tại combobox2 khi doubleclick). Tuy nhiên phải chọn combobox4 thì combobox2 mới được xóa.
- Xin giúp sửa code sao cho tại tùy biến combobox sẽ thực hiện lệnh.

Xin cám ơn
 

File đính kèm

  • Book1.xlsb
    15.2 KB · Đọc: 7
Xin chào mọi người, tôi đang gặp vấn đề về withevwnts nhu sau:

- khỏi tạo các combobox khi chạy userform, sau đó, chọn sự kiện tại một trong combobox (ví dụ: xóa dữ lieu tại combobox2 khi doubleclick). Tuy nhiên phải chọn combobox4 thì combobox2 mới được xóa.
- Xin giúp sửa code sao cho tại tùy biến combobox sẽ thực hiện lệnh.

Xin cám ơn

Đã có
WithEvents
đâu mà hoạt động đúng hay sai?

Mô tả vấn đề cũng chưa rõ, 4 với 3 cứ loạn cả nên , xóa dữ liệu , các combobox có dữ liệu đâu mà xóa
 
ah, ví dụ combox 2 minh lỡ đánh sai, giờ muốn xóa nó. thôi thường thì bôi đen và xóa, nhưng muốn thao tác nhanh thì chỉ cần click đôi chuột.
Nhưng đằng này phải chọn ở combobox4 mới xóa được combobox 2
 
ah, ví dụ combox 2 minh lỡ đánh sai, giờ muốn xóa nó. thôi thường thì bôi đen và xóa, nhưng muốn thao tác nhanh thì chỉ cần click đôi chuột.
Nhưng đằng này phải chọn ở combobox4 mới xóa được combobox 2
Ví dụ xong cũng rối hơn mà thôi,
Tốt nhất là mô tả lại bài toán thực là gì, dữ liệu đầy đủ, thì mới hy vọng
Còn chỉ làm chơi , ví dụ chơi thì khó ai hiểu được ý bạn.
 
Để nói rõ hơn như sau:
- Khi chạy userform sẽ hiện ra rất nhiều combobox nhưng mình chỉ nói đến 4 combobox cho dễ thấy.
- Cobobox1 có dư liệu: trái mít, conbobox2: Trái xoài, Combobox3: Trái Cam, combobox4: Trái bưởi.
- Giờ muốn xóa trái xoài thì có 2 cách:
cách 1: Xóa trực tiếp (cái này thì không nói tới)
cách 2: xóa nhanh (bằng cách double click).
Tuy khi làm cách 2, thì muốn được như vậy phải chọn Cobobox4, sau đó double click thì combobox2 mới xóa được. Như vậy, phải làm sau, khi ta chỉ cần chọn đúng combobox2 sẽ xóa, không phải nhấn combobox4
Bạn có thể làm trực tiếp trên phải mình đã gởi sẽ rõ.
 
Để nói rõ hơn như sau:
- Khi chạy userform sẽ hiện ra rất nhiều combobox nhưng mình chỉ nói đến 4 combobox cho dễ thấy.
- Cobobox1 có dư liệu: trái mít, conbobox2: Trái xoài, Combobox3: Trái Cam, combobox4: Trái bưởi.
- Giờ muốn xóa trái xoài thì có 2 cách:
cách 1: Xóa trực tiếp (cái này thì không nói tới)
cách 2: xóa nhanh (bằng cách double click).
Tuy khi làm cách 2, thì muốn được như vậy phải chọn Cobobox4, sau đó double click thì combobox2 mới xóa được. Như vậy, phải làm sau, khi ta chỉ cần chọn đúng combobox2 sẽ xóa, không phải nhấn combobox4
Bạn có thể làm trực tiếp trên phải mình đã gởi sẽ rõ.
Quả thật, chắc tôi chậm hiểu, nên không hiểu bạn nói gì,
File gửi trên bài #1 thì tôi đã nói
Đã có
WithEvents
đâu mà hoạt động đúng hay sai?

Mô tả vấn đề cũng chưa rõ, 4 với 3 cứ loạn cả nên , xóa dữ liệu , các combobox có dữ liệu đâu mà xóa
Hy vọng mai mốt thành viên khác hiểu giúp bạn vậy.
 
Code thực thi ở DoComboDblClick. Làm thế để dễ tùy biến. Khi cần chỉnh sửa hoặc dùng trong tập tin khác thì chỉ kéo thả lớp clsCombo sang tập tin mới -> viết lại DoComboDblClick cho phù hợp với bối cảnh mới. Code clsCombo không phải sửa. Nếu đặt code thực thi trong clsCombo thì trong bối cảnh mới phải chỉnh sửa clsCombo.

Trong DoComboDblClick hiện thời code sẽ xóa nếu là 2 ComboBox cb2 hoặc cb3. Không xóa cb1 và cb4. Đó chỉ là ví dụ. Có thể làm nhiều việc tùy theo tập tin, bối cảnh. Lúc đó chỉ phải chỉnh sửa DoComboDblClick, không "đụng vào" clsCombo.

Toàn bộ code chỉ là ví dụ. Tùy theo nhu cầu mà chỉnh sửa.

1. Code Module1
Mã:
Option Explicit

Sub Button1_Click()
    UserForm1.Show
End Sub

Sub DoComboDblClick(ctrl As MSForms.ComboBox)
    If ctrl.name = "cb2" Or ctrl.name = "cb3" Then ctrl.ListIndex = -1
End Sub

2. Code trong UserForm
Mã:
Option Explicit

Private combos() As New clsCombo

Private Sub UserForm_Initialize()
Dim k As Long, lastRow As Long
    ReDim combos(1 To 4)
    For k = 1 To 4
        combos(k).Create Frame1, "cb" & k, "DoComboDblClick", RGB(211, 240, 224), 6, 6 + (k - 1) * 24, 100, 18
        With ThisWorkbook.Worksheets("Sheet1")
            lastRow = .Cells(Rows.Count, k).End(xlUp).Row
            If lastRow = 2 Then
                combos(k).ComboBox.AddItem .Cells(2, k).Value
            ElseIf lastRow > 2 Then
                combos(k).ComboBox.List = .Cells(2, k).Resize(lastRow - 1).Value
            End If
        End With
    Next
End Sub

Private Sub UserForm_Terminate()
    Erase combos
End Sub

3. Code trong clsCombo
Mã:
Option Explicit

Private WithEvents ctrl As MSForms.ComboBox
Private strMacro As String

Private Sub Class_Terminate()
    Set ctrl = Nothing
End Sub

Property Get ComboBox() As MSForms.ComboBox
    Set ComboBox = ctrl
End Property

Property Set ComboBox(ctl As MSForms.ComboBox)
    Set ctrl = ctl
End Property

Public Sub Create(parent As Object, ByVal name As String, ByVal macro As String, ByVal color As Long, _
    ByVal left As Single, ByVal top As Single, ByVal width As Single, ByVal height As Single)
On Error Resume Next
    Set ctrl = parent.Controls.Add("Forms.ComboBox.1")
    If Not ctrl Is Nothing Then
        strMacro = macro
        With ctrl
            .name = name
            .BackColor = color
            .Font.name = "Times New Roman"
            .Font.Size = 12
            If left > 0 Then .left = left
            If top > 0 Then .top = top
            If width > 0 Then .width = width
            If height > 0 Then .height = height
        End With
    End If
End Sub

Private Sub ctrl_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
    On Error Resume Next
    If strMacro <> vbNullString Then Application.Run strMacro, ctrl
End Sub
 

File đính kèm

  • Book1.xlsb
    24.2 KB · Đọc: 24
Dear [U]batman1,[/U]

Cám ơn đã hỗ trợ minh cho case này.

Tuy nhiên, Tuấn đã làm theo code của anh đưa nhưng vẫn chưa được, không biết sai ở chỗ nào.

1. Áp dụng nguyên file a sửa thì ok, nhưng lại khó hiếu so với file của Tuấn. Vì hiện tại số lượng Comboxbox có 4 cái cho dễ hình dung, chứ trên thực thế số lượng combobox là tùy biến.
2. Combobox này không chỉ load dữ liệu từ sheet mà có thể từ các combobox khác.
3. Vấn đề làm sao với file (mẫu) này, chỉ cần double click vào là sẽ xóa (trên nền code đã tạo ra các combobox này).

Tuấn gởi lại file nhờ anh chỉnh sửa lại giúp
 

File đính kèm

  • Book1_3.xlsb
    18.9 KB · Đọc: 13
1. Áp dụng nguyên file a sửa thì ok, nhưng lại khó hiếu so với file của Tuấn. Vì hiện tại số lượng Comboxbox có 4 cái cho dễ hình dung, chứ trên thực thế số lượng combobox là tùy biến.
Tôi tạo 4 nút vì đấy là ví dụ. Muốn tạo bao nhiêu thì chỉnh sửa thôi. Vd. muốn tạo 100 thì sửa 4 trong
Mã:
ReDim combos(1 To 4)
    For k = 1 To 4
thành 100. Thế thôi.
2. Combobox này không chỉ load dữ liệu từ sheet mà có thể từ các combobox khác.
Tôi cho vd. nhập vào combobox vì trong code của bạn không có. Chả nhẽ làm việc với 4 combobox rỗng? Còn việc bạn không nhập từ sheet hoặc cách nhập khác thì thay đoạn nhập của tôi bằng đoạn nhập của mình.
Tuy nhiên, Tuấn đã làm theo code của anh đưa nhưng vẫn chưa được, không biết sai ở chỗ nào.
Bạn có
Mã:
Sub DoComboDblClick(nut As MSForms.ComboBox)
For i = 1 To 4
nut.ListIndex = -1
Next
End Sub

Của tôi là
Mã:
Sub DoComboDblClick(ctrl As MSForms.ComboBox)
    If ctrl.name = "cb2" Or ctrl.name = "cb3" Then ctrl.ListIndex = -1
End Sub

Tôi hiểu là đúp chuột vào combobox nào thì xóa combobox đó, các combobox khác không xóa. Cái combobox vừa được đúp chuột chính là ctrl được "dâng" bởi đối tượng được tạo từ lớp clsCombo. Vậy nếu muốn xóa combobox được đúp chuột bất luận nó là "ai" thì đơn giản là
Mã:
Sub DoComboDblClick(ctrl As MSForms.ComboBox)
    ctrl.ListIndex = -1
End Sub

Chắc chắn bạn không làm theo code của tôi.

Để làm cái việc bạn định làm thì clsCombo phải y hệt như tôi đã viết. Bạn xem lại clsCombo của mình.

Tóm lại bạn chả hiểu gì cả. Không hiểu được triết lý.

-Trong module Form của tôi có Private combos() As New clsCombo. Đó là mảng các đối tượng được tạo trên cơ sở lớp clsCombo. Bạn nhìn trong code của mình có Private combos() As New clsCombo không?

- trong Initialize code gọi phương thức Create của đối tượng lớp clsCombo để tạo combobox. Lớp clsCombo của bạn làm quái gì có phương thức Create?

- nếu bạn tự tạo combobox trong Initialize thì nó có dính dáng gì tới đối tượng lớp clsCombo đâu.

Tóm lại thì với việc của bạn thì phải có clsCombo y như tôi đã làm cho bạn.

Trong Initialize nếu bạn muốn tạo 100 combobox thì bạn phải tạo 100 đối tượng lớp clsCombo. Với mỗi đối tượng lớp clsCombo, tức combos(k) trong ví dụ của tôi, bạn phải gọi phương thức Create của nó để tạo combobox - combos(k).Create ... Bạn phải cung cấp parent của combobox cần tạo (trong vd. là Frame1), tên cho combobox, tên macro mà đối tượng lớp clsCombo sẽ gọi khi combobox được đúp chuột, mầu, top, left, width, height của combobox cần tạo. Nếu bạn muốn nhập danh sách cho combobox vừa tạo thì trước hết phải truy cập, phải có combobox đó. combos(k).ComboBox trả về control ComboBox trong đối tượng lớp clsCombo là combos(k). Có control combobox rồi thì gọi các phương thức của nó để nhập danh sách thôi. Kể từ lúc này khi combobox nào được đúp chuột thì đối tượng lớp clsCombo tương ứng sẽ thực thi code của Sub ctrl_DblClick (trong lớp clsCombo). Code của Sub ctrl_DblClick sẽ gọi macro mà bạn cung cấp khi gọi CREATE, và được ghi nhớ trong trường (chuỗi) strMacro của đối tượng. Do bạn cung cấp macro "DoComboDblClick" (strMacro = "DoComboDblClick") nên macro đó sẽ được gọi thông qua Application.Run. Và đồng thời combobox vừa được đúp chuột sẽ được truyền vào macro ở dạng tham số. Trong
Mã:
Sub DoComboDblClick(ctrl As MSForms.ComboBox)
    
End Sub
thì viết code để xử lý thôi. Trong yêu cầu của bạn thì có ctrl là combobox vừa được đúp chuột, vậy thì xóa nó thôi. Tức code xử lý chỉ là ctrl.ListIndex = -1

Hướng dẫn thế là quá đủ. ̣đừng xóa, chỉnh sửa clsCombo, và tạo các combobox theo kiểu của mình rồi nói là làm y theo tôi hướng dẫn nhé.
3. Vấn đề làm sao với file (mẫu) này, chỉ cần double click vào là sẽ xóa (trên nền code đã tạo ra các combobox này).

Tuấn gởi lại file nhờ anh chỉnh sửa lại giúp
Nếu vẫn không hiểu thì:
- lấy nguyên tập tin của tôi.

- sửa 4 thành 100 hay số tùy ý

- trong Sub DoComboDblClick thay
Mã:
If ctrl.name = "cb2" Or ctrl.name = "cb3" Then ctrl.ListIndex = -1
bằng
Mã:
ctrl.ListIndex = -1
 
Rất cám ơn [U]batman1[/U] đã có nhận xét rất đúng và hướng dẫn cụ thể.

Excell VBA tuấn tự tìm hiểu và làm nên về cấu trúc và ngữ pháp sẽ không hiểu. Càng đi sâu vô cái VBA này càng thấy lợi hại, làm cho dung lượng excel nhẹ đi mà làm được nhiều thứ việc.

  • Còn về tại sao combobox lại trống: nguyên nhân là tuấn thay combobox cho texbox vì combobox có khả năng tìm kiếm được, DropDown dữ liệu từ sheet.
  • Theo như batman1 hướng dẫn chi tiết, thì combobox luôn PHẢI ĐƯỢC NẠP dữ liệu trước và cùng với lúc khỏi tạo chương trình.
  • Trường hợp ý tuấn ghi là combobox không phải cái nào cũng có dự liệu trước, mà dự liệu sẽ được them vào tùy yêu cầu.
Tuấn đã sửa lại theo đúng batman1 hướng dẫn, chỉ bỏ qua phần khởi tạo dư liệu vào thì lệnh không thực hiện được, còn nếu để nguyên thì chạy.

Khó hiểu ở chỗ này, sửa hoài không được.
Bài đã được tự động gộp:

ok rồi, ở double click thay bang ctrl.Value = "" thì chạy.

Cám ơn anh nhiều.
 
Lần chỉnh sửa cuối:
Tôi tạo 4 nút vì đấy là ví dụ. Muốn tạo bao nhiêu thì chỉnh sửa thôi. Vd. muốn tạo 100 thì sửa 4 trong
Mã:
ReDim combos(1 To 4)
    For k = 1 To 4
thành 100. Thế thôi.

Tôi cho vd. nhập vào combobox vì trong code của bạn không có. Chả nhẽ làm việc với 4 combobox rỗng? Còn việc bạn không nhập từ sheet hoặc cách nhập khác thì thay đoạn nhập của tôi bằng đoạn nhập của mình.

Bạn có
Mã:
Sub DoComboDblClick(nut As MSForms.ComboBox)
For i = 1 To 4
nut.ListIndex = -1
Next
End Sub

Của tôi là
Mã:
Sub DoComboDblClick(ctrl As MSForms.ComboBox)
    If ctrl.name = "cb2" Or ctrl.name = "cb3" Then ctrl.ListIndex = -1
End Sub

Tôi hiểu là đúp chuột vào combobox nào thì xóa combobox đó, các combobox khác không xóa. Cái combobox vừa được đúp chuột chính là ctrl được "dâng" bởi đối tượng được tạo từ lớp clsCombo. Vậy nếu muốn xóa combobox được đúp chuột bất luận nó là "ai" thì đơn giản là
Mã:
Sub DoComboDblClick(ctrl As MSForms.ComboBox)
    ctrl.ListIndex = -1
End Sub

Chắc chắn bạn không làm theo code của tôi.

Để làm cái việc bạn định làm thì clsCombo phải y hệt như tôi đã viết. Bạn xem lại clsCombo của mình.

Tóm lại bạn chả hiểu gì cả. Không hiểu được triết lý.

-Trong module Form của tôi có Private combos() As New clsCombo. Đó là mảng các đối tượng được tạo trên cơ sở lớp clsCombo. Bạn nhìn trong code của mình có Private combos() As New clsCombo không?

- trong Initialize code gọi phương thức Create của đối tượng lớp clsCombo để tạo combobox. Lớp clsCombo của bạn làm quái gì có phương thức Create?

- nếu bạn tự tạo combobox trong Initialize thì nó có dính dáng gì tới đối tượng lớp clsCombo đâu.

Tóm lại thì với việc của bạn thì phải có clsCombo y như tôi đã làm cho bạn.

Trong Initialize nếu bạn muốn tạo 100 combobox thì bạn phải tạo 100 đối tượng lớp clsCombo. Với mỗi đối tượng lớp clsCombo, tức combos(k) trong ví dụ của tôi, bạn phải gọi phương thức Create của nó để tạo combobox - combos(k).Create ... Bạn phải cung cấp parent của combobox cần tạo (trong vd. là Frame1), tên cho combobox, tên macro mà đối tượng lớp clsCombo sẽ gọi khi combobox được đúp chuột, mầu, top, left, width, height của combobox cần tạo. Nếu bạn muốn nhập danh sách cho combobox vừa tạo thì trước hết phải truy cập, phải có combobox đó. combos(k).ComboBox trả về control ComboBox trong đối tượng lớp clsCombo là combos(k). Có control combobox rồi thì gọi các phương thức của nó để nhập danh sách thôi. Kể từ lúc này khi combobox nào được đúp chuột thì đối tượng lớp clsCombo tương ứng sẽ thực thi code của Sub ctrl_DblClick (trong lớp clsCombo). Code của Sub ctrl_DblClick sẽ gọi macro mà bạn cung cấp khi gọi CREATE, và được ghi nhớ trong trường (chuỗi) strMacro của đối tượng. Do bạn cung cấp macro "DoComboDblClick" (strMacro = "DoComboDblClick") nên macro đó sẽ được gọi thông qua Application.Run. Và đồng thời combobox vừa được đúp chuột sẽ được truyền vào macro ở dạng tham số. Trong
Mã:
Sub DoComboDblClick(ctrl As MSForms.ComboBox)
   
End Sub
thì viết code để xử lý thôi. Trong yêu cầu của bạn thì có ctrl là combobox vừa được đúp chuột, vậy thì xóa nó thôi. Tức code xử lý chỉ là ctrl.ListIndex = -1

Hướng dẫn thế là quá đủ. ̣đừng xóa, chỉnh sửa clsCombo, và tạo các combobox theo kiểu của mình rồi nói là làm y theo tôi hướng dẫn nhé.

Nếu vẫn không hiểu thì:
- lấy nguyên tập tin của tôi.

- sửa 4 thành 100 hay số tùy ý

- trong Sub DoComboDblClick thay
Mã:
If ctrl.name = "cb2" Or ctrl.name = "cb3" Then ctrl.ListIndex = -1
bằng
Mã:
ctrl.ListIndex = -1
Bác chịu khó và hiểu nhanh thật
Tôi thì thấy:
Đã là combo box thì sao lại xóa - chỉ cần chọn lại là xong
Hơn nữa người trình bày cứ loằng ngoằng, giờ có code của bác cũng không áp dụng mà dựng code mới rồi kêu không được, lạ thật (mà không được gì cũng không hiểu luôn)
 
  • Theo như batman1 hướng dẫn chi tiết, thì combobox luôn PHẢI ĐƯỢC NẠP dữ liệu trước và cùng với lúc khỏi tạo chương trình.
Tôi nhập danh sách cho combobox vì thấy để trống combobox thì hơi lạ. Không ngờ bạn chỉ cần phần Edit của combobox.

Nhưng tôi chưa bao giờ viết là
combobox luôn PHẢI ĐƯỢC NẠP dữ liệu trước

Tôi viết
Nếu bạn muốn nhập danh sách cho combobox vừa tạo thì trước hết phải truy cập, phải có combobox đó. combos(k).ComboBox trả về control ComboBox trong đối tượng lớp clsCombo là combos(k)

Bạn hiểu NẾU BẠN MUỐN là gì không?
 
Web KT
Back
Top Bottom