【问题标题】:Trying to make my VBA run a little bit faster试图让我的 VBA 运行得更快一点
【发布时间】:2023-01-07 12:50:35
【问题描述】:

我是 VBA 的新手,所以我的代码通常非常慢/未优化。

在我的一个程序中,当用户按下按钮时,工作表中有一些单元格必须填充,这些单元格会根据按钮而变化,但概念是相同的。

所以我做了这个怪物:

Cells((Range("namedrange").Row + 5), 1).Value = ThisWorkbook.Sheets(5).Cells(4, 7).Value
Cells((Range("namedrange").Row + 5), 3).Value = ThisWorkbook.Sheets(5).Cells(4, 8).Value
Cells((Range("namedrange").Row + 5), 5).Value = ThisWorkbook.Sheets(5).Cells(4, 9).Value
Cells((Range("namedrange").Row + 5), 8).Value = ThisWorkbook.Sheets(5).Cells(4, 10).Value
Cells((Range("namedrange").Row + 5) + 1, 1).Value = ThisWorkbook.Sheets(5).Cells(5, 7).Value
Cells((Range("namedrange").Row + 5) + 1, 3).Value = ThisWorkbook.Sheets(5).Cells(5, 8).Value
Cells((Range("namedrange").Row + 5) + 1, 5).Value = ThisWorkbook.Sheets(5).Cells(5, 9).Value
Cells((Range("namedrange").Row + 5) + 1, 8).Value = ThisWorkbook.Sheets(5).Cells(5, 10).Value

但后来改为:

    With Range("namedrange")
        .Offset(5).Columns(1).Value = ThisWorkbook.Sheets(3).Cells(4, 7).Value
        .Offset(5).Columns(3).Value = ThisWorkbook.Sheets(3).Cells(4, 8).Value
        .Offset(5).Columns(5).Value = ThisWorkbook.Sheets(3).Cells(4, 9).Value
        .Offset(5).Columns(8).Value = ThisWorkbook.Sheets(3).Cells(4, 10).Value
        .Offset(6).Columns(1).Value = ThisWorkbook.Sheets(3).Cells(5, 7).Value
        .Offset(6).Columns(3).Value = ThisWorkbook.Sheets(3).Cells(5, 8).Value
        .Offset(6).Columns(5).Value = ThisWorkbook.Sheets(3).Cells(5, 9).Value
        .Offset(6).Columns(8).Value = ThisWorkbook.Sheets(3).Cells(5, 10).Value
    End With

这有点快,但我觉得它仍然没有优化。我想知道是否有办法让它更清洁/更优雅。 请注意,列中存在不连续性,例如它从第一列开始,然后跳到第三列,然后跳到第五列,最后跳到第八列。

该代码有效但速度很慢,我只是想要一种使其更快/更清洁的方法。

【问题讨论】:

  • 您可以停止屏幕刷新以获得更高速度的常用方法。而这个操作是不是要循环多次呢?
  • 如果 ThisWorlbook.Sheets(3) 在编译时存在,那么您可以使用它的代号,而不是从 Sheets 集合中重新提取它。 Sheet3.Cells(...)
  • 还要注意隐式 ActiveSheet 和 ActiveWorkbook 引用,它们是错误的常见来源。 Rubberduck 可以提供帮助。
  • 非常感谢,我对这个评论线程不太了解......但我会研究它们并尝试实施它。

标签: excel vba optimization return-value with-statement


【解决方案1】:

使用变量

  • 关于效率,仅此而已:您正在使用最有效的方式将值从一个单元格复制到另一个单元格赋值复制.
  • 如果您希望它更加灵活、可维护和可读(?),这里有一些想法。
  • 此外,您可以将剩余的幻数和文本移至代码开头的常量,甚至可以将常量用作参数。
