编写高效Excel VBA代码的最佳实践

上传人:dus****log 文档编号:92728956 上传时间:2022-05-19 格式:DOC 页数:22 大小:96KB
收藏 版权申诉 举报 下载
编写高效Excel VBA代码的最佳实践_第1页
第1页 / 共22页
编写高效Excel VBA代码的最佳实践_第2页
第2页 / 共22页
编写高效Excel VBA代码的最佳实践_第3页
第3页 / 共22页
资源描述:

《编写高效Excel VBA代码的最佳实践》由会员分享,可在线阅读,更多相关《编写高效Excel VBA代码的最佳实践(22页珍藏版)》请在装配图网上搜索。

1、很多Excel VBA文章和图书都介绍过如何优化VBA代码,使代码运行得更快。下面搜集了一些使Excel VBA代码运行更快的技术和技巧,基本上都是实践经验的总结。如果您还有其它优化Excel VBA代码的方法,可以在本文后留言或给出链接,与大家分享。对于应用程序属性,在代码运行时关闭除必需属性以外的其它所有属性在代码运行时关闭不需要的Excel功能。其原因是,如果通过VBA更新不同的单元格区域,或者从不同的单元格区域复制/粘贴来创建汇总表,则不希望Excel浪费时间和资源来重新计算公式、显示粘贴进度或者重绘网格,尤其在每次单独的操作后(更有甚者,如果代码使用了循环,则每次单独操作后Excel

2、都会在后台运行这些功能)。只需要在代码执行结束时进行一次重新计算和重绘就足以使工作簿更新。下面的代码将帮助您提高代码的执行速度。(1)放置在主代码前的一段代码,获取Excel当前的属性状态,然后将其关闭获得当前的Excel设置状态,将其放置在代码的开头screenUpdateState = Application.ScreenUpdatingstatusBarState = Application.DisplayStatusBarcalcState = Application.CalculationeventsState = Application.EnableEventsdisplayPag

3、eBreakState = ActiveSheet.DisplayPageBreaks 注:这是工作表级的设置关闭一些Excel功能使代码运行更快Application.ScreenUpdating = FalseApplication.DisplayStatusBar = FalseApplication.Calculation = xlCalculationManualApplication.EnableEvents = FalseActiveSheet.DisplayPageBreaks = False 注:这是工作表级的设置(2)放置在主代码结束后的一段代码,用来将Excel恢复到代码

4、运行前的设置代码运行后,恢复Excel原来的状态;将下面的代码放在代码的末尾Application.ScreenUpdating = screenUpdateStateApplication.DisplayStatusBar = statusBarStateApplication.Calculation = calcStateApplication.EnableEvents = eventsStateActiveSheet.DisplayPageBreaks = displayPageBreaksState 注:这是工作表级的设置下面简要解释这些设置:Application.ScreenUpd

5、ating:将该属性设置为False,告诉Excel不要重绘屏幕。其优点是不需要Excel花费资源来绘制屏幕,因而其改变会更快而不致让用户察觉其变化。因为如此频繁地绘制屏幕需要大量的资源,所以关闭绘制屏幕直到代码执行结束。在代码结束前,确保重新开启了该属性。Application.DisplayStatusBar:将该属性设置为False,告诉Excel停止显示状态栏。例如,如果使用VBA复制/粘贴单元格,当粘贴执行时Excel将在状态栏中显示操作的进度。关闭屏幕更新不会关闭状态栏显示,因此,如果需要的话,可以禁用屏幕更新而仍然可以通过状态栏给用户提供反馈。记住,如果将该属性设置为False,

6、在代码结束前应该将其设置为True。Application.Calculation:该属性允许编程设置Excel的计算模式。“手工的”(xlCalculationManual)模式意味着Excel等待用户(或代码)来触发计算;默认为“自动的”(xlCalculationAutomatic)模式,意味着由Excel来决定何时重新计算工作簿(例如,当在工作表中输入新公式时)。由于重新计算工作簿将花费时间且浪费资源,因此可能不希望每次改变单元格值时Excel都触发重新计算。当代码执行时关闭重新计算,在代码结束前再设置回重新计算模式。Application.EnableEvents:将该属性设置为Fa

