我听说过很多关于在Excel VBA中使用. select的可以理解的厌恶,但我不确定如何避免使用它。我发现,如果我能够使用变量而不是Select函数,我的代码将更具可重用性。然而,我不确定如果不使用选择如何引用事物(如ActiveCell等)。
我找到了这篇关于范围的文章和这个关于不使用select的好处的例子,但我找不到任何关于如何使用的东西。
我听说过很多关于在Excel VBA中使用. select的可以理解的厌恶,但我不确定如何避免使用它。我发现,如果我能够使用变量而不是Select函数,我的代码将更具可重用性。然而,我不确定如果不使用选择如何引用事物(如ActiveCell等)。
我找到了这篇关于范围的文章和这个关于不使用select的好处的例子,但我找不到任何关于如何使用的东西。
当前回答
为了避免使用. select方法,可以将变量设置为所需的属性。
例如,如果你想要单元格A1中的值,你可以设置一个变量等于该单元格的value属性。
示例valOne = Range("A1")。价值
例如,如果你想要“Sheet3”的代码名,你可以设置一个变量等于该工作表的codename属性。
示例valTwo = Sheets("Sheet3")。代号
其他回答
避免选择和激活是一个举动,使你更好的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
从不使用选择或活动表的主要原因是,大多数人在运行宏时至少会打开另外几个工作簿(有时是几十个),如果他们在宏运行时从工作表中单击离开,并单击他们已经打开的其他工作簿,那么“活动表”会发生变化,而不满足“选择”命令的目标工作簿也会发生变化。
在最好的情况下,你的宏会崩溃,在最坏的情况下,你可能会在错误的工作簿中写入值或更改单元格,而无法“撤消”它们。
我有一个我遵循的简单的黄金法则:为工作簿对象和工作表对象添加名为“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”,你可以将代码从一本书复制粘贴到另一本书,通常只需要进行最小的更改就可以工作。
使用. 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
请注意,在下面我将比较Select方法(OP想要避免的方法)和Range方法(这是问题的答案)。所以当你看到第一个选择时不要停止阅读。
这真的取决于你想要做什么。总之,举个简单的例子会很有用。让我们假设您想要将活动单元格的值设置为“foo”。使用ActiveCell,你可以这样写:
Sub Macro1()
ActiveCell.Value = "foo"
End Sub
如果你想将它用于一个非活动单元格,例如“B2”,你应该首先选择它,如下所示:
Sub Macro2()
Range("B2").Select
Macro1
End Sub
使用Ranges,你可以编写一个更通用的宏,可以用来设置任何你想要的单元格的值:
Sub SetValue(cellAddress As String, aVal As Variant)
Range(cellAddress).Value = aVal
End Sub
然后你可以重写Macro2为:
Sub Macro2()
SetCellValue "B2", "foo"
End Sub
而Macro1为:
Sub Macro1()
SetValue ActiveCell.Address, "foo"
End Sub
如何避免复制粘贴?
让我们面对现实吧:这个在记录宏时经常出现:
Range("X1").Select
Selection.Copy
Range("Y9").Select
Selection.Paste
而这个人唯一想要的是:
Range("Y9").Value = Range("X1").Value
因此,与其在VBA宏中使用复制粘贴,我建议使用以下简单的方法:
Destination_Range.Value = Source_Range.Value