Hỏi về phương thức Find, FindNext trong hàm tự tạo.

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ó đoạn code sau :

PHP:
Function TEST1(Bang As Range)
    Dim Tmp As Range
    With Bang
        Set Tmp = .Find(1, .Cells(.Count), xlValues, xlWhole)
        Set Tmp = .FindNext(Tmp)
    End With
    TEST1 = Tmp(, 2)
End Function

Sub TEST2()
    Dim Tmp As Range
    With Range("A1:A8")
        Set Tmp = .Find(1, .Cells(.Count), xlValues, xlWhole)
        Set Tmp = .FindNext(Tmp)
        MsgBox Tmp(, 2)
    End With
End Sub
Khi chạy thử thì thấy :

- Sub TEST2 chạy bình thường.

- Function TEST1 --> =TEST1(A1:A8) : bị lỗi (xin xem file đính kèm) :

Nếu bỏ đi dòng Set Tmp = .FindNext(Tmp) thì hàm lại chạy được.

* Mình muốn hỏi tại sao không dùng được phương thức Findnext ở đây. Mong mọi người giúp đỡ. Xin cảm ơn!
 

File đính kèm

Mình có đoạn code sau :

PHP:
Function TEST1(Bang As Range)
    Dim Tmp As Range
    With Bang
        Set Tmp = .Find(1, .Cells(.Count), xlValues, xlWhole)
        Set Tmp = .FindNext(Tmp)
    End With
    TEST1 = Tmp(, 2)
End Function

Sub TEST2()
    Dim Tmp As Range
    With Range("A1:A8")
        Set Tmp = .Find(1, .Cells(.Count), xlValues, xlWhole)
        Set Tmp = .FindNext(Tmp)
        MsgBox Tmp(, 2)
    End With
End Sub
Khi chạy thử thì thấy :

- Sub TEST2 chạy bình thường.

- Function TEST1 --> =TEST1(A1:A8) : bị lỗi (xin xem file đính kèm) :

Nếu bỏ đi dòng Set Tmp = .FindNext(Tmp) thì hàm lại chạy được.

* Mình muốn hỏi tại sao không dùng được phương thức Findnext ở đây. Mong mọi người giúp đỡ. Xin cảm ơn!
Tôi cũng từng nghiên cứu vấn đề này và cảm giác rằng không thể dùng FindNext trong 1 UDF để trả về 1 giá trị nào đó
Tuy nhiên, nếu bạn làm vầy thì được
PHP:
Function TEST1(Bang As Range) As Range
  Dim Tmp As Range
  With Bang
    Set Tmp = .Find(1, .Cells(.Count), xlValues, xlWhole)
    Set Tmp = .FindNext(Tmp)
  End With
  Set TEST1 = Tmp(, 2)
End Function
Tiếp theo ta kiểm tra tính chính xác của hàm bằng code sau:
PHP:
Sub ThiNghiem()
  MsgBox TEST1([A1:A8]).Value
End Sub
Theo dữ liệu trong file của bạn, kết quả nhận được là =5 ---> Đúng chứ?
 
Upvote 0
Sau đây là những ngâm cứu của mình về vấn đề này

Từ khi khai sinh ra topic: http://www.giaiphapexcel.com/forum/...ợp-về-phương-thức-tìm-kiếm-FIND-(-Find-Method)
mình đã nhắm đến hàm tự tạo dựa trên fương thức tìm kiếm. Nhưng cũng như bạn; Hàm chỉ đúng khi ta không dùng fương thức
FindNext hay FindPrevious

Ngoài ra mình còn fát hiện một số điều sau & muốn chia sẻ cùng bạn & những ai quan tâm:

(1) Dù có dòng lệnh
Set Tmp = .FindPrevious(Tmp)
hay Set Tmp = .FindNext(Tmp) thì khi thử hàm này trong cửa sổ Immediate vẫn không báo lỗi. Tuy nhiên nó chỉ cho ra 1 đáp án duy nhứt (nếu có nhiều đáp án) mà thôi.

Xin fép được dẫn ra ở ví dụ sau: Ta có trang tính:
| TT | Add | KQuả | Cú fáp |
|1| GPE 03| ||
|3| GPE 04| #VALUE!| =test1(A1:A9)|
|5| GPE 05| ||
|7| GPE 06| 3 |=test2(B1:B9)|
|3| GPE 07| GPE 04| =test2(B1:B9)|
|7| GPE 04| $B$3 |=test2(B1:B9)|
|5| GPE 09| ||
|2| GPE 01| ||