7、lse,告诉Excel不要触发事件。你可能不希望Excel为每个正在通过代码发生改变的单元格触发事件,关闭事件将加速VBA代码的执行。ActiveSheet.DisplayPageBreaks:当在较新版本的Excel中运行VBA时,则可能比在早期版本的Excel中需要更长的时间完成。例如,需要几秒钟在早期版本的Excel中完成的宏可能需要几分钟才能在更高版本的Excel中完成。或者,第二次运行一个宏可能比第一次运行需要的时间更长。这是由于VBA宏修改了多行或列的属性,或者必须强制执行计算Excel分页符。如果宏设置了任何PageSetup属性或者手动设置了PageSetup属性,接着运行较大

8、区域的行或列属性设置时会出现这样的问题。您可以将该属性设置为False来提高代码的运行速度。当然,在代码运行结束前,应将该属性恢复为原设置。在单个操作中读/写大块的单元格区域本技巧用于优化在Excel和代码之间转换数据的次数。使用数组变量存储所需要的值并执行取值或赋值操作,而不是一次遍历单个单元格并获取或设置单个值。例如,下面的代码在单元格区域A1:C10000中放置随机数。代码段一:运行速度较慢的代码Sub testSlow()Dim DataRange As RangeDim Irow As LongDim Icol As IntegerDim MyVar As DoubleSet Dat

9、aRange = Range(A1:C10000)For Irow = 1 To 10000For Icol = 1 To 3MyVar = DataRange(Irow, Icol) 从Excel单元格中读取值30K次If MyVar 0 ThenMyVar = MyVar * MyVar 改变值DataRange(Irow, Icol) = MyVar 将值写入Excel单元格中30000次End IfNext IcolNext IrowEnd Sub代码段二:运行速度更快的代码Sub testFast()Dim DataRange As VariantDim Irow As LongDi

10、m Icol As IntegerDim MyVar As DoubleDataRange = Range(A1:C10000).Value 一次从Excel单元格中读取所有的值,将其放入数组For Irow = 1 To 10000For Icol = 1 To 3MyVar = DataRange(Irow, Icol)If MyVar 0 ThenMyVar = MyVar * MyVar 改变数组中的值DataRange(Irow, Icol) = MyVarEnd IfNext IcolNext IrowRange(A1:C10000).Value = DataRange 一次将所有

11、结果写回单元格End Sub避免选取/激活对象使用选取的方法更新单元格区域是最慢的。在试验了使用Range对象、使用Variant类型和使用Select方法对一个大的单元格区域读写数据的操作后,Select方法是最慢的。再来看一个例子:在工作表中有40个形状,在每个形状中写入“Hello”。使用Select方法的代码为:Sub testSlow()Dim i As IntegerFor i = 0 ToActiveSheet.Shapes(i).SelectSelection.Text = HelloNext iEnd Sub运行速度更快的方法是完全避免使用选取并直接引用形状:Sub test

12、Fast()Dim i As IntegerFor i = 0 ToActiveSheet.Shapes(i).TextEffect.Text = HelloNext iEnd Sub在使用宏录制器时,所生成的程序代码在应用任何方法或属性之前都会激活或者选择对象。但是,并不是在所有的情况下都需要这样做。所以,在您编写VBA程序代码时,不需要在对对象执行任何任务之前都激活或者选择每个对象。例如,在Excel中,我们如果要使第一行变成粗体就必须先选项中它。但在VBA中(除在图表操作时需要选中图表对象外),很少需要这样做,即VBA可以在不选中第一行的情况下,将它变成粗体。宏录制器的代码:Rows(1

13、:1).SelectSelection.Font.Bold = True改编后的代码为:Row(“1:1”).Font.Bold=True这样做还可以使程序代码更简洁,并且程序可以运行得更快。工作簿设计好的工作簿设计和数据组织有助于编写运行良好的代码。良好设计的工作簿,其执行效率和维护量将大大优化。可以说,工作簿设计是从大的宏观方面进行优化,而对代码的优化只是一些微观的细节上的优化。其他 尽量简化代码通过简化代码,可以提高程序的性能。您可以将通用过程编写为子过程来调用。例如,假设有一个应用程序需要在不同的地方实现查找一定范围内的某个特殊条目,在一个没有简化代码的应用程序中,不同的过程可能需要应

