当你执行以下操作时:
Set r = Range("A1")
你实际上正在做的是这个:
您真正所做的是:
Dim r As Variant
Set r = Application.ActiveSheet.Range("A1")
所以,声明所有变量,并且在每个模块的顶部始终指定Option Explicit
- 这样VBA将拒绝编译使用未声明变量(或打字错误)的代码。并使用显式类型声明您的变量:
Dim r As Range
一个 Range
对象知道它所属的工作表,这就是为什么,正如你所注意到的那样,这个范围对于活动工作表有效。即使您激活另一个工作表(99.999% 的情况下您不需要这样做),它也会保留在该工作表上。
这就是为什么您不能这样做的原因:
Worksheets("Sheet42").r.Value = 1
因为r
不是Worksheet
对象的成员 - 它是一个指向非常具体的工作表地址的本地对象变量。现在,当您执行Worksheets("Sheet42")
时,实际上访问的是Worksheets
集合类的默认属性,即其Item
属性:
Dim sheet As Worksheet
Set sheet = Worksheets.Item("Sheet42")
而 Worksheets
集合的 Item
属性返回一个 Object
,这意味着在此后添加的任何成员调用都将是晚期绑定/在运行时解析的:
Dim obj As Object
Set obj = Worksheets.Item("Sheet42")
obj.AnythingYouWantHereWillCompileAnyway
在运行时,VBA查询对象的接口以寻找
AnythingYouWantHereWillCompileAnyway
,但未找到该成员 - 这就是出现运行时错误438“对象不支持此属性或方法”的原因。
您可以通过使用早期绑定调用将该类型安全性移回编译时(而不是运行时),即使用
Worksheet
接口/类而不是
Object
来工作。
Dim obj As Worksheet
Set obj = Worksheets.Item("Sheet42")
obj.AnythingYouWantHereWillCompileAnyway 'nope. that won't compile anymore.
当你询问“如何为另一个工作表分配已经设置的区域?”时,你认为
Range
对象仅仅是一个地址,这个假设是错误的。
Range
不仅仅只是一个地址,如果它只是一个地址,那么它将成为一个字符串文字,而不是一个对象。
如果你想要一个代表地址的变量,你可以使用
String
变量来实现:
Dim a As String
a = "A1"
Dim r1 As Range
Set r1 = Sheet1.Range(a)
Dim r2 As Range
Set r2 = Sheet2.Range(a)
Select
和Activate
,因为意识到未经限定的Range
调用会隐式地引用活动工作表。 - Mathieu Guindon