如何在Excel VBA中使用相对名称

许多“高级”(又名:VBA)在网上excel教程甚至excel的vba帮助鼓励我们使用

Range("B2:B10") 

方法(确切地说:对象)用于select单元格或获取值。 在同一个地方,他们经常添加完全可以使用预定义的名字:

 Range("valuesabove") 

另一方面,我爱上了相对定义的单元名称的难以置信的力量。 他们使得编写和处理大型复合公式变得容易很多,基本上可以指代几乎任何东西。

但是, 相对名称在Range(“valuesabove”)方法中不适用于我们习惯的方式。

通常(在工作表上使用时)相对名称是相对于当前选定的单元格或使用它们的单元格。

在VBA的Range()对象中,这是不正确的。 范围相对于WorkSheet对象,默认情况下是ActiveSheet。 但ActiveSheet由其上层单元格A1代表。 这就是Range相对的原因。 这就是为什么绝对名称($ C $ 23)可以和它一起工作,而相对的名称(“向左一列,向上两列”)则不然。

所以我的问题是:如何利用VBA中的相对名称的力量呢?


编辑:

意识到我的问题还不太清楚(thx请你们不知疲倦地发表意见)让我试着把它放在一个特定的forms和澄清条款:

恕我直言,在Excel工作表,它是非常舒适的使用名称,以引用单元格或基于单元格值函数定义计算值。

在Excel中,对单元格的引用可以是相对的,绝对的或混合的 。 创build名称时也是如此。 因此,我们可以谈论绝对的,相对的或混合的名称(就当然指的而言)。

这里使用绝对名称几次(使用Excel的Trace Dependentsfunction创build): 绝对名称

名称“name”= $D$2

一个相对的名字在这里用了几次: 在这里输入图像说明

命名“upright24” ,例如单元格A7被选中 = C3 (没有$符号!)。 但是这根据所选的细胞或地区不断变化。 你可以在名字pipe理器中检查它! (按Ctrl + F3)

这是我们可以考虑的混合名称混合名称

命名“rel_serialnumber” ,例如单元格C6被选中 = $B6 。 ( 6 )的行按照选定的单元格或区域不断变化。

创build相对名称或混合名称是在创build名称时明确基于活动单元格的。 绝对名称的创build自然不依赖于光标位置。

注意

  • 绝对名称是指从被引用的单元格开始的唯一偏移量

  • 相对名称是指被引用的单元格的静态偏移量,因此它总是对应于名称所在的位置

  • 混合名称是指与被引用的单元格相偏离的混合(或半dynamic)偏移量,因此其中的行或列总是对应于使用名称的位置,而另一个始终保持相同(一个或另一个中的偏移量方向保持为零)。


好的,现在是这样的。 我有一个类似数据库的Excel表格,我把logging​​和列作为属性的字段来处理。 用户使用这个东西,如下所示:他通过将光标放在所需logging行的任何单元格中来“selectlogging”。 然后他按下一个大的命令button ,启动我的VBAmacros。 这打算打开一个准备好的框架文件,并用选定logging中的某些值(通过混合名称定义)填充其中的某些特定单元格(它们是由绝对名称定义的)。

由于Range("name")被认为可以在VBA中使用(参见上面),所以我认为Range("relativename")或者Range("mixedname")在自动依赖活动单元格的同时会工作得很好。
我不能变坏。
只有Range("absolutename")以人们所期望的方式工作! 解释见上面。

所以我追求一个函数/方法/对象,可能与使用"relativename""mixedname"作为Range("absolutename")一样舒适。

我想我已经find了一个适当而紧凑的解决scheme。 它的

 Names("mixedname").RefersToRange 

不像Range("mixedname")那么短,但是它确实提供了期望的值。

更新:

如果要将源工作簿中的相对命名的单元格值复制到具有单个代码行的目标工作簿中的相对命名的单元格,则此解决scheme通常是无用的。 这是因为Names()依赖于光标的实际位置,这取决于哪个工作簿当前处于活动状态,在大多数情况下,这对另一个工作簿是不正确的。

在这种情况下,名称的非固定部分必须被存储:

sourcerow = ActiveCell.Row [...] 'opening a wbk, this also makes it the active one [...] Names("dest").RefersToRange = mysheet.Cells(sourcerow, mybook.Names("src").RefersToRange.Column)

看来你正在寻找Range.Offset() http://msdn.microsoft.com/en-us/library/office/ff840060%28v=office.15%29.aspx

但是你可以这样做:

 'Your example Range(Col_B_in_current_row) as Range("B" & ActiveCell.Row).Select 'Your example Range("B2:B10") -> Range("valuesabove") as Range("B2:B10").Offset(-1, 0).Select 

只是似乎已经存在一个相对简单的语法。

要引用一个相对于另一个Range的Range,可以使用下面的语法:

myRange.Range("namedRange")

注意: 只有在行偏移量和列偏移量都为正数的情况下才能使用。 例如,如果指定范围的“引用”公式为“= Offset(A1, rc )”,那么如果r c为负,则上述语法将引发错误。 但是,如果两者都是正面的,它将会起作用。

不对称是不幸的,但VBA业务照常…

要引用当前ActiveCell的行中的第三列:

ActiveCell.EntireRow.Range("C1")

要引用相对于ActiveCell偏移(例如)1行和3列的单元格:

ActiveCell.Range("C2")

显然,您可以在VBA中使用与Selection对象或其他Range值相同的语法。

Private Sub Worksheet_Change(ByVal Target as Range) If Not Intersect(Target.Address,ThisWorkbook.Sheets('sheetname).Range('RangeName)) Is Nothing Then _ 'Do whatever you want down here. ThisWorbook.Sheets('sheetname).Range('RangeName).Offset(0,Target.Row) End If End Sub

这应该给你正确的道路上你想要的(这是超级不清楚)。 使用工作表更改事件将用户工作表select和更改引入VBA模块。 把它放入相关的表格。

我也有同样的问题,但是我确实得到了它的工作 – 有点。 我不知道下面这个简单的例子有什么不同,但它是有效的。 起初我认为select是重要的,但没有 – 它的工作原理没有改变活动细胞。

(我仍然无法在我的主电子表格中工作。)

  • 命名范围:“TestName”= Sheet1!$ H1
  • H1中的值:H10 = 1,2,3,4,5,6,7,8,9,10

     Sub Test() Dim x As Integer For x = 0 To 10 Range("A1").Offset(x, 0).Value = Range("A1").Offset(x, 0).Range("Testname").Value Next x End Sub 

    结果:A1:A10 = 1,2,3,4,5,6,7,8,9,10