14、用各自的算法以实现在某个范围内查找某一条目,修改每个过程使其采用一个更有效的算法并不是一件很容易的事。而一个简化的程序则只有一个查找算法,即将该查找算法编写成通用的子程序,需要查找某个范围的过程都调用该子程序,通过在查找方法的子程序中优化查找算法,使得调用该方法的所有过程都享受性能提高所带来的好处。另外,删除所有无关的代码,这在所录制宏中表现得尤为明显。在录制宏时,经常会产生一些与所实现的功能无关的代码,您可以将这些代码删除,以使得代码得以简化。宏录制器生成无效代码的一个原因是它不知道在对话框中您选择了哪些选项,因此,当您关闭对话框时它将直接记录所有可用的选项。例如,选择单元格区域G2:G20

15、,然后在单元格格式对话框中改变字体样式为粗体,使用宏录制器生成的代码如下: Sub NowThis1() Dim Start As Double, Finish As Double Start = Timer - 为了进行测试,将循环100次 Dim N As Long For N = 1 To 100 * Range(G2:G20).Select With Selection.Font .Name = Arial .FontStyle = Bold .Size = 10 .Strikethrough = False .Superscript = False .Subscript = Fals

16、e .OutlineFont = False .Shadow = False .Underline = xlNone .ColorIndex = xlAutomatic End With * Next - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub您能只用下面的一行代码为指定的单元格设置字体样式,不需要选择单元格区域。Range(G2:G20).Font.FontStyle = Bold如果您考虑到您想要宏所做的事情(本例中为使字体加粗),那么您可以查阅应用到Font对象的属性和方法列表,您将知道只需使用Bold属性编写这个宏

17、代码以实现所需的功能。代码如下:Sub NowThis2() 快约10倍 Dim Start As Double, Finish As Double Start = Timer - 为进行测试,将循环100次 Dim N As Long For N = 1 To 100 * Range(G2:G20).Font.Bold = True * Next - Finish = Timer MsgBox 本次运行的时间为 & Finish - Start End Sub您也能在用户界面中通过执行不同的方法来录制产生结果相同的操作对宏录制器进行试验。例如,如果您通过标准工具栏上的粗体按钮格式化某区域为粗

18、体,那么宏录制器将使用Bold属性。下面将要讲到的设置对象变量代替长对象引用,使用WithEnd With语句、执行For EachNext循环语句,根据程序环境尽量减少OLE引用,等等,均是简化代码的好方法。 强制声明变量在VBE编辑器中的菜单“工具选项”对话框中“编辑器”选项卡中,您应该始终保持“要求变量声明”复选框被选中,这样将在模块代码顶部出现Option Explicit语句,要求您在编写代码时对所有出现的变量均进行声明,这样,在使用变量时减少内存需求并加速性能。(1)要节省内存资源,必须始终用特定的数据类型声明所有变量。如果不使用特定的数据类型声明变量,VBA会创建Variant类

19、型的变量,这将比任何其他数据类型要求更多的内存。(2)清楚每种数据类型需要多少内存以及它可以存储的值的范围。除使用较小的数据类型会导致隐性转换的情况外,应始终使用尽可能小的数据类型。例如,因为Integer类型的变量将被转换成Long类型的变量,应该将那些存储整型值的变量声明为Long类型,而不是Integer类型。(3)除非确实需要,应避免使用浮点数据类型。尽管Currency数据类型更大,但它比 Single 数据类型快,因为Currency数据类型不使用浮点处理器。(4)如果在一个过程中多次引用一个对象,可以创建对象变量,并将对给对象的引用指派给它。因为对象变量存储对象在内存中的位置,V

