excel VBA运行时错误“424”:需要对象

dly7yett  于 2022-12-30  发布在  其他
关注(0)|答案(3)|浏览(1155)

我正在尝试创建一个打印函数,它可以从一个长列表底部的范围中进行选择。宏可以工作,但在宏完成后,每次“需要对象”时都会给我一个错误。我不知道如何清理这个错误并防止错误发生。

Option Explicit
Sub SchedulePrint()

    Dim lRow As Range
    
Application.ScreenUpdating = False
    With Sheets("Line 3")

        Set lRow = Range("G1024").End(xlUp).Offset(-3, -6).Resize(20, 14).PrintOut
'The above is the line where I get the debug error message
    
    End With
Application.ScreenUpdating = True
End Sub
2lpgd968

2lpgd9681#

需要对象

这条线爆炸了:

Set lRow = Range("G1024").End(xlUp).Offset(-3, -6).Resize(20, 14).PrintOut

因为Range.PrintOut方法不返回任何内容(它是一个Sub,不是Function),所以实际上赋值语句的右边得到了求值,因为它是右边的一个副作用语句,所以副作用在表达式求值时发生(也就是说,你 * 确实 * 得到了一个打印输出)。这应该是一个编译时错误,但是VBA编译器将许多检查推迟到运行时,所以...
VBA然后获取RHS表达式的结果,并尝试执行Set lrow指令......但RHS没有生成任何对象引用,因此您会得到一个 * object required * 错误,因为当您在赋值的LHS上有Set xyz时,RHS * 必须 * 计算为对象引用。
解决办法是从赋值中删除副作用:

Set lRow = Range("G1024").End(xlUp).Offset(-3, -6).Resize(20, 14)

现在,RHS计算Range.Resize的结果,它是一个Range对象,因此,当此指令完成时,lrow持有对该Range的引用。
现在,另一条指令可以调用该Range对象的PrintOut方法:

lRow.PrintOut

但还有一个问题。

隐式ActiveSheet引用

这里有一个明确的意图:

With Sheets("Line 3")

看起来像是要处理一个名为Line 3的工作表,但是Range函数不是 * qualified *,所以它的行为会根据代码在项目中的编写位置而有所不同:

  • 在工作表模块中,Range指的是该工作表 * 上的单元格 * 区域。
  • 在任何其他模块类型中,Range指的是 * 无论活动工作表是什么 *。

因此,如果宏是在Line 3工作表的代码隐藏中编写的,则With块是多余的,因为未限定的Range调用总是将引用正确的工作表。通过使用Me进行限定,可以使隐式包含workhseet引用更加明确。也就是说,使用Me.Range(...)而不仅仅是Range。如果它是在另一个工作表的代码隐藏中编写的,那么代码就会产生误导,因为它 * 不是 * 在Line 3工作表上工作(相反,它引用了编写宏的任何工作表模块)。
如果宏是在任何其他模块中编写的,那么就有一个隐含的要求,即当宏运行时,Line 3也是ActiveSheet,否则就不会产生预期的结果。
错误的解决方法是在访问Range之前激活该特定工作表:

With Sheets("Line 3")
    .Activate
    Set lRow = Range(...)

这是错误的,因为With块仍然是无用的。* 正确 * 的修复方法是使用With块变量作为限定符-那么哪个工作表是活动的就不重要了:

With Sheets("Line 3")
    Set lRow = .Range(...)

类似地,Sheets隐式地引用了活动 * 工作簿 *,除非代码是在ThisWorkbook模块中编写的--在这种情况下,Sheets隐式地是Me.Sheets,如果我们知道我们在寻找Worksheet类型的工作表,我们应该使用Worksheets集合。Sheets(或Worksheets)不带限定符,表示 * 当前活动的任何工作簿 *-它可能是也可能不是包含宏的工作簿。使用ThisWorkbook.Worksheets("...")可从包含宏的工作簿中检索Worksheet
有关更多详细信息,请参见以下Rubberduck * 检查:

3qpi33ja

3qpi33ja2#

@freeflow和@vbasic2008说的都是正确的。由于您首先使用“With”语句选择了“第3行”工作表,因此下面的Range需要以句点开头,以便与所选工作表关联。
看起来好像您试图在运行PrintOut函数的同时设置范围“LROW”。由于PrintOut方法返回变量而不是Excel抛出的范围和错误。
如果你需要将lRow设置为一个范围,最好先设置lRow,然后在设置好之后再使用它。

Set lRow = .Range("G1024").End(xlUp).Offset(-3, -6).Resize(20, 14)
lRow.PrintOut

也可以完全避免设置lRow,而只调用打印输出函数

.Range("G1024").End(xlUp).Offset(-3, -6).Resize(20, 14).PrintOut
bmvo0sr5

bmvo0sr53#

在@Mathiedu_Guindon的基础上,我可以建议如下减少代码

Option Explicit

Sub SchedulePrint()
    
    Application.ScreenUpdating = False
    Sheets("Line 3").Range("G1024").End(xlUp).Offset(-3, -6).Resize(20, 14).PrintOut
    Application.ScreenUpdating = True

End Sub

相关问题