[英]Using the .Find Function VBA - not returning the first value
我已经为较大的程序编写了代码摘录,以测试概念验证。 (因此,代码很少。)主代码背后的想法是,用户使用带有复选框的Custom UserForm生成数组,然后在数组中搜索所有提及的“ 1”,即当复选框包含被选中。 然后,使用数组的行号基于所选的复选框来加载一系列额外的用户窗体。 我想象有更简单的方法可以做到这一点,但这是我选择的方法,我在VBA方面的编码经验非常有限!
我已附上了所生成数组的示例。
当我运行代码时,除单元格(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
使用您的代码:
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
参数如何, 它总是会正确返回 。 如果有多个值,它将返回找到的第一个值。
因此,在上面的代码中,由于使用了.Find()
之后 ,按以下顺序搜索单元格:
B1> B2> B3> B4> B5
如果没有After,则序列如下:
B2> B3> B4> B5> B1
为了更好地说明,假设您有两个不同的范围,如下所示:
使用左侧代码,如果您搜索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
才能从第一个单元格获取值。如果尝试这样做,则会在即时窗口中显示2
和1
。
这几乎就是为什么我决定在某个时候决定使用一种缓慢的方法,该方法只是在范围内循环并检查值,而不是内置 到LastThings的 .Find()
GitHub链接 。
我认为一切都发生在一张纸上。 它适用于您提供的数据。
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
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.