Sub CopyValues()
    
    Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
    
    ' Specify the worksheet if you know it.
    'Dim dnrg As Range: Set dnrg = wb.Sheets("Sheet1").Range("NamedRange")
    ' Otherwise, make sure the workbook is active.
    If Not wb Is ActiveWorkbook Then wb.Activate
    Dim dnrg As Range: Set dnrg = Range("NamedRange")
    
    Dim drg As Range: Set drg = dnrg.Range("A1,C1,E1,H1").Offset(5)
    Dim cCount As Long: cCount = drg.Cells.Count
    
    ' If you know the tab name, use it instead of the index (3).
    Dim sws As Worksheet: Set sws = wb.Sheets(3)
    Dim srg As Range: Set srg = sws.Range("G4").Resize(, cCount)
    
    Dim r As Long, c As Long
        
    For r = 0 To 1
        For c = 1 To cCount
            drg.Offset(r).Cells(c).Value = srg.Offset(r).Cells(c).Value
        Next c
    Next r

End Sub

【讨论】:

  • 我明白了,这段代码看起来非常好,非常感谢您的回答,但我看到的一个问题是 ´´´dnrg.Range("A1,C1,E1,H1")´´´ 部分的使用因为工作表不断更新并且这些单元格的值也会修改,这就是我使用命名范围和偏移量的原因。我可以更改代码的这个特定部分以获得不变的东西吗?就像你做的'''dnrg.Range(“A1,C1,E1,H1”)''',但不是A1,C1等,我会把命名范围作为参考。
【解决方案2】:

我想知道如果你使用会发生什么全部.Offset 参数,行和列。例子:

With Range("namedrange")
    .Offset(5, 0).Value = ThisWorkbook.Sheets(3).Cells(4, 7).Value
    .Offset(5, 2).Value = ThisWorkbook.Sheets(3).Cells(4, 8).Value
    .Offset(5, 4).Value = ThisWorkbook.Sheets(3).Cells(4, 9).Value
    .Offset(5, 7).Value = ThisWorkbook.Sheets(3).Cells(4, 10).Value
    .Offset(6, 0).Value = ThisWorkbook.Sheets(3).Cells(5, 7).Value
    .Offset(6, 2).Value = ThisWorkbook.Sheets(3).Cells(5, 8).Value
    .Offset(6, 4).Value = ThisWorkbook.Sheets(3).Cells(5, 9).Value
    .Offset(6, 7).Value = ThisWorkbook.Sheets(3).Cells(5, 10).Value
End With

【讨论】:

    【解决方案3】:

    从 VBA 访问 Excel 的值是一个缓慢的操作,当您发出多个请求时,这会加起来。当您实际上是在重复检索相同的信息时,可以使用两种方法来减少访问时间。

    1. 用计算值替换查找
    2. 使用 with 语句

      因此你的代码可以写成

      Dim myCol as long 
      myCol =Range("namedrange").Row + 5
      
      With ThisWorkook.Sheets(5)
          Cells(myCol, 1).Value = .Cells(4, 7).Value
          Cells(myCol, 3).Value = .Cells(4, 8).Value
          Cells(myCol, 5).Value = .Cells(4, 9).Value
          Cells(myCol, 8).Value = .Cells(4, 10).Value
          myCol=myCol+1 ' trivial example
          Cells(mycol, 1).Value = .Cells(5, 7).Value
          Cells(myCol, 3).Value = .Cells(5, 8).Value
          Cells(myCol, 5).Value = .Cells(5, 9).Value
          Cells(myCol, 8).Value = .Cells(5, 10).Value
      End with
      

      还请为 VBA 安装免费、开源和出色的 Rubberduck 插件。代码检查将帮助您编写更正确的 VBA。

    【讨论】:

      【解决方案4】:

      您可以尝试在执行期间禁用屏幕更新。

      禁用屏幕更新

      1. 要禁用 ScreenUpdating,请在代码开头放置以下行:
        Application.ScreenUpdating = False

        启用屏幕更新

        1. 要重新启用 ScreenUpdating,请在代码末尾放置以下行:
          Application.ScreenUpdating = True

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-02-15
        • 1970-01-01
        • 2011-05-10
        • 2017-03-19
        • 2018-08-23
        • 1970-01-01
        • 2011-04-30
        相关资源
        最近更新 更多