20、BA将不必再次查找其位置。(5)将对象变量声明为特定的类型(不是Object类型),以便利用早期绑定。(6) 减少”Variant”类型变量的使用虽然您可能发现在您的代码中使用Variant(变体)变量是方便的,但是如果您将变量清楚地声明为特定的数据类型,然后用VBA处理存储在该变量中的值,要比处理存储在Variant变量里的值快。如果执行不涉及分数值的数学运算,那么在您的代码中使用Long型变量比使用Variant变量更快。Long型变量也是在ForNext循环中索引值变量类型的最好选择。然而,您要注意到,您使用特定类型变量所获取的速度是以失去灵活性为代价的。例如,当使用特定数据类型时,您可

21、能遭到变量溢出或类型不匹配的情形,而不会像Variant变量会自动进行类型转换处理。(7) 声明时指定特定的对象类型当您的宏被编译或者是运行(后台编译)时,会解析对象及它们的方法和属性的引用。经过宏编译解析的引用比在程序运行时必须被解析的引用要更快,因此,您最好跳过后台编译。如果您声明变量和参数为特定的对象类型(比如Range或Worksheet),VBA在编译您的程序时将解析引用为这些对象的属性和方法。(如果要查找指定对象类型列表,请参见”对象浏览器”) 减少变量的作用范围并及时释放变量主要是对象变量,在其使用完后,及时释放。例如, Dim TempObj As AnyObject,AnOb

22、j As AnyObject Set TempObj=New AnyObject Set AnObj=TempObj Set TempObj=Nothing 释放对象变量 使用常量变量会发生变化,因此VBA在程序运行时必须获取当前变量的值。在应用程序中使用常量会使程序运行更快。在编译您的代码时,常量仅计算一次并被存储。常量也能使您的宏程序更易阅读和维护。如果在您的程序中有一些不变的字符串或数值的话,您可以声明它们作为常量。 尽可能使用早期绑定绑定是指将程序调用与实际代码相匹配。为了实现早期绑定,先应创建对对象库的引用。早期绑定可以在代码中使用定义在对象库中的常量,可以自动列出对象的方法和属性,

23、但早期绑定只有在所控制的对象拥有独立的类型库或对象库文件才适用且还需要已安装了特定的库。而后期绑定则只是在运行时才知道对象的类型并对对象进行引用,因此不具备上述特点。使用早期绑定创建对象通常更有效率,使代码能获得更好的性能。因为对象的早期绑定引用在编译时可以通过VBE的解析,而不是通过运行时模块解析,因此早期绑定的性能要好得多。虽然在程序设计时不可能总是使用早期绑定,但应该尽可能使用它。 使用For EachNext循环可以使用For EachNext循环来保证程序代码更快地执行。在使用For EachNext循环时,对于存储在集合或数组中的每个对象执行一组语句,程序更简洁,也更容易阅读、调试

24、和维护。当For EachNext语句迭代集合时,自动指定一个对集合当前成员的引用,然后在到达集合的尾部时跳出循环语句。与使用计数进行循环相比,在遍历集合或数组时使用For EachNext循环将更快。在多数情况下,使用For EachNext循环也更方便,并且使您的宏更简洁、更容易阅读和调试。下面的示例运行很慢,因为在每次循环重复时它设置并调用了行变量.Row(i)。 Sub DoSomethingSlow() Dim Start As Double, Finish As Double Start = Timer - Dim Cell As Range, i As Long With She

25、et1.Range(A1:A10000) For i = 1 To 10000 Set Cell = .Rows(i) If Cell 0 Then Cell.Font.ColorIndex = 5 End If Next End With - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub下面的示例代码更简洁,其运行速度大约是上面代码的23倍。因为For EachNext循环自动记录行数并定位,而不需要调用变量i。Sub DoSomethingFaster() 快两至三倍 Dim Start As Double, Finish

26、As Double Start = Timer - Dim Cell As Range With Sheet1 For Each Cell In .Range(A1:A10000) If Cell 0 Then Cell.Font.ColorIndex = 5 End If Next End With - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub 在执行循环时考虑如何能够尽可能地节省资源(1)分析循环以查看是否正在不必要地执行一些消耗内存的重复操作。例如,是否可以在循环外(而不是在循环中)设置某些变量?每次都通过循环执行的转

