我听说过很多关于在Excel VBA中使用. select的可以理解的厌恶,但我不确定如何避免使用它。我发现,如果我能够使用变量而不是Select函数,我的代码将更具可重用性。然而,我不确定如果不使用选择如何引用事物(如ActiveCell等)。
我找到了这篇关于范围的文章和这个关于不使用select的好处的例子,但我找不到任何关于如何使用的东西。
我听说过很多关于在Excel VBA中使用. select的可以理解的厌恶,但我不确定如何避免使用它。我发现,如果我能够使用变量而不是Select函数,我的代码将更具可重用性。然而,我不确定如果不使用选择如何引用事物(如ActiveCell等)。
我找到了这篇关于范围的文章和这个关于不使用select的好处的例子,但我找不到任何关于如何使用的东西。
当前回答
使用. parent特性,这个例子展示了如何只设置一个myRng引用就可以动态访问整个环境,而不需要任何. select、. activate、. activecell、. activeworkbook、. activesheet等等。(没有任何通用的. child特性。)
Sub ShowParents()
Dim myRng As Range
Set myRng = ActiveCell
Debug.Print myRng.Address ' An address of the selected cell
Debug.Print myRng.Parent.name ' The name of sheet, where MyRng is in
Debug.Print myRng.Parent.Parent.name ' The name of workbook, where MyRng is in
Debug.Print myRng.Parent.Parent.Parent.name ' The name of application, where MyRng is in
' You may use this feature to set reference to these objects
Dim mySh As Worksheet
Dim myWbk As Workbook
Dim myApp As Application
Set mySh = myRng.Parent
Set myWbk = myRng.Parent.Parent
Set myApp = myRng.Parent.Parent.Parent
Debug.Print mySh.name, mySh.Cells(10, 1).Value
Debug.Print myWbk.name, myWbk.Sheets.Count
Debug.Print myApp.name, myApp.Workbooks.Count
' You may use dynamically addressing
With myRng
.Copy
' Pastes in D1 on sheet 2 in the same workbook, where the copied cell is
.Parent.Parent.Sheets(2).Range("D1").PasteSpecial xlValues
' Or myWbk.Sheets(2).Range("D1").PasteSpecial xlValues
' We may dynamically call active application too
.Parent.Parent.Parent.CutCopyMode = False
' Or myApp.CutCopyMode = False
End With
End Sub
其他回答
始终声明工作簿,工作表和单元格/范围。
例如:
Thisworkbook.Worksheets("fred").cells(1,1)
Workbooks("bob").Worksheets("fred").cells(1,1)
因为终端用户总是只会点击按钮,一旦焦点从代码想要使用的工作簿上移开,事情就会完全出错。
永远不要使用工作簿的索引。
Workbooks(1).Worksheets("fred").cells(1,1)
当用户运行您的代码时,您不知道还会打开哪些工作簿。
我要给出简短的答案,因为其他人都给出了长答案。
当您记录宏并重用它们时,您将得到.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函数偏移量,因为它是一个易失函数。
两个主要原因,为什么.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
一些如何避免选择的例子
使用Dim变量
Dim rng as Range
将变量设置为所需的范围。有很多种方法来指代单格范围:
Set rng = Range("A1")
Set rng = Cells(1, 1)
Set rng = Range("NamedRange")
或者一个多单元格范围:
Set rng = Range("A1:B10")
Set rng = Range("A1", "B10")
Set rng = Range(Cells(1, 1), Cells(10, 2))
Set rng = Range("AnotherNamedRange")
Set rng = Range("A1").Resize(10, 2)
您可以使用Evaluate方法的快捷方式,但这效率较低,通常应该在生产代码中避免使用。
Set rng = [A1]
Set rng = [A1:B10]
以上所有示例都引用活动工作表上的单元格。除非你特别想只使用活动表,否则最好将工作表变量也调暗:
Dim ws As Worksheet
Set ws = Worksheets("Sheet1")
Set rng = ws.Cells(1, 1)
With ws
Set rng = .Range(.Cells(1, 1), .Cells(2, 10))
End With
如果你确实想要使用ActiveSheet,为了清晰起见,最好是显式的。但是要小心,因为有些工作表方法会更改活动表。
Set rng = ActiveSheet.Range("A1")
同样,这是指活动工作簿。除非你特别想只使用ActiveWorkbook或ThisWorkbook,否则最好也使用Dim Workbook变量。
Dim wb As Workbook
Set wb = Application.Workbooks("Book1")
Set rng = wb.Worksheets("Sheet1").Range("A1")
如果您确实想使用ActiveWorkbook,为了清晰起见,最好是显式的。但是要注意,因为许多WorkBook方法会更改活动簿。
Set rng = ActiveWorkbook.Worksheets("Sheet1").Range("A1")
您还可以使用ThisWorkbook对象来引用包含运行代码的书籍。
Set rng = ThisWorkbook.Worksheets("Sheet1").Range("A1")
一个常见的(糟糕的)代码片段是打开一本书,获得一些数据,然后再次关闭
这很糟糕:
Sub foo()
Dim v as Variant
Workbooks("Book1.xlsx").Sheets(1).Range("A1").Clear
Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
v = ActiveWorkbook.Sheets(1).Range("A1").Value
Workbooks("SomeAlreadyOpenBook.xlsx").Activate
ActiveWorkbook.Sheets("SomeSheet").Range("A1").Value = v
Workbooks(2).Activate
ActiveWorkbook.Close()
End Sub
最好是这样:
Sub foo()
Dim v as Variant
Dim wb1 as Workbook
Dim wb2 as Workbook
Set wb1 = Workbooks("SomeAlreadyOpenBook.xlsx")
Set wb2 = Workbooks.Open("C:\Path\To\SomeClosedBook.xlsx")
v = wb2.Sheets("SomeSheet").Range("A1").Value
wb1.Sheets("SomeOtherSheet").Range("A1").Value = v
wb2.Close()
End Sub
将范围传递给子函数和函数作为范围变量:
Sub ClearRange(r as Range)
r.ClearContents
'....
End Sub
Sub MyMacro()
Dim rng as Range
Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:B10")
ClearRange rng
End Sub
你还应该对变量应用方法(比如Find和Copy):
Dim rng1 As Range
Dim rng2 As Range
Set rng1 = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10")
Set rng2 = ThisWorkbook.Worksheets("SomeSheet").Range("B1:B10")
rng1.Copy rng2
如果你循环遍历一个单元格范围,通常更好(更快)复制范围值到一个变量数组,然后循环遍历它:
Dim dat As Variant
Dim rng As Range
Dim i As Long
Set rng = ThisWorkbook.Worksheets("SomeSheet").Range("A1:A10000")
dat = rng.Value ' dat is now array (1 to 10000, 1 to 1)
for i = LBound(dat, 1) to UBound(dat, 1)
dat(i,1) = dat(i, 1) * 10 ' Or whatever operation you need to perform
next
rng.Value = dat ' put new values back on sheet
这是对可能性的小小尝试。