我听说过很多关于在Excel VBA中使用. select的可以理解的厌恶,但我不确定如何避免使用它。我发现,如果我能够使用变量而不是Select函数,我的代码将更具可重用性。然而,我不确定如果不使用选择如何引用事物(如ActiveCell等)。
我找到了这篇关于范围的文章和这个关于不使用select的好处的例子,但我找不到任何关于如何使用的东西。
我听说过很多关于在Excel VBA中使用. select的可以理解的厌恶,但我不确定如何避免使用它。我发现,如果我能够使用变量而不是Select函数,我的代码将更具可重用性。然而,我不确定如果不使用选择如何引用事物(如ActiveCell等)。
我找到了这篇关于范围的文章和这个关于不使用select的好处的例子,但我找不到任何关于如何使用的东西。
当前回答
从不使用选择或活动表的主要原因是,大多数人在运行宏时至少会打开另外几个工作簿(有时是几十个),如果他们在宏运行时从工作表中单击离开,并单击他们已经打开的其他工作簿,那么“活动表”会发生变化,而不满足“选择”命令的目标工作簿也会发生变化。
在最好的情况下,你的宏会崩溃,在最坏的情况下,你可能会在错误的工作簿中写入值或更改单元格,而无法“撤消”它们。
我有一个我遵循的简单的黄金法则:为工作簿对象和工作表对象添加名为“wb”和“ws”的变量,并始终使用它们来引用我的宏书。如果我需要引用多本书或多张表格,我会添加更多变量。
例如,
Dim wb as Workbook
Dim ws as Worksheet
Set wb = ThisWorkBook
Set ws = wb.sheets("Output")
“Set wb = ThisWorkbook”命令绝对是关键。“ThisWorkbook”是Excel中的一个特殊值,它意味着您的VBA代码当前正在运行的工作簿。一个非常有用的快捷方式来设置你的工作簿变量。
当你在你的Sub顶部做了这些之后,使用它们再简单不过了,只要在你使用“Selection”的地方使用它们:
因此,要将“Output”中的单元格“A1”的值更改为“Hello”,而不是:
Sheets("Output").Activate
ActiveSheet.Range("A1").Select
Selection.Value = "Hello"
我们现在可以这样做:
ws.Range("A1").Value = "Hello"
如果用户使用多个电子表格,它不仅更可靠,而且不太可能崩溃;它也更短,更快,更容易写。
作为额外的奖励,如果你总是将变量命名为“wb”和“ws”,你可以将代码从一本书复制粘贴到另一本书,通常只需要进行最小的更改就可以工作。
其他回答
我要给出简短的答案,因为其他人都给出了长答案。
当您记录宏并重用它们时,您将得到.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"
这些方法有多种组合,但对于像我这样没有耐心的人来说,这将是尽可能简短地表达的总体思想。
从不使用选择或活动表的主要原因是,大多数人在运行宏时至少会打开另外几个工作簿(有时是几十个),如果他们在宏运行时从工作表中单击离开,并单击他们已经打开的其他工作簿,那么“活动表”会发生变化,而不满足“选择”命令的目标工作簿也会发生变化。
在最好的情况下,你的宏会崩溃,在最坏的情况下,你可能会在错误的工作簿中写入值或更改单元格,而无法“撤消”它们。
我有一个我遵循的简单的黄金法则:为工作簿对象和工作表对象添加名为“wb”和“ws”的变量,并始终使用它们来引用我的宏书。如果我需要引用多本书或多张表格,我会添加更多变量。
例如,
Dim wb as Workbook
Dim ws as Worksheet
Set wb = ThisWorkBook
Set ws = wb.sheets("Output")
“Set wb = ThisWorkbook”命令绝对是关键。“ThisWorkbook”是Excel中的一个特殊值,它意味着您的VBA代码当前正在运行的工作簿。一个非常有用的快捷方式来设置你的工作簿变量。
当你在你的Sub顶部做了这些之后,使用它们再简单不过了,只要在你使用“Selection”的地方使用它们:
因此,要将“Output”中的单元格“A1”的值更改为“Hello”,而不是:
Sheets("Output").Activate
ActiveSheet.Range("A1").Select
Selection.Value = "Hello"
我们现在可以这样做:
ws.Range("A1").Value = "Hello"
如果用户使用多个电子表格,它不仅更可靠,而且不太可能崩溃;它也更短,更快,更容易写。
作为额外的奖励,如果你总是将变量命名为“wb”和“ws”,你可以将代码从一本书复制粘贴到另一本书,通常只需要进行最小的更改就可以工作。
我注意到这些答案都没有提到. 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, Selection, Activecell, Activesheet, Activeworkbook等应该避免
它会降低代码的速度。 它通常是运行时错误的主要原因。
我们如何避免它?
1)直接与相关对象一起工作
考虑下面的代码
Sheets("Sheet1").Activate
Range("A1").Select
Selection.Value = "Blah"
Selection.NumberFormat = "@"
这段代码也可以写成
With Sheets("Sheet1").Range("A1")
.Value = "Blah"
.NumberFormat = "@"
End With
2)如果需要,声明你的变量。上面相同的代码可以写成
Dim ws as worksheet
Set ws = Sheets("Sheet1")
With ws.Range("A1")
.Value = "Blah"
.NumberFormat = "@"
End With
这是一个很好的答案,但我在这个话题上忽略了我们真正需要Activate的时候。每个人都说它不好,但没有人解释在什么情况下使用它是有意义的。
无法避免使用. activate /. select的情况。(将添加更多的链接,当我遇到他们)
当您希望将工作表显示给用户以便用户可以看到它时。 例如工作宏从表单控件运行时返回错误,强制使用.Activate 当通常的Text To Columns / .Formula = .Formula方法不起作用时,您可能不得不求助于.Select
避免选择和激活是一个举动,使你更好的VBA开发人员。一般来说,在记录宏时使用“选择”和“激活”,因此父工作表或范围总是被认为是活动的。
这是在以下情况下避免选择和激活的方法:
添加一个新的工作表并复制一个单元格:
从(宏记录器生成的代码):
Sub Makro2()
Range("B2").Select
Sheets.Add After:=ActiveSheet
Sheets("Tabelle1").Select
Sheets("Tabelle1").Name = "NewName"
ActiveCell.FormulaR1C1 = "12"
Range("B2").Select
Selection.Copy
Range("B3").Select
ActiveSheet.Paste
Application.CutCopyMode = False
End Sub
To:
Sub TestMe()
Dim ws As Worksheet
Set ws = Worksheets.Add
With ws
.Name = "NewName"
.Range("B2") = 12
.Range("B2").Copy Destination:=.Range("B3")
End With
End Sub
当你想复制工作表之间的范围:
来自:
Sheets("Source").Select
Columns("A:D").Select
Selection.Copy
Sheets("Target").Select
Columns("A:D").Select
ActiveSheet.Paste
To:
Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").Range("a1")
使用花哨的命名范围
您可以使用[]访问它们,这与其他方式相比非常漂亮。检查自己:
Dim Months As Range
Dim MonthlySales As Range
Set Months = Range("Months")
Set MonthlySales = Range("MonthlySales")
Set Months =[Months]
Set MonthlySales = [MonthlySales]
上面的例子是这样的:
Worksheets("Source").Columns("A:D").Copy Destination:=Worksheets("Target").[A1]
不是复制值,而是取值
通常,如果你愿意选择,很可能你是在复制一些东西。如果你只对值感兴趣,这是一个避免选择的好选项:
范围(“B1: B6”)。值=范围("A1:A6")。价值
试着经常引用工作表
这可能是vba中最常见的错误。无论何时复制范围,有时工作表没有被引用,因此VBA将错误的工作表视为ActiveWorksheet。
'This will work only if the 2. Worksheet is selected!
Public Sub TestMe()
Dim rng As Range
Set rng = Worksheets(2).Range(Cells(1, 1), Cells(2, 2)).Copy
End Sub
'This works always!
Public Sub TestMe2()
Dim rng As Range
With Worksheets(2)
.Range(.Cells(1, 1), .Cells(2, 2)).Copy
End With
End Sub
我真的不能在任何事情上使用。select或。activate吗?
一个很好的例子,当你想要确保一个特定的工作表被选择为视觉原因时,你可以使用. activate和. select。例如,您的Excel总是首先选择封面工作表打开,而不管文件关闭时哪个是活动表。
因此,像下面这样的代码是完全可以的:
Private Sub Workbook_Open()
Worksheets("Cover").Activate
End Sub
另一个很好的例子是当你需要将所有的表导出到一个PDF文件中,正如在这种情况下提到的那样——如何避免在本例中VBA中的选择/活动语句? 当一个命令只适用于ActiveWindow时,如ActiveWindow。缩放或ActiveWindow。FreezePanes