Hỏi về phương thức Find và sự kiện ấn phím.

Liên hệ QC

ptlong04x1

Thành viên tích cực
Tham gia
15/10/08
Bài viết
1,031
Được thích
1,531
Nghề nghiệp
Kỹ sư xây dựng
Mình có 2 câu hỏi về code như sau :

1. Mình copy đoạn code này về phương thức Find từ Help của VBE, chạy cho ra kết quả bình thường, nhưng kết thúc thì báo lỗi (file đính kèm).

PHP:
Sub Re()
    With Worksheets(1).Range("a1:a500")
        Set c = .Find(2, LookIn:=xlValues)
        If Not c Is Nothing Then
            firstAddress = c.Address
            Do
                c.Value = 5
                Set c = .FindNext(c)
            Loop While Not c Is Nothing And c.Address <> firstAddress
        End If
    End With
End Sub
2. Mình có đoạn code sau :

PHP:
Sub Chay()
    Do
        i = i + 1
    Loop Until ...???
    MsgBox i
End Sub
Mình muốn nhấn tổ hợp phím nào đó (Vd : Ctrl Shift K, hoặc là nhấn 1 nút bất kỳ trên bàn phím như là Keypressed trong Pascal) thì code ngừng chạy và hiện Msgbox.

Xin mọi người giúp đỡ. Xin cảm ơn!
 

File đính kèm

1. Lỗi ở đây
PHP:
c.Address
Khi tất các số 2 đã được thay thế bằng số 5 thì Find sẽ không tìm thấy nữa, lúc này biến c rỗng, c.Address sẽ gây ra lỗi. Bỏ cái c.Address đi, chỉ cần như thế này là đủ:
PHP:
Loop While Not c Is Nothing
2. Tôi nghĩ là không thể can thiệp khi Macro đang chạy đâu.
 
Upvote 0
Khi tất các số 2 đã được thay thế bằng số 5 thì Find sẽ không tìm thấy nữa, lúc này biến c rỗng, c.Address sẽ gây ra lỗi. Bỏ cái c.Address đi, chỉ cần như thế này là đủ:
PHP:
Loop While Not c Is Nothing

Mình lấy đoạn này từ Help của VBE về phương thức FindNext :
When the search reaches the end of the specified search range, it wraps around to the beginning of the range. To stop a search when this wraparound occurs, save the address of the first found cell, and then test each successive found-cell address against this saved address.
Nếu đúng như nó nói thì sau khi tìm hết vùng được chỉ ra nó sẽ quay lại tìm từ đầu (vì có Set c = .FindNext(c)) và gặp lại cell tìm thấy đầu tiên first found cell, nếu đúng như thế thì dòng c.Address <> firstAddress là cần thiết. Vậy mà lại báo lỗi, híc không lẽ Help lại sai hả trời.
 
Upvote 0
Muốn bắt được sự kiện thì phải được hỗ trợ KeyCode, Shift, KeyAscii trong một số đối tượng đặc biệt, bạn có chuyển thủ tục vào Form và sử dụng như kiểu dưới:

Mã:
Private Sub UserForm_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    MsgBox KeyCode
End Sub

Private Sub UserForm_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    MsgBox KeyAscii
End Sub
 
Upvote 0
Mình lấy đoạn này từ Help của VBE về phương thức FindNext :
Nếu đúng như nó nói thì sau khi tìm hết vùng được chỉ ra nó sẽ quay lại tìm từ đầu (vì có Set c = .FindNext(c)) và gặp lại cell tìm thấy đầu tiên first found cell, nếu đúng như thế thì dòng c.Address <> firstAddress là cần thiết. Vậy mà lại báo lỗi, híc không lẽ Help lại sai hả trời.
Trong trường hợp bạn không sửa dữ liệu. Khi FindNext, tìm hết dữ liệu nó sẽ tìm lại từ đầu và sẽ lặp lại quá trình tìm kiếm. Lúc bắt đầu lặp lại quá trình tìm kiếm sẽ tìm lại ô đầu tiên. Dùng địa chỉ ô này làm dấu hiệu để dừng vòng lặp là hợp lý. Nhưng khi bạn tìm và sửa dữ liệu thì khác, khi tìm và sửa hết dữ liệu cần tìm thì Find sẽ không tìm thấy nữa. Lúc đó .Address sẽ gây ra lỗi.

Không biết do Microsoft sơ xuất vì một lý do gì mà đưa ra ví dụ đó??!
 
Lần chỉnh sửa cuối:
Upvote 0
Chuyển đổi thứ tự giữa 2 dòng lệnh là OK;

PHP:
Sub TimVaDiet()
   Dim Rng As Range, MyAdd As String
    With Worksheets("DSach").Range("a23:a58")
        Set Rng = .Find(2, LookIn:=xlValues)
        If Not Rng Is Nothing Then
            MyAdd = Rng.Address
            Do
               Rng.Interior.ColorIndex = 39
                Set Rng = .FindNext(Rng)  '<='
                Rng.Value = 5    '<='
            Loop While Not Rng Is Nothing And Rng.Address <> MyAdd
        End If
    End With
End Sub

http://giaiphapexcel.com/forum/showthread.php?t=15116
 
Upvote 0
Lổi này rất tinh vi... nếu ai "cày" nhiều với Find method mới phát hiện được
Tóm lại: c vẫn còn tồn tại thì dù FindNext(c) không tồn tại vẫn không báo lổi
Chính vì lẽ đó, làm như sư phụ SA_DQ là hợp lý nhất:
- Set c = .FindNext(c) trước
- Sau đó mới gán value cho c
 
Upvote 0
Muốn bắt được sự kiện thì phải được hỗ trợ KeyCode, Shift, KeyAscii trong một số đối tượng đặc biệt, bạn có chuyển thủ tục vào Form và sử dụng như kiểu dưới:

Mã:
Private Sub UserForm_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    MsgBox KeyCode
End Sub

Private Sub UserForm_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
    MsgBox KeyAscii
End Sub

PHP:
Sub Chay()
    Do
        i = i + 1
    Loop Until ...???  <-- thắc mắc chỗ này, Until có phím nào đó được nhấn thì dừng lặp
    MsgBox i
End Sub
Ý em là thế này : em muốn dừng Do...Loop, thông thường mình đưa ra điều kiện của i, VD : Until i = 100 thì dừng lặp, nhưng ở đây em muốn là Until "Nhấn phím gì đó" thì dừng lặp. Em nhớ trong Pascal có cách là Until Keypressed, còn trong biết trong VBE thì thế nào?
 
Upvote 0
PHP:
Sub Chay()
    Do
        i = i + 1
    Loop Until ...???  <-- thắc mắc chỗ này, Until có phím nào đó được nhấn thì dừng lặp
    MsgBox i
End Sub
Ý em là thế này : em muốn dừng Do...Loop, thông thường mình đưa ra điều kiện của i, VD : Until i = 100 thì dừng lặp, nhưng ở đây em muốn là Until "Nhấn phím gì đó" thì dừng lặp. Em nhớ trong Pascal có cách là Until Keypressed, còn trong biết trong VBE thì thế nào?
Thay vì cố gắng đi tìm cái Keypress gì đó mà theo tôi là khó có thể thực hiện được, sao bạn không trình bày toàn bộ ý tưởng ---> Biết đâu mọi người có cách khác tốt hơn
 
Upvote 0
Web KT

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

Back
Top Bottom