Ta thấy tại dòng thứ 3 ta bị báo lỗi khi dùng hàm có dòng Set Tmp = .FindPrevious(Tmp)

Nhưng trong CS Immediate ta nhập cú fáp ?Test1(Range("A1:A9")) & sau khi nhấn {ENTER} ta sẽ thu được
kết quả GPE 03

(2) Hàm mảng tự tạo vẫn đúng, một khi ta không dùng dòng lệnh FindNext(. . .) nêu trên, như hàm sau:

PHP:
Function Test2(Rng As Range)
 Dim sRng As Range:        ReDim MDL(1 To 3, 1 To 1)
 Set sRng = Rng.Find("04", , , xlPart)
 If Not sRng Is Nothing Then
   MDL(1, 1) = sRng.Offset(, -1).Value
   MDL(2, 1) = sRng.Value
   MDL(3, 1) = sRng.Address
 End If
 Test2 = MDL
End Function

(Kết quả hàm này thể hiện ở các dòng 5 ->7 của cột thứ 3
& Tất nhiên hàm mảng này không thử trong CS Trung gian được)


Có một vấn đề tế nhị xin fép được hỏi chủ Topic:
Nếu bạn đồng í ta đề nghị MOD hay SMOD gộp chung topic mà bạn đã khở tạo vô "Fương thức tìm kiếm trong VBA" nêu trên.
Xin lỗi, nếu việc này làm fật lòng bạn!
 
Upvote 0
Gữi bạn link tham khảo, trong đó người ta có nói rất rõ về việc dùng Find và FindNext
Find as a Function
Từ đây nếu có xây dựng UDF thì hãy "quên đi" FindNext nhé
Nếu có nhu cầu, nên dùng giống như người ta đã dùng: Set myResult = .Find(myResult, After:=myResult)
Ăn tiền ở chổ After ấy!
 
Upvote 0
Em thử dùng find next vào việc cập nhật thanh toán hóa đơn nhưng không được
PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
     
            If Target.Address = "$G$2" And Target.Offset(, -2) <> "" Then
                
                With ActiveSheet.Range(Sheet1.[E5], ActiveSheet.[E65500].End(xlUp))
                     Dim RngInv As Range
                     Set RngInv = ActiveSheet.Range(ActiveSheet.[E5], ActiveSheet.[E65000].End(xlUp))
                     Qty = Dem(RngInv, ActiveSheet.[E1])
                     For i = 1 To Qty
                            
                            Set RngInv = .Find(What:=ActiveSheet.Cells(1, i), After:=ActiveCell)
                            Set RngInv = .FindNext(After:=ActiveCell)

                            If Not RngInv Is Nothing Then
                            
                                    RngInv.Offset(, 2) = ActiveSheet.[G2]
                                    RngInv.Offset(, 1) = ActiveSheet.[E2]
                            
                            Else
                               MsgBox "khong tim thay so hoa don"
                            End If
                            
                         
                     Next
                End With
            End If

End Sub
 

File đính kèm

Upvote 0
Bạn chưa đúng trình tự của fương thức FINDNext()

PHP:
 Dim MyAdd As String 
 '. . . . '
   For i = 1 To Qty
    Set RngInv = .Find(What:=ActiveSheet.Cells(1, i), After:=ActiveCell)
    If Not RngInv Is Nothing Then
       MyAdd = RngInv.AddRess                 'Ghi Đ/Chỉ Tìm Thấy Lần Đầu, Để Sau Này Thoát Vòng Lặp'
       Do                          
          RngInv.Offset(, 2) = ActiveSheet.[G2]
          RngInv.Offset(, 1) = ActiveSheet.[E2]
          Set RngInv = .FindNext(RngInv)                   
       Loop While Not RngInv Is Nothing And MyAdd<> RngInv.Address               
     Else
          MsgBox "khong tim thay so hoa don"
     End If                                          
  Next i     
'. . . . . . '
 
Upvote 0
Em thử dùng find next vào việc cập nhật thanh toán hóa đơn nhưng không được
PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
     
            If Target.Address = "$G$2" And Target.Offset(, -2) <> "" Then
                
                With ActiveSheet.Range(Sheet1.[E5], ActiveSheet.[E65500].End(xlUp))
                     Dim RngInv As Range
                     Set RngInv = ActiveSheet.Range(ActiveSheet.[E5], ActiveSheet.[E65000].End(xlUp))
                     Qty = Dem(RngInv, ActiveSheet.[E1])
                     For i = 1 To Qty
                            
                            Set RngInv = .Find(What:=ActiveSheet.Cells(1, i), After:=ActiveCell)
                            Set RngInv = .FindNext(After:=ActiveCell)

                            If Not RngInv Is Nothing Then
                            
                                    RngInv.Offset(, 2) = ActiveSheet.[G2]
                                    RngInv.Offset(, 1) = ActiveSheet.[E2]
                            
                            Else
                               MsgBox "khong tim thay so hoa don"
                            End If
                            
                         
                     Next
                End With
            End If