27、换过程是否可以在循环之外执行?(2)考虑是否必须在满足特定的条件时才执行循环。如果是,也许可以更早地退出循环。例如,假设正在对一个不应该包含数字字符的字符串进行数据验证。如果循环要检查字符串中的每个字符以确定其中是否包含数字字符,那么您可以在找到第一个数字字符时立即退出循环。(3)如果必须在循环中引用数组的元素,可以创建一个临时变量存储该元素的值,而不是引用数组中的值。从数组中检索值比从相同类型的变量读取值要慢。(4) 将属性和方法放在循环外部在代码运行时,获取变量的值快于获取属性的值。因此,如果您的代码在循环内部获取属性的值,您可以在循环外部将该属性的值先指定给一个变量,然后在循环内部使用此

28、变量代替属性的值,这样的代码将运行得更快。下面所示的代码运行较慢,因为在每次重复循环时都必须获取Sheet的Range属性的值。 Sub TryThisSlow() Dim Start As Double, Finish As Double Start = Timer - Dim MyLoop As Long For MyLoop = 2 To 4001 Cells(MyLoop, 2) = Sheet1.Range(B1) Next - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub下面的示例与上面所产生的结果相同,但比上面的要

29、更快,因为在循环开始以前我们已经将Sheet的Range属性的值指定给了单独的变量MyVar。这样,代码将在每次重复循环时利用该变量的值,而不必每次都要调有属性。Sub TryThisFaster() 快约35%以上 Dim Start As Double, Finish As Double Start = Timer - Dim MyVar As String, MyLoop As Long MyVar = Sheet1.Range(B1) For MyLoop = 2 To 4001 Cells(MyLoop, 2) = MyVar Next - Finish = Timer MsgBox

30、 本次运行的时间是 & Finish - Start End Sub如果您在一个循环内部使用多个对象访问,您也可以使用WithEnd With将您能够移动的对象移到循环外部。下面的示例在每次循环重复时都调用Sheets对象和Cells属性。Sub NowTryThisSlow() Dim Start As Double, Finish As Double Start = Timer - Dim c As Long For c = 1 To 8000 Sheet1.Cells(c, 5) = c Next - Finish = Timer MsgBox 本次运行的时间是 & Finish - S

31、tart End Sub对上面的代码改写如下,使用With语句将调用Sheets对象移到循环外部,只剩余调用Cells。Sub NowTryThisFaster() 约快3倍 Dim Start As Double, Finish As Double Start = Timer - Dim c As Long With Sheet1 For c = 1 To 8000 .Cells(c, 5) = c Next End With - Finish = Timer MsgBox 本次运行时间为 & Finish - Start End Sub注:您也能通过使用对象变量在循环外部调用该对象。 使用

32、WithEnd With语句可以使用WithEnd With语句来尽量减少对象引用。使用With语句对指定的对象完成一系列的任务,而不用重复引用对象。也可以使用嵌套的With语句进一步提高程序代码的效率。例如,下面的使用WithEnd With语句是在同一个单元格中执行多个操作。 With Workbooks(Book1.xls).Worksheets(Sheet1).Range(A1) .Formula=SQRT(20) With .Font .Name=Arial .Bold=True .Size=10 End With End With同理,可使用WithEnd With语句在同一个单元

33、格区域中执行多个操作。 尽量减少OLE引用调用每个VBA方法或属性都需要一个或多个OLE引用,这样在代码中会有多个点运算符,而每次代码调用都需要对这些点运算符进行解析,这将花费更多的时间。因此,在调用方法或属性时减少引用长度将是使您的程序运行更快的一种好方法。可以通过尽量减少在VBA程序代码中使用OLE(对象链接与嵌入自动识别)引用来优化程序代码。VBA语句中所调用的方法和属性越多,执行语句所用的时间就越多。例如下面的两个语句:语句1: Workbooks(1).Sheets(1).Range(A1).value=10语句2:ActiveWindow.Left=200执行时,语句2比语句1快。

