我可以使这个宏更有效或更快吗?

时间:2013-12-23 06:51:45

标签: excel vba excel-vba

我对编码很陌生。这个宏运行缓慢,我希望有人可以帮我清理它。在此先感谢您的帮助。

我开发了代码来更新我公司的“呼叫路由器”工作表,其中包含从外部来源购买的新线索。这些潜在客户以原始格式在名为Fresh Agents Leads的工作表中找到我们。一旦“Fresh Agent Leads”表被复制到包含“Call Router”工作表的“MSS Call Routing Master List”文件中,宏就会减少原始数据,以便消除我们不使用的部分。然后它重新格式化剩余的内容以匹配旧呼叫路由器工作表的格式并合并这两者。然后,它将新的主表重命名为Call Router。

该代码旨在从包含Fresh Agent Leads Sheet的工作簿内部开始。在执行代码之前,指示用户在桌面上打开Fresh Agents Leads File和MSS Call Routing Master List。

    Sheets("Fresh Agent Leads").Select
    Sheets("Fresh Agent Leads").Copy After:=Workbooks( _
        "MSS Call Routing Master List.xlsx").Sheets(1)
    Columns("F:F").Select
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Range("A1").Select
    Selection.Copy
    Columns("F:F").Select
    ActiveSheet.Paste
    Columns("A:A").Select
    Application.CutCopyMode = False
    Selection.Delete Shift:=xlToLeft
    Columns("C:C").Select
    Selection.Delete Shift:=xlToLeft
    Columns("E:E").Select
    Selection.Delete Shift:=xlToLeft
    Selection.Delete Shift:=xlToLeft
    Columns("G:S").Select
    Selection.Delete Shift:=xlToLeft
    Rows("1:1").Select
    Selection.Delete Shift:=xlUp
    Columns("C:C").Select
    Selection.Insert Shift:=xlToRight, CopyOrigin:=xlFormatFromLeftOrAbove
    Range("C1").Select
    ActiveCell.FormulaR1C1 = "=CONCATENATE(RIGHT(RC[1],4))"
    Range("C1").Select
    Selection.AutoFill Destination:=Range("C1:C1048575")
    Range("C1:C1048575").Select

    Sheets("Call Router").Select
    Rows("1:1").Select
    Selection.Copy
    Sheets("Fresh Agent Leads").Select
    Rows("1:1").Select
    Selection.Insert Shift:=xlDown
    Application.CutCopyMode = False
    Application.Run "PERSONAL.xlsb!MergeIdenticalWorksheets"
    Columns("C:C").Select
    Selection.NumberFormat = "0000"
    Range("A:A,B:B,F:F").Select
    Range("F1").Activate
    Selection.ColumnWidth = 14
    Columns("E:E").Select
    Selection.ColumnWidth = 25
    Columns("C:C").Select
    Selection.ColumnWidth = 8.29
    With Selection
        .HorizontalAlignment = xlCenter
        .VerticalAlignment = xlBottom
        .WrapText = False
        .Orientation = 0
        .AddIndent = False
        .IndentLevel = 0
        .ShrinkToFit = False
        .ReadingOrder = xlContext
        .MergeCells = False
    End With
    Rows("1:1").Select
    Selection.RowHeight = 30
    With Selection
        .VerticalAlignment = xlBottom
        .WrapText = True
        .Orientation = 0
        .AddIndent = False
        .ShrinkToFit = False
        .ReadingOrder = xlContext
        .MergeCells = False
    End With
    With Selection.Interior
        .Pattern = xlSolid
        .PatternColorIndex = xlAutomatic
        .ThemeColor = xlThemeColorLight1
        .TintAndShade = 0
        .PatternTintAndShade = 0
    End With
    With Selection.Font
        .ThemeColor = xlThemeColorDark1
        .TintAndShade = 0
    End With
    Columns("D:D").Select
    Selection.EntireColumn.Hidden = True
    Range("E2").Select
    ActiveWindow.FreezePanes = True
    Sheets(Array("Call Router", "Fresh Agent Leads")).Select
    Sheets("Call Router").Activate
    ActiveWindow.SelectedSheets.Delete
    Sheets("Master").Select
    Sheets("Master").Name = "Call Router"
    Range("C23").Select
    ActiveSheet.Protect DrawingObjects:=True, Contents:=True, Scenarios:=True
    ActiveWorkbook.Save
