我听说过很多关于在Excel VBA中使用. select的可以理解的厌恶,但我不确定如何避免使用它。我发现,如果我能够使用变量而不是Select函数,我的代码将更具可重用性。然而,我不确定如果不使用选择如何引用事物(如ActiveCell等)。

我找到了这篇关于范围的文章和这个关于不使用select的好处的例子,但我找不到任何关于如何使用的东西。


当前回答

我注意到这些答案都没有提到. offset属性。这也可以用来避免在操作某些单元格时使用Select操作,特别是在引用选定的单元格时(正如OP中使用ActiveCell提到的那样)。

这里有几个例子:

我还假定ActiveCell是J4。

ActiveCell。Offset(2,0).Value = 12

这将从activecell(即J6)往下两行更改单元格的值为12 A -2会把值12放在J2上面两行

ActiveCell.Offset(0, 1)。ActiveCell.Offset副本(2)

这将把右边一列的单元格(k4)复制到活动单元格(L4)两列的单元格。 注意,offset参数中0可能被省略 因此:activecell。offset(,2)和activecell。offset(0,2)是一样的 类似于前面的例子,-1是左边的一列(i4)

这并不是说这些选项比上面的选项更好,但它肯定比使用select要好。注意,在工作表中应该避免使用EXCEL函数偏移量,因为它是一个易失函数。

其他回答

我要给出简短的答案,因为其他人都给出了长答案。

当您记录宏并重用它们时,您将得到.select和.activate。当你选择一个单元格或工作表时,它会使它激活。从那时起,当你使用像Range这样的非限定引用时。值他们只是使用活动单元格和表。如果您没有观察代码放置的位置或用户单击工作簿,这也会产生问题。

因此,您可以通过直接引用单元格来消除这些问题。这是:

'create and set a range
Dim Rng As Excel.Range
Set Rng = Workbooks("Book1").Worksheets("Sheet1").Range("A1")
'OR
Set Rng = Workbooks(1).Worksheets(1).Cells(1, 1)

或者你可以

'Just deal with the cell directly rather than creating a range
'I want to put the string "Hello" in Range A1 of sheet 1
Workbooks("Book1").Worksheets("Sheet1").Range("A1").value = "Hello"
'OR
Workbooks(1).Worksheets(1).Cells(1, 1).value = "Hello"

这些方法有多种组合,但对于像我这样没有耐心的人来说,这将是尽可能简短地表达的总体思想。

我注意到这些答案都没有提到. offset属性。这也可以用来避免在操作某些单元格时使用Select操作,特别是在引用选定的单元格时(正如OP中使用ActiveCell提到的那样)。

这里有几个例子:

我还假定ActiveCell是J4。

ActiveCell。Offset(2,0).Value = 12

这将从activecell(即J6)往下两行更改单元格的值为12 A -2会把值12放在J2上面两行

ActiveCell.Offset(0, 1)。ActiveCell.Offset副本(2)

这将把右边一列的单元格(k4)复制到活动单元格(L4)两列的单元格。 注意,offset参数中0可能被省略 因此:activecell。offset(,2)和activecell。offset(0,2)是一样的 类似于前面的例子,-1是左边的一列(i4)

这并不是说这些选项比上面的选项更好,但它肯定比使用select要好。注意,在工作表中应该避免使用EXCEL函数偏移量,因为它是一个易失函数。

这些方法都是被污名化的,所以以Vityata和jeomed为首为了划清界限:

调用.Activate, .Select, Selection, ActiveSomething方法/属性

基本上是因为调用它们主要是为了通过应用程序UI处理用户输入。因为它们是用户通过UI处理对象时调用的方法,所以它们是宏记录器所记录的方法,这就是为什么在大多数情况下调用它们不是脆弱就是多余的原因:您不必选择一个对象以便在随后执行Selection操作。

然而,这个定义适用于需要它们的情况:

何时调用.Activate, .Select, .Selection, .ActiveSomething方法/属性

基本上,当你希望最终用户在执行过程中发挥作用时。

如果您正在开发并希望用户为您的代码选择要处理的对象实例,那么. selection或. activeobject是合适的。

On the other hand, .Select and .Activate are of use when you can infer the user's next action and you want your code to guide the user, possibly saving him/her some time and mouse clicks. For example, if your code just created a brand new instance of a chart or updated one, the user might want to check it out, and you could call .Activate on it or its sheet to save the user the time searching for it; or if you know the user will need to update some range values, you can programmatically select that range.

始终声明工作簿,工作表和单元格/范围。

例如:

Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)

因为终端用户总是只会点击按钮,一旦焦点从代码想要使用的工作簿上移开,事情就会完全出错。

永远不要使用工作簿的索引。

Workbooks(1).Worksheets("fred").cells(1,1)

当用户运行您的代码时,您不知道还会打开哪些工作簿。

我将在之前给出的所有优秀答案中补充一个小重点:

为了避免使用Select,你能做的最大的事情可能就是在你的VBA代码中尽可能使用命名范围(结合有意义的变量名)。上面提到了这一点,但它被掩盖了一点;然而,它值得特别关注。

下面是自由使用命名范围的另外几个原因,不过我相信我还能想出更多的原因。

命名范围使您的代码更容易阅读和理解。

例子:

Dim Months As Range
Dim MonthlySales As Range

Set Months = Range("Months")
' E.g, "Months" might be a named range referring to A1:A12

Set MonthlySales = Range("MonthlySales")
' E.g, "Monthly Sales" might be a named range referring to B1:B12

Dim Month As Range
For Each Month in Months
    Debug.Print MonthlySales(Month.Row)
Next Month

很明显,命名范围monthales和monthsale包含了什么,以及过程在做什么。

为什么这很重要?部分原因是其他人更容易理解它,但即使你是唯一一个看到或使用你的代码的人,你仍然应该使用命名范围和良好的变量名,因为你会忘记一年后你打算用它做什么,你会浪费30分钟来弄清楚你的代码在做什么。

命名范围确保当电子表格的配置改变时(不是如果!)宏不太可能被破坏。

考虑一下,如果上面的例子是这样写的:

Dim rng1 As Range
Dim rng2 As Range

Set rng1 = Range("A1:A12")
Set rng2 = Range("B1:B12")

Dim rng3 As Range
For Each rng3 in rng1
    Debug.Print rng2(rng3.Row)
Next rng3

这段代码一开始会工作得很好,直到您或未来的用户决定“天哪,我想我要在a列中添加一个新的列,其中包含年份!”,或者在月份和销售列之间添加一个费用列,或者为每个列添加一个标题。现在,你的密码坏了。因为你使用了糟糕的变量名,你会花更多的时间来解决这个问题。

如果一开始就使用了命名范围,那么Months和Sales列就可以随意移动,代码就可以继续正常工作。