34、同样,上面所讲的对重复使用的对象引用指定一个变量,通过调用变量从而保证避免多次进行对象引用。 尽可能少使用“.”,使用对象变量在前面已经介绍过的对长对象引用使用对象变量以及使用WithEnd With等都是简化”.”的方法。因为在代码中的每个句点都表示至少一个(而且可能是多个)过程调用,而这些过程调用必须在后台执行。真正好的做法是在局部进行缓存对象引用,例如,应该把对象模型中较高层次的对象引用保存到局部对象变量中,然后用这些对象引用创建其他较低层次的对象引用。例如,引用某单元格数据时,可用如下代码: Dim i As Long For i=1 to 10 Workbooks(Book1.xls

35、).Worksheets(Sheet1).Cells(1,i).Value=i Next i但下面的代码运行效率更高,因为代码中引用Workbook对象和Worksheet对象的调用命令只执行一次,而上面的代码中却要执行10次。Dim ws As Worksheet Dim i As Long Set ws= Workbooks(Book1.xls).Worksheets(Sheet1) For i=1 to 10 ws.Cells(1,i).Value=i Next i当您一遍又一遍的使用相同对象引用时,您可以将该对象引用设置成一个变量,然后使用该变量代替对象引用。这样,您在代码中只需对该对

36、象变量进行引用即可。例如,下面的示例在每行中调用Workbook对象的Sheets属性、Range属性和Value属性三次,当您循环1000次时,总共要调用属性6000次。Sub DoThis1() Dim Start As Double, Finish As Double Start = Timer - Dim N As Long For N = 1 To 1000 Workbooks(Book1).Sheets(1).Range(c5).Value = 10 Workbooks(Book1).Sheets(1).Range(d10).Value = 12 Next - Finish = T

37、imer MsgBox 本次运行的时间是 & Finish - Start End Sub您能在循环开始前通过设置Workbooks(“Book1”).Sheets(1)作为一个对象变量来优化上面的例子,下面的示例在每行仅调用一个Range属性,当循环1000次时,总共只调用该属性2000次。注意,“Value”是一个缺省属性,通常不需要明确指定它,它将被自动调用。因此,该属性在下面的代码中被忽略。然而,就养成良好的编程习惯而言,还是建议您最好写明该属性。Sub DoThis2() 快约35%以上 Dim Start As Double, Finish As Double Start = Ti

38、mer - Dim ThisBookSheet As Object, N As Long Set ThisBookSheet = Workbooks(Book1).Sheets(1) For N = 1 To 1000 ThisBookSheet.Range(c5) = 10 ThisBookSheet.Range(d10) = 12 Next - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub您可以比较这两个示例的运行速度,它们都得到同样的结果,但在我的机子上运行时,第二个示例比第一个快60%。当然,您还能使用WithEnd W

39、ith语句获得相同的结果。您也能不设置明确的对象变量,而是使用With语句减少对象的重复引用。上面的示例也能使用下面的代码,该代码仅调用Workbooks属性和Sheets属性一次,当循环1000次时,总共调用1000次属性。Sub DoThis3() 快约35%以上 Dim Start As Double, Finish As Double Start = Timer - Dim N As Long With Workbooks(Book1).Sheets(1) For N = 1 To 1000 .Range(c5) = 10 .Range(d10) = 12 Next End With

40、- Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub上述三个示例均得到相同的结果,但在我的机子上运行时,本示例比第一个示例快50%以上。 在一个语句中进行复制或者粘贴在用宏录制代码时,首先是选择一个区域,然后再执行ActiveSheet.Paste。在使用Copy方法时,可以在一个语句中指定复制的内容及要复制到的目的地。例如,将B5:C6区域的内容复制到以单元格B8开始的区域中,使用宏录制器的代码为: Range(B5:C6).Select Selection.Copy Range(B8).Select ActiveSheet.Pa

