使用.Find函数VBA - 不返回第一个值

时间:2017-12-22 09:20:12

标签: excel vba excel-vba

我已经编写了一个代码摘录,用于测试概念验证的大型程序。 (因此少量代码。)主代码背后的想法是让用户使用带有复选框的自定义用户窗体生成数组,然后在数组中搜索所有提及的“1”,即当复选框有被选中。然后使用数组的行号加载一系列额外的UserForms,基于哪些复选框被选中。我想有更简单的方法可以做到这一点,但这是我选择的方法,我对VBA的编码经验相当有限!

我附上了生成的数组示例。

An test example of arrey generated by the main code

当我运行代码时,除了大​​小写之外,它就像inteneded一样工作 细胞(1,2)= 1

任何人都可以发现为什么会这样,我现在一直在努力解决这个问题。

Sub Array_Finder()

    Dim StartFinder As String
    Dim StartFinderZero As String
    Dim StartFinderCheck As String

    i = 4 : j = 1
    StartFinderZero = 0 : StartFinderCheck = i + 2
    For StartFinderTest = 1 To i + 1
        StartFinder = StartFinderZero + 1
        If StartFinderCheck > StartFinder Then
            StartFinderZero = Range(Cells(StartFinder, 2), Cells(i + 1, 2)).Find _
                (What:="1", after:=Cells(StartFinder, 2), searchdirection:=xlNext).Row
            Cells(StartFinderTest, 3) = StartFinderZero
        Else
            MsgBox ("here")
            Exit For
        End If
    Next StartFinderTest
End Sub

2 个答案:

答案 0 :(得分:3)

使用您的代码:

Sub ArrayFinder()

    Dim StartFinder As Long
    Dim StartFinderZero As String
    Dim StartFinderCheck As String
    i = 4: j = 1
    StartFinderZero = 0: StartFinderCheck = i + 2

    For StartFinderTest = 1 To i + 1
        StartFinder = StartFinderZero + 1
        If StartFinderCheck > StartFinder Then    
            With Range(Cells(StartFinder, 2), Cells(i + 1, 2))
                Debug.Print "row" & vbTab & .Cells(.Cells.Count).Row
                Debug.Print "address" & vbTab & .Address
                Debug.Print "after"; vbTab & .Cells(.Cells.Count).Address
                StartFinderZero = .Find(1, after:=.Cells(.Cells.Count)).Row
            End With    
            Cells(StartFinderTest, 3) = StartFinderZero
        Else
            Debug.Print "here"
            Exit For
        End If
    Next StartFinderTest

End Sub

这是你在即时窗口得到的:

row 5
address $B$1:$B$5
after    $B$5
row 5
address $B$2:$B$5
after    $B$5

诀窍是以下(来自MSDN的After参数):

您希望搜索开始的单元格。这对应于从用户界面进行搜索时活动单元的位置。请注意,After必须是范围内的单个单元格。请记住,搜索在此单元格之后开始; 指定的单元格不会被搜索,直到该方法回绕到此单元格。如果不指定此参数,则搜索范围左上角的单元格后开始搜索。

因此,您可以将最后一个单元格作为开头。它知道它应该从之后开始。因此,它理论上没有更好的事情可做,只是从范围的开始开始。 After参数的想法是设置要检查的最后一个值。 因此,如果我们只有一个值,它总是正确返回 ,无论After参数如何。如果有多个值,则返回它找到的第一个值。

因此,在上面的代码中,由于 After 的使用,.Find()按以下顺序搜索单元格:

B1> B2> B3> B4> B5

如果没有 After ,则序列如下:

B2> B3> B4> B5> B1

为了更好地说明,假设您有两个不同的范围:

enter image description here

使用左边的那个,如果你搜索1的行,即使没有选择after参数,你也总是没问题,使用这个代码:

Sub TestMe()
    Dim myR     As Range
    Dim myS     As Range
    Set myS = Range("B1:B5") 'change the range
    With myS
        Set myR = .Find(1)
        Debug.Print myR.Row
        Set myR = .Find(1, after:=.Cells(.Cells.Count))
        Debug.Print myR.Row
    End With
End Sub

右边的范围是棘手的,因为它也有1两次。因此,after是必须的,以便从第一个单元格中获取值。如果您尝试它,您将在即时窗口中显示21

而且这就是为什么在某些时候我决定使用一个慢速方法,它只是在范围内循环并检查值,而不是内置的.Find() GitHub link to LastThings

答案 1 :(得分:1)

我假设一切都发生在一张纸上。它适用于您提供的数据。

Sub MyAnswer()
    Dim lRow As Long ' Number of rows (or last row)
    Dim rngCheckBoxes As Range ' Range of values
    Dim vArr()
    ' Calculate last row
    lRow = ActiveSheet.Range("A" & ActiveSheet.Rows.Count).End(xlUp).Row
    ' Define range of checkboxes' numbers
    Set rngCheckBoxes = ActiveSheet.Range("A1","A" & lRow)
    ' Replace all zeroes with empty string
    rngCheckBoxes.Offset(0,1).Replace "0", "", xlWhole
    ' Put all values from defined range into array
    ' where according values from column next to it aren't blank
    vArr = rngCheckBoxes.Offset(0,1).SpecialCells(xlCellTypeConstants).Offset(0,-1).Value
    ' Insert array values into column "C"
    ActiveSheet.Range("C1").Resize(Ubound(vArr),1).Value = vArr
End Sub