End Sub

3 个答案:

答案 0 :(得分:9)

虽然这段代码几乎属于CR而不是SO,因为我手上有很多时间,但我决定至少发布一些关于代码的内容。

===

一些提示:

  1. 尽可能避免使用.Select.Activate。录制宏是VBA的一个良好开端,但第一个重要的步骤是离开"舒适区"由这些属性提供。一开始,他们很好,但从长远来看,他们必然会产生问题。

  2. 阅读以下内容"基本"过程:复制/粘贴/插入范围,创建/删除工作表,以及确定具有相关数据的工作表或范围的最后行/列。这三个是你最好的朋友。通过学习这三个,您可以在Excel VBA中进行大量操作。

  3. 在(2)之后,开始学习如何标注变量和/或对象。把行话放在一边,这基本上就像给你正在处理的每件重要的东西"昵称"。假设您正在处理3张纸。您不想继续引用ThisWorkbook.Sheets("Sheet1")等等。您更愿意改为Sh1Sh2

  4. 了解如何使用UnionWith等将相似程序捆绑在一起。这与上面的(1)同时进行。您稍后会看到一个示例。

  5. Application.ScreenUpdating - Excel VBA中最佳时间削减技巧之一。

  6. 现在,一些样本:

    (1)避免.Select ||学习使用非常好的.Copy单行

    这部分......

    Range("A1").Select
    Selection.Copy
    Columns("F:F").Select
    ActiveSheet.Paste
    

    ...可以简化为:

    Range("A1").Copy Range("F:F")
    

    从四行到一行。而且它更具可读性。上面的第二个代码片段基本上是读取"将A1的值复制到整个F列"。请注意,这实际上是内存密集型的,因为在Excel 2010中,您实际上使用该命令粘贴到了一百万行以上。更具体,如Range("F1:F1000")

    (2)聚集命令

    在"书面"中拼凑命令VBA与您在宏中的方式不同。由于记录了宏,所以一切都基于实时修改。在"书面"在VBA中,您可以指定一个操作,允许您对多个对象应用单个操作。例如,我们想要删除列A和C,同时将所有相关数据移到左侧。

    录制宏时,您可以同时选择A和C并删除它们。但是,大多数初学者采取安全路径并一次记录一个列的删除 - 虽然安全 - 非常违反直觉。在删除之前选择两者是最佳选择。

    在书面VBA中,上面的第二种方法是大规模的禁忌(或者至少,它不是常态)。除非有特定和必要的原因,否则将类似命令捆绑在一起就是惯例,因为它既可以在很大程度上消除错误,又不会占用大量资源。

    在您的代码中......

    Selection.Delete Shift:=xlToLeft
    Columns("C:C").Select
    Selection.Delete Shift:=xlToLeft
    Columns("E:E").Select
    Selection.Delete Shift:=xlToLeft
    Selection.Delete Shift:=xlToLeft
    Columns("G:S").Select
    Selection.Delete Shift:=xlToLeft
    

    ......读起来真是太痛苦了。我们不知道为什么有两个删除,我们不确定列S中的数据原始位置等等。在这样的情况下,提前确定您想要的范围删除和执行删除是完美的方式。

    让我们假设您要将A,C,E和F列删除为O.如下所示,一个简洁的方法可以非常快速有效地解决这个问题。

    Union(Range("A:A"),Range("C:C"),Range("E:E"),Range("F:O")).Delete
    

    Union是你早期最好的朋友之一。与数学中的集合表示法一样,您指定的范围将一起放在一组范围中并同时处理(在这种情况下,.Delete d同时执行)。由于默认移位在左侧,我们可以完全删除Shift:=xlToLeft行(另一个漂亮的VBA事实)。

    (3)With - 有一件事你不能没有

    此时,你可能在想,这些范围内的多个动作怎么样?我们只对多个范围进行了单一操作,而不是相反。这就是With的用武之地。在此上下文中,With仅在Ranges上使用,但它几乎可用于VBA中的任何内容。对象,范围,外部应用程序等等。我不会深思熟虑,但只需说使用With就像在一些程序中使用锚点就可以了。

    在您的代码中,我们发现......

    Columns("C:C").Select
    Selection.ColumnWidth = 8.29
    With Selection
        .HorizontalAlignment = xlCenter
        .VerticalAlignment = xlBottom
        .WrapText = False
        .Orientation = 0
        .AddIndent = False
        .IndentLevel = 0
        .ShrinkToFit = False
        .ReadingOrder = xlContext
        .MergeCells = False
    End With
    Rows("1:1").Select
    Selection.RowHeight = 30
    With Selection
        .VerticalAlignment = xlBottom
        .WrapText = True
        .Orientation = 0
        .AddIndent = False
        .ShrinkToFit = False
        .ReadingOrder = xlContext
        .MergeCells = False
    End With
    

    ......可以简化为:

    With Columns("C:C")
        .ColumnWidth = 8.29
        .HorizontalAlignment = xlCenter
    End With
    With Rows(1:1)
        .RowHeight = 30
        .WrapText = True
    End With
    

    基本上,我们在这里做了两件事。首先,我们锚定在C列上,并对其执行了两个操作:设置列宽,然后设置水平对齐。在锚定到C列并修改它之后,我们将锚更改为整个第1行,我们修改它的高度并将其设置为将文本换行到单元格宽度。从24行开始,我们将宏块减少到只有8行。为简洁起见,这是怎么回事? :)

    为什么我没有其他线路?与前面的示例(Union)一样,我们可以使用一些无论如何都是默认值或未修改的行。这些会有例外情况,但它们会很少而且现在有点偏离你的水平。你会到达那里。

    (4)创建/修改工作表并避免.Activate,并触及维度

    VBA初学者的一个缺陷是他们经常使用ActiveWorkbookActiveSheet.Activate。这本身并不坏,但它也不好。它使用起来很方便,但如果将它合并到非常复杂的子程序和函数中,它会引起无数的麻烦。

    为了解决这个问题,我们首先考虑对对象进行尺寸标注或限定。这是通过首先声明关键字然后声明数据类型来完成的。我不会深入研究这个问题,因为你可以阅读很多VBA教程,所以我只想指出一些重要的教程。

    我们假设您正在处理两个开放工作簿。我们可以创建一个"昵称"对于他们每个人,所以你可以参考他们而不必输入整行参考。

    Dim SourceWbk As Workbook
    Dim TargetWbk As Workbook
    

    以上两行显示为" SourceWbk / TargetWbk是我的昵称,我的工作手册属于工作簿,所以我希望能够将其引用到工作簿中#34 ;.现在我们已经为它们创建了尺寸,我们可以指出它们将代表什么。

    Set SourceWbk = ThisWorkbook
    Set TargetWbk = Workbooks("I AM THE MASTER REPORT")
    

    注意&#34; =&#34;这里。现在,我们基本上宣称从现在起,SourceWbk将引用包含此代码的工作簿,而TargetWbk将引用 open < / em> 工作簿名为&#34;我是主要报告&#34;。现在让我们看一下将表单从SourceWbk复制到TargetWbk的简单操作。

    SourceWbk.Sheets("Sheet1").Copy After:=TargetWbk.Sheets("Sheet1")
    

    看起来很熟悉?这是因为这与您记录的代码块几乎相同:

    Sheets("Fresh Agent Leads").Select
    Sheets("Fresh Agent Leads").Copy After:=Workbooks( _
        "MSS Call Routing Master List.xlsx").Sheets(1)
    

    现在,您可以更进一步,自己命名表单,然后复制它们。示例如下:

    Dim FAL As Worksheet 'Expects a worksheet.
    Dim LastSheet As Worksheet
    
    Set FAL = SourceWbk.Sheets("Fresh Agent Leads")
    Set LastSheet = TargetWbk.Sheets("Sheet1") 'You can use a number index or specific name
    
    FAL.Copy After:=LastSheet
    

    此时代码已经非常非常短而且很甜蜜。没有麻烦,你真正需要的唯一努力就是记住&#34;昵称&#34;参考。请注意,您应该使用特定字词作为变量名称。尽可能使其个性化但合理。简单地将工作表命名为Sh是好的,但它可以让您无法在一个文件中找到100张不同用途的文件。

    (5)Application Trickbook

    在Excel VBA中,您可以通过一些操作来提高代码的效率。毕竟说完了,宏只是一个重复的动作。运行录制或书面录制将带您完成操作。 .Select会选择特定范围,您会看到它们被选中。 .Activate会或多或少地做同样的事情。 .Copy会告诉你那些&#34;蚂蚁&#34;以及他们留下的亮点。所有这些都有助于实现代码的更长且通常草率的可视化执行。这里是ScreenUpdating&#34;技巧&#34;。

    的步骤

    请注意,它并非真正的伎俩。大多数人认为它们是代码中非常重要的部分,但是它们被包含在&#34;外行&#34; VBA模块仍然很有用。最佳做法之一是在子例程开始时设置Application.ScreenUpdating = False,然后在结束时将其设置回True

    ScreenUpdating将&#34;冻结&#34;你的屏幕,无需你看到它们就能完成所有事情。您不会看到要复制的项目或范围被选中。您不会看到关闭的工作簿被打开和关闭。虽然这只会在你打电话时影响Excel,但它仍然具有无可估量的价值。

    快速而脏的列表(不要将其用作绝对引用!)Application技巧:

    • .ScreenUpdating(False / True ):在False时消除Excel的可视更新。复制粘贴或删除行时绝对必要。
    • 。计算( xlCalculationAutomatic / xlCalculationSemiautomatic / xlCalculationManual):与Formulas > Calculation Options功能区功能类似,将其设置为手动将暂停所有计算。强烈推荐,尤其是当您更新VLOOKUPINDEX公式所需的范围时。
    • .EnableEvents(False / True ):禁用基于触发事件的过程。有点高级,但足以说如果您在基于事件的更改中获得了一些自动宏触发,这将暂停它们以支持当前运行的宏。

    还有很多其他人,了解大部分内容都符合您的最佳利益。 ;)

    THE BIG FINALE

    以下是从录制的宏中获取的示例代码,它使用了上述所有技术,并考虑了您在宏上执行的步骤。 这不是您的全部代码。 阅读本文,测试一下,修改此内容,您将在一天内取得很大进步。

    Sub RefinedCode()
    
        Dim SourceWbk As Workbook, TargetWbk As Workbook
        Dim FALSht As Worksheet, FALSht2 As Worksheet, MasterSht As Worksheet
    
        Application.ScreenUpdating = False 'We won't see the copy-paste and column deletion happening but they will happen. 
    
        Set SourceWbk = ThisWorkbook
        Set TargetWbk = Workbooks("MSS Call Routing Master List")
        Set FALSht = SourceWbk.Sheets("Fresh Agent Leads")
    
        With TargetWbk          
            Set MasterSht = .Sheets("Master") 'Basically reads as Set MasterSht = TargetWbk.Sheets("Master")
            FAL.Copy After:= .Sheets(1)
            Set FALSht2 = .Sheets("Fresh Agent Leads")
        End With
    
        With FALSht2
            Union(.Range("A:A"),.Range("C:C"),.Range("E:O")).Delete
            With .Rows(1)
                .RowHeight = 30
                .WrapText = True
            End With
            .Range("A1").Copy .Range("F1:F100")
        End With
    
        MasterSht.Name = "Call Router"
        TargetWbk.Save
        SourceWbk.Close
    
        Application.ScreenUpdating = True 'Return to default setting.
    
    End Sub
    

    希望这有帮助。

答案 1 :(得分:0)

我总是使用以下行

Application.ScreenUpdating = False

关闭屏幕更新,使宏运行速度更快。只需将其添加到宏的开头。

答案 2 :(得分:0)

这里有很棒的帮助。我希望有一种简单的方法可以在更换工作表时停止闪烁... Application.ScreenUpdating并不能完全消除excel 2013中的闪烁。