我从未找到一个好的解决方案的问题之一是在VBA项目中定义工作表中事物的位置。如果您中的任何一个必须使用VBA和工作表功能来构建工作表,您都知道这很重要的原因。运行脚本并意识到保存f检验结果的单元从F20移到H20实在令人沮丧,因为您必须添加两列数据,并且在VBA中找不到所有范围引用需要更新。
我正在寻找更多有助于系统存储VBA范围参考的想法和最佳实践,这些参考信息易于更新并与不断发展的电子表格保持一致。
我列出了我认为的常用选项。我之前已经做过前四个,但是他们只是做不到。
选项1:在每个子标题的顶部定义并编程位置变量
通常会发生这种情况。在每个主子控件的顶部,定义范围接口变量,然后使用完全限定的引用进行设置。对于具有一个或两个主要功能的快速项目,这通常就足够了。
当您开始有很多嵌套函数时,这将成为一个问题。您是否在headerRow
函数中重新定义firstDataRow
和moveDataRow()
?还是您每次都传递所有这些信息?真痛苦小规模可管理。随着事情的发展,完全变成了面条上的意大利面条怪兽和针头(我们都知道它们通常会这样做)。
选项2:定义我自己的工作表对象
我花了很多时间定义自己的工作表对象,该对象具有其他属性,例如“ headerRow”或“ firstDataRow”,以便可以将这些属性存储在工作表代码中。然后,当我定义工作表对象时,我使用dim srcSheet as myWorksheet
而不是dim srcSheet as Worksheet
。这使我可以通过对象模型找到属性。例如:srcSheet.headerRow
当您处理同一工作表的许多重复项时,此解决方案是极好的。如果您有六张纸都需要不同的属性来做一些不同的事情,那将完全浪费时间。例如:一张纸可能是Monte Carlo控件,而另一张纸正在运行f检验。我不想为每个对象创建一个新的工作表对象。
选项3:动态查找所有内容
这可能是最强大的,但是令人难以置信的耗时。找到一种根据其内容,格式和相对位置定义每个单元格位置的方法。通常,您要引用的单元格中有一些特定内容不会更改。编写脚本来查找该东西会使事情变得更加容易。但是,这是一项繁重的工作,并不是每个项目都切实可行。太多的工作对大多数项目来说都是浪费时间。
选项4:模块级位置变量
对主要功能使用一个新模块,该主要功能与纸张的一部分相连。然后在该模块的顶部一次将所有位置信息定义为私有常量。
这对于中型项目非常有效。但是,当您处理多个模块并在处理多个工作表时在多个工作表之间移动数据时,您开始必须多次定义相同的常量。
选项5:创建“位置”模块
这可能效果很好,因为所有位置都在一个地方。我还没有尝试过,但这就是我在这里问这个问题的原因。每当您创建位置参考时,它都会进入位置模块。每个工作表将具有定义的前缀,以标识该特定工作表。这样,您可以在子程序或函数中调用srcHeaderRow = dataHeaderRow
来定义数据头在第5行,而不必在每次使用{时都要重新定义该行,而不是在该子程序中设置工作表范围位置{1}}。
还有什么?您尝试过的一切都很棒吗?
您还使用哪些其他方法来保持VBA与工作表之间接口的单元格/范围位置?
答案 0 :(得分:0)
我不知道这些是否符合最佳做法,但这是我的做法。
为什么dim srcSheet as myWorksheet
仅可以更改工作表的代号?
我为每个工作表创建一个枚举,以枚举每列,[第一列],[最后一列]和[标题行]。将Enum成员括在方括号中,并使用特殊字符命名将创建隐藏成员。请参见下面的示例代码。如果以后我决定重新排列列,添加列或重新定位数据,我要做的就是更新枚举,并且代码不会中断。
枚举可用于Intellisense
我使用了Excel Sample Data的前10行作为数据。
Public Enum EnumWSDataColumns
dcOrderDate = 3
dcRegion
dcRep
dcItem
dcUnits
dcUnitCost
dcTotal
[_dcFirstColumn] = dcOrderDate
[_dcLastColumn] = dcTotal
dcHeaderRow = 4
End Enum
Sub DemoEnum()
Dim r As Long, c As Long
Dim value As String * 10
With wsData
For r = dcHeaderRow To .Cells(.Rows.count, [_dcFirstColumn]).End(xlUp).Row
For c = [_dcFirstColumn] To [_dcLastColumn]
value = .Cells(r, c)
Debug.Print value; "|";
Next
Dim n As Long
n = ([_dcLastColumn] - [_dcFirstColumn] + 1) * (Len(value) + 1)
Debug.Print
Debug.Print String(n, "-")
Next
End With
End Sub