41、ste经修改后的最佳代码是:Range(B5:C6).Copy Destination:=Range(B8) 合理地使用消息框和窗体在一个很长的程序中,尝试着将消息框或者窗体安排显示在程序的最开始或最后面,避免干扰用户。此外,尽管窗体提供了许多功能,但它们能够导致文件大小迅速增加。还有就是尽量避免给工作表单元格链接用户窗体控件,因为这样将会导致链接更新操作,影响程序运行速度。 尽可能加速对数字的运算(1)当对整数进行除法时,您可以使用整型除法运算符()而不是浮点除法运算符(/),因为无论参与除法运算的数值类型如何,浮点除法运算符总会返回Double类型的值。(2)在任何具有整数值的算术表达式中

42、使用Single或Double值时,整数均将被转换成Single或Double值,最后的结果将是Single或Double值。如果要对作为算术运算结果的数字执行多次操作,可能需要明确地将该数字转换为较小的数据类型。 提高字符串操作的性能(1)尽可能少使用连接操作。可以在等号左边使用Mid函数替换字符串中的字符,而不是将它们连接在一起。使用 Mid 函数的缺点是替换字符串必须与要替换的子字符串的长度相同。例如, Dim strText As String strText = this is a test Mid(strText, 11, 4) = tent(2)VBA提供许多可用来替换函数调用的

43、内部字符串常量。例如,可以使用vbCrLf常量来表示字符串中的回车/换行组合,而不是使用Chr(13) & Chr(10)。(3)字符串比较操作的执行速度很慢。有时,可以通过将字符串中的字符转换为 ANSI 值来避免这些操作。例如,下列代码会检查字符串中的第一个字符是否为空格:If Asc(strText) = 32 Then上面的代码会比以下代码更快:If Left(strText, 1) = Then 使用Asc()检验ANSI的值在VBA中,可以使用Chr$()函数把数转换成字符,并确定ANSI的值,但是更好的是使用Asc()函数把字符串转换成数值,然后确定它的ANSI值。如果需要进行有

44、限次数的这种检验,对程序代码的效率可能不会产生很大影响,但是,如果需要在多个循环内进行这种检验时,这将节省处理时间并且有助于程序代码更快地执行。 使用Len()检验空串尽管有多种方法可检验空串,但首选的是使用Len()函数。为了测试零长度的串,可以选择把串与”相比较,或者比较串的长度是否为0,但这些方法比用Len()函数要用更多的执行时间。当对字符串应用Len()函数并且函数返回0值时,说明该字符串是空的或者是零长度的字符串。并且,因为在If语句内非零值被认为是True,所以直接使用Len()函数而不必与”或0比较,减少了处理时间,因此执行更快。 有效地使用数组用VBA数组而不是单元格区域来处

45、理数据,即可以先将数据写入到某个数组,然后用一个语句就可以将数组中的数据传递到单元格区域中。(前文已述)在创建已知元素的确定数组时,使用Array函数对于节约空间和时间以及写出更具效率的代码是非常理想的。例如, Dim Names As Variant Names=Array(Fan,Yang,Wu,Shen)此外,应该尽量使用固定大小的数组。如果确实选择使用了动态数组,应该避免数组每增加一个元素就改变一次数组的大小,最好是每次增加一定数量的元素。 使用Excel的内置函数对于要实现的某一功能,如果有Excel的内置函数能够实现,那么就用Excel的内置函数,不需要另外自定义函数,因为自定义的

46、函数总比Excel内置的函数慢。考虑在VBA代码中使用工作表函数操作单元格区域的Excel工作表函数通常比完成同样任务的VBA程序更快(但不能确保总是这样,您可以对它们进行速度测试)例如,在代码中使用SUM工作表函数比用VBA代码在单元格区域中循环并相加值要快得多,以此为例,下面的代码运行速度相对较慢。 Sub AddItSlow() Dim Start As Double, Finish As Double Start = Timer - 为了进行测试,我们循环5次 Dim N As Long For N = 1 To 5 * Dim Cell As Range For Each Cell

47、In Worksheets(2).Range(A1:G200) a1 = a1 + Cell.Value Next Cell * Next N - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub下面的代码实现相同的功能,但运行得更快(几乎瞬间完成)。Sub AddItFaster() 快近600倍 Dim Start As Double, Finish As Double Start = Timer - 为了进行测试,我们循环5次 Dim N As Long For N = 1 To 5 * a1 = Application.Wo