End Sub
Sai cả 1 rổ luôn (ngay từ cái hàm Dem đã sai)
Sửa thành vầy:
PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
  Dim fRng As Range, firstAdd As String, Shd As String, Ntt As Long
  On Error GoTo ExitSub
  If Target.Address = "$G$2" And Target.Value <> "" Then
    If Target.Offset(, -2).Value <> "" Then
      Shd = Range("E1").Value
      Ntt = Range("E2").Value
      With Range([E4], [E65500].End(xlUp))
        Set fRng = .Find(Shd, , xlValues, xlWhole)
        If Not fRng Is Nothing Then
          firstAdd = fRng.Address
          Do
            fRng.Offset(, 1) = Ntt
            fRng.Offset(, 2) = Target.Value
            Set fRng = .FindNext(fRng)
          Loop Until fRng.Address = firstAdd
        End If
      End With
    End If
  End If
ExitSub:
End Sub
 
Lần chỉnh sửa cuối:
Upvote 0
Hay quá, em lại học thêm được Do..Loop qua ví dụ này
và hay là mình cho nó lặp về bằng địa chỉ tìm thấy ban đầu

Cám ơn 2 Anh NDU & ChanhTQ
 
Upvote 0
Hay quá, em lại học thêm được Do..Loop qua ví dụ này
và hay là mình cho nó lặp về bằng địa chỉ tìm thấy ban đầu

Cám ơn 2 Anh NDU & ChanhTQ
Gợi ý chút: Với bài toán liên quan đến FindNext, bạn chỉ cần bôi đen chữ FindNext trong cửa số VBA rồi bấm F1, sẽ có ngay câu trả lời + Ví dụ minh họa
(tôi cũng viết code dựa vào ví dụ ấy thôi)
 
Upvote 0
PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
  Dim fRng As Range, firstAdd As String, Shd As String, Ntt As Long
  On Error GoTo ExitSub
  If Target.Address = "$G$2" And Target.Value <> "" Then
    If Target.Offset(, -2).Value <> "" Then
      Shd = Range("E1").Value
      Ntt = Range("E2").Value
      With Range([E4], [E65500].End(xlUp))
        Set fRng = .Find(Shd, , xlValues, xlWhole)
        If Not fRng Is Nothing Then
          firstAdd = fRng.Address
          Do
            fRng.Offset(, 1) = Ntt
            fRng.Offset(, 2) = Target.Value
            Set fRng = .FindNext(fRng)
          Loop Until fRng.Address = firstAdd
        End If
      End With
    End If
  End If
ExitSub:
End Sub

Cũng đoạn code này
fRng.Offset(, 2) đã có dữ liệu rồi thì bỏ qua mình sửa code như nào
Em lồng thêm if vào nhưng không được
ìf
fRng.Offset(, 2) <> "" then
Do
...

 
Upvote 0
PHP:
Private Sub Worksheet_Change(ByVal Target As Range)
  Dim fRng As Range, firstAdd As String, Shd As String, Ntt As Long
  On Error GoTo ExitSub
  If Target.Address = "$G$2" And Target.Value <> "" Then
    If Target.Offset(, -2).Value <> "" Then
      Shd = Range("E1").Value
      Ntt = Range("E2").Value
      With Range([E4], [E65500].End(xlUp))
        Set fRng = .Find(Shd, , xlValues, xlWhole)
        If Not fRng Is Nothing Then
          firstAdd = fRng.Address
          Do
            fRng.Offset(, 1) = Ntt
            fRng.Offset(, 2) = Target.Value
            Set fRng = .FindNext(fRng)
          Loop Until fRng.Address = firstAdd
        End If
      End With
    End If
  End If
ExitSub:
End Sub

Cũng đoạn code này
fRng.Offset(, 2) đã có dữ liệu rồi thì bỏ qua mình sửa code như nào
Em lồng thêm if vào nhưng không được
ìf
fRng.Offset(, 2) <> "" then
Do
...

Vầy thôi:
If fRng.Offset(, 2).Value = "" then fRng.Offset(, 2).Value = Target.Value
 
Upvote 0
Web KT

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

Back
Top Bottom