【问题标题】:Excel VBA: Workbook-scoped, worksheet dependent named formula/named range (result changes depending on the active worksheet)Excel VBA:工作簿范围,工作表依赖的命名公式/命名范围(结果根据活动工作表而变化)
【发布时间】:2014-04-07 18:18:45
【问题描述】:

编辑:为清楚起见更改了标题。

快速总结:我想知道工作簿范围内、工作表相关的命名公式(我将在下面描述)的行为是否是 Excel 中的一个记录功能。如果是这样,请在某处向我指出一些文档的方向-我似乎无法在网上找到任何关于此的内容(也许我使用了错误的搜索词..?)并且不想使用实际上是一个错误,可能会在以后的版本中消失!

严格来说,这并不是一个关于 VBA 的问题。但是,命名公式是我和其他人use in VBA code all the time 的东西,所以它仍然适用于我认为的主题。

编辑:请注意,下面的 VBA 代码可能并不完全正确——我还没有测试过。

常规方法

对于工程/科学计算,我经常需要在同一个工作簿中多次使用相同的命名公式/范围,但在不同的工作表上。作为一个简化的例子,我可能会为圆的面积实现这样的事情:

Dim sht as Worksheet
For Each sht In ThisWorkbook
    Call sht.Names.Add(Name:="AreaCircle",RefersTo:="=PI()*'" & _
            sht.Name & "'!Radius^2")
Next sht

这会产生以下一组命名范围/公式(范围仅限于每个工作表):

=PI()*Sheet1!Radius^2        <--- scoped to Sheet1
=PI()*Sheet2!Radius^2        <--- scoped to Sheet2
etc. etc.

这当然可以,但它的主要缺点是难以在未来进行更改。因此,例如,如果公式发生变化(圆的面积当然不会改变!但是 AASHTO LRFD 高速公路设计代码中的公式,例如,几乎每个版本都会改​​变!),我必须编辑每个实例每一个名称公式。这很乏味,即使我编写了一个 VBA 程序来为我做这件事。

替代方法

前几天我在 Excel 2013 中偶然发现了以下内容,但在网上的任何地方都找不到关于它的任何信息。这让我犹豫要不要开始使用它。

假设我运行以下单行代码:

Call ThisWorkbook.Names.Add(Name:="AreaCircle",RefersTo:="=PI()*!Radius^2")

这会产生以下单个命名范围/公式(范围为工作簿):

=PI()*!Radius^2 !Radius,而不是Radius

请注意,这与以下内容不同(没有感叹号):

=PI()*Radius^2 Radius 的范围是工作簿。

现在,AreaCircle 将产生与上述第一种方法完全相同的行为:它将根据本地工作表定义的 Radius 值产生结果。因此,如果有两个名为Radius 的命名范围(一个用于Sheet1,一个用于Sheet2),则AreaCircle 将根据使用它的工作表中Radius 的值进行计算。并且每次添加新工作表时,我不再需要添加此(以及其他所有!)公式的新版本(这是巨大的!)。

这是难以描述的行为;如果您对我的描述感到困惑,您可以执行以下步骤来重新创建此行为:

  1. 在一个工作簿中,创建两个或多个工作表并在Sheet1 的单元格A1 中输入“1”,在Sheet2 的单元格A1 中输入“2”,在Sheet3 的单元格A1 中输入“3”等等
  2. 创建一个名为CellA1 的命名范围(具有工作簿范围)并为公式输入以下内容:=!$A$1
  3. 在任何单元格中输入=CellA1 将导致Sheet1 为“1”,Sheet2 为“2”,等等。

文档?

嘿,你成功了 - 谢谢你一直陪着我!

那么,正如我上面所说,有人可以指点我这个“功能”的文档吗?我很想在我的一些更复杂的项目中开始实施它;如果不出意外,它只会使名称管理器更容易导航 20 倍(没有所有重复的名称)。

【问题讨论】:

  • 只是一个旁注(目前正在尝试重新创建您的示例):您真的使用R 作为名称吗? AFAIK 这应该是不可能的......
  • 啊哈!我不!我会相应地进行编辑。
  • 瑞克,我很乐意为此给你+100,而不仅仅是+1!我不知道这一点 - 但它确实有效。我刚刚在 2003、2010 和 2013 年对其进行了测试。因此,我相信您可以期待它在未来的版本中工作!谢谢
  • 是的,它真的是救命稻草——当我意识到发生了什么事时,我差点从椅子上摔下来。
  • 好问题!我想指出,在Excel 2013Excel Online 中存在一个名为Sheet 的本机电子表格函数,它返回等效于Sheet.IndexVBA。因此,您描述的两种方法的替代方法是构造一个 Range Radius(或命名数组)和另一个名称 LocalRadius = INDEX(Radius, SHEET()),它返回 Radius 数组的相应元素,具体取决于哪个工作表它被调用(SHEET() 返回包含该函数的工作表的索引,两个名称都应在全局范围内)。

标签: vba excel named-ranges


【解决方案1】:

文档见Evaluating Names and Other Worksheet Formula Expressions

  • =A1 引用当前工作表上的单元格 A1
  • =!A1 指的是活动工作表上的单元格 A1

结合Worksheet References

  • 当前是指 Excel 正在重新计算的...
  • 活动是指用户正在查看的内容...

这就是查尔斯·威廉姆斯所展示的。至于您的用例,我建议使用用户定义的函数,例如在 VBA 中。

【讨论】:

  • 太好了,这正是我想要的。实际上,对于我的用例,我建议根本不使用 Excel!这只是错误的工具。但是,有时你的双手被束缚了。
【解决方案2】:

您需要小心使用!名称中的引用:
带有以 = 开头的 refer-to 的名称!从 VBA 调用计算时可能会给出不正确的结果。它们的计算方式好像它们总是引用活动工作表而不是它们正在使用的工作表:

将 1 放入 Sheet1 的单元格 A1
a) 将=CellA1 放入Sheet1 的A2 中,其中CellA1 定义为=!$A$1
b) 切换到手动计算
c) 激活 Sheet2
d) 运行此 VBA 代码

Sub Testing()
Worksheets("Sheet1").Range("a1") = 8
Application.Calculate
End Sub

e) 现在切换回 Sheet1,您将看到 Sheet1!A2 包含 Sheet2!A1 中的所有内容

使用indirect() 可以避免这个问题
我们的名称管理器插件会检测并警告使用这种语法。

【讨论】:

  • 啊-是的,我今天下午正在玩它并意识到这一点。工作簿中的所有 !Referenced 公式是否根据活动工作表重新计算,还是仅根据活动工作表上的公式重新计算?我希望这不会太令人困惑。
  • 回答我自己上面的问题:似乎并非如此。如果我在 Sheet1 的单元格 A2 中放入 =CellA1,在 Sheet2 中放入 =Sheet2!A2,它会根据公式的位置而不是 ActiveSheet 显示值。不过,VBA 中的行为可能会有所不同。
  • 您能否编辑您的答案以提供您正在谈论的内容的代码示例?我很难创造出你描述的行为会产生意想不到的情况。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-25
  • 2018-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多