当使用 Application.Evaluate 或 ActiveSheet.Evaluate 方法调用例程时,我在子例程内运行查找循环时遇到一些问题。例如,在下面的代码中,我定义了一个子例程 FindSub(),它在工作表中搜索字符串“xxx”。例程 CallSub() 使用标准 Call 语句和 Evaluate 调用 FindSub() 例程。
当我运行 Call FindSub 时,一切都会按预期工作:每个匹配的地址都会打印到直接窗口中,并且当代码完成时我们会收到一条最终消息“Finished up”。但是,当我执行 Application.Evaluate "FindSub()"时,仅打印出第一个匹配的地址,并且我们永远不会到达“完成”消息。换句话说,当循环尝试评估是否应该继续时,在 Cells.FindNext 行之后遇到错误,并且程序执行停止而不会打印任何运行时错误。
在这种情况下,我希望 Call FindSub 和 Application.Evaluate "FindSub()"都能产生相同的结果。有人可以解释为什么他们不这样做,如果可能的话,有办法解决这个问题吗?谢谢。
注意:在这个例子中我显然不需要使用Evaluate。此版本经过简化,只关注我在更复杂的情况下遇到的特定问题。
Sub CallSub()
Call FindSub
Application.Evaluate "FindSub()"
End Sub
Sub FindSub()
Dim rngFoundCell As Range
Dim rngFirstCell As Range
Set rngFoundCell = Cells.Find(What:="xxx", after:=ActiveCell, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not rngFoundCell Is Nothing Then
Set rngFirstCell = rngFoundCell
Do
Debug.Print rngFoundCell.Address
Set rngFoundCell = Cells.FindNext(after:=rngFoundCell)
Loop Until (rngFoundCell Is Nothing) Or (rngFoundCell.Address = rngFirstCell.Address)
End If
Debug.Print "Finished up"
End Sub
最佳答案
原因很可能是 Evaluate 将您的函数视为 UDF - 就好像它是从工作表公式中调用的一样。 UDF 对它们可以执行的操作有严格的限制 - 特别是不能设置属性或调用其他函数 - 我想这里的某些内容已经违反了这些限制,尽管我无法准确地隔离这里所做的事情。
在 UDF 内,错误会被悄悄吞掉,因为工作表公式不允许引发 VB 错误。 (如果公式错误不断引发 VB 对话框,则会破坏 Excel 用户界面)
参见http://support.microsoft.com/kb/170787了解 UDF 限制的详细信息。
编辑:好的,这是对您的问题的一些澄清,我知道您的代码在评估过程中在哪里默默地出错。使用此代码:
Sub FindSub()
Dim rngFoundCell As Range
Dim rngFirstCell As Range
Set rngFoundCell = Cells.Find(What:="xxx", after:=ActiveCell, LookIn:=xlValues, _
LookAt:=xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, _
MatchCase:=False, SearchFormat:=False)
If Not rngFoundCell Is Nothing Then
Set rngFirstCell = rngFoundCell
Do
Debug.Print "FOUND: " & rngFoundCell.Address
Set rngFoundCell = Cells.FindNext(after:=rngFoundCell)
Debug.Print "FIND NEXT: " & IIf(rngFoundCell Is Nothing, " NOTHING", " SOMETHING")
Loop Until (rngFoundCell Is Nothing) Or (rngFoundCell.Address = rngFirstCell.Address)
Debug.Print "ESCAPED LOOP"
End If
Debug.Print "Finished up"
End Sub
我在立即窗口中得到以下输出:
findsub
FOUND: $G$6
FIND NEXT: SOMETHING
FOUND: $D$11
FIND NEXT: SOMETHING
ESCAPED LOOP
Finished up
太好了。但是:
callsub
FOUND: $G$6
FIND NEXT: SOMETHING
FOUND: $D$11
FIND NEXT: SOMETHING
ESCAPED LOOP
Finished up
FOUND: $G$6
FIND NEXT: NOTHING
这里有三件事值得注意,至少当我运行它时。
- 该函数被调用两次。这是 Evaluate 的一个已知问题,与 Excel 如何处理工作表上的计算有关。这就是为什么 Evaluate 永远不能用在记录数据的函数上 - 因为它可以在单个 Evaluate 中被多次调用。
- 在第二次循环中,“查找下一个”无法找到另一个单元格。这是一个谜,但 Evaluate 不应该真正用于运行在工作表中运行的函数,因此在某种程度上,这是未定义的行为,不能真正被视为错误。评估意味着运行一个公式,其中所有单元格引用都在公式中明确映射。我自己的理论是“查找下一个”不起作用,因为您尝试使用不是事件单元格的单元格引用,而“评估”则试图消除此类非法事件。
- 你的错误。在
Loop Until
行中,您处理 Or 测试。麻烦的是,如果rngFoundCell
为Nothing
,第二个测试将抛出错误; VBA 正在尝试处理完整表达式,在这种情况下无法计算rngFoundCell.Address
。当作为 UDF 运行时(即在 Evaluate 中),代码将立即退出,不会出现错误对话框。这就是为什么您在评估中看不到“已完成”的原因。
关于excel - 为什么从 Evaluate 调用时 VBA Find 循环失败?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2668090/