48、rksheetFunction. _ Sum(Worksheets(2).Range(A1:G200) * Next - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub产生统计结果的函数(例如PRODUCT、COUNT、COUNTA和COUNTIF)是代替运行速度更慢的VBA代码的很好的选择,并且,一些工作表函数(例如MATCH和LOOKUP)能够将单元格区域作为参数。不要认为工作表函数总是更快的如下例所示,在VBA中没有Max或Min函数,但Excel中有该函数。于是,您能编写出如下代码:Sub MaxIt1() Dim Sta

49、rt As Double, Finish As Double Start = Timer - 为了测试,我们循环10000次 Dim N As Long For N = 1 To 10000 * J1 = Application.Max(J2, J3) * Next N - Finish = Timer MsgBox 本次运行时间是 & Finish - Start End Sub或者,您能在VBA中使用下面的方式实现相同的功能:Sub MaxIt2() Dim Start As Double, Finish As Double Start = Timer - 为了测试,我们循环10000次

50、Dim N As Long For N = 1 To 10000 * If J2 = J3 Then J1 = J2 Else J1 = J3 * Next N - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub比较上面的两个程序,可能认为使用工作表函数会更快,但事实上用VBA代码可以获得几乎相同的速度。因此,在一些大的循环中,您可以对实现同样功能的工作表函数的VBA代码进行测试。一些内置的VBA函数事实上运行速度也是慢的,因此,在编写代码时,在不同方式之间进行速度测试总是值得的。但是,在代码中经常使用的简单的函数,就直接编写代码

51、,而不是使用WorksheetFunction对象。 使用Range.SpecialCells()来缩小需要处理的单元格数。 只要有可能就使用集合索引值您能在集合中使用名称或者数字来指定某个单一的对象,但使用对象的索引值通常是更快的。如果您使用对象的名字,VBA必须解析名字成为索引值;但如果您使用索引值,就能避免这个额外的步骤。但另一方面,我们要注意到在集合中通过名称指定对象有很多优点。使用对象名称能使您的代码更容易阅读和调试。此外,通过名称指定一个对象比通过索引值更安全,因为当您的代码运行时该对象的索引值可能变化。例如,某菜单的索引值表示它在菜单栏中的位置,但是如果在菜单栏中添加了菜单或者删

52、除了菜单,该菜单的索引值会变化。这样,您就不应该考虑代码的速度,而应保证代码运行可靠。您使用索引值加快代码速度之前,应该确保该索引值在代码运行过程中或使用应用程序时不会改变。 使用完全受限制的对象引用使用完全受限制的对象引用消除了引用模糊并确保变量有明确的类型。一个完全受限制的对象引用包括了对象库名称,如下代码所示: Dim wb As Excel.Workbook如果您使用通用的对象数据类型声明变量和参数,在运行过程中VBA可能必须对它们的引用进行解析为(某对象的)属性和方法,这将导致速度变慢。一个通用对象数据类型示例如下:Dim wb As Workbook 使用已有的VBA方法也有一些特

53、定目的的VBA方法,它们提供在单元格区域执行特定操作的一种简单的方式。例如工作表函数,这些特定的方法比使用通常的VBA编码完成相同的任务要更快。最常用的是”Replace”方法和”Find”方法。Replace方法:下面的示例用了一种相当慢的方式代码改变单元格区域H1:H20000中每个单元格的值。 Sub NowDoThis1() Dim Start As Double, Finish As Double Start = Timer - Dim Cell As Range For Each Cell In Worksheets(1).Range(H1:H20000).Cells If Cel

54、l.Value = 4 Then Cell.Value = 4.5 Next - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End Sub下面的示例使用Replace方法进行同样的操作,但运行得更快。Sub NowDoThis2() 快约两倍 Dim Start As Double, Finish As Double Start = Timer - Worksheets(1).Range(H1:H20000).Replace 4, 4.5 - Finish = Timer MsgBox 本次运行的时间是 & Finish - Start End SubFind方法:下面的代码使用一种

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!