在 Excel 2019 中通过 sheet 内的按钮激活宏需要更多时间来执行

Macro takes more time to be executed when activated through button inside sheet in Excel 2019

我在 Excel 2019 中有一个宏,它 运行 直接通过 VBE(通过按 F5)不到一秒,或者当我在功能区中为宏配置按钮时(通过选项 > 自定义色带)。

当我在sheet区域内创建一个按钮(FormControlButton),并关联宏时,至少需要七秒。

宏 运行 没有任何错误消息。其他宏也较慢,但这一个是最引人注目的。

我的宏使用另一个 sheet 中的数据(约 4000 条记录)构建了一个锯齿状数组,然后按 bubble/quicksorting 对数组进行排序(都进行了测试以检查问题是否出在这里,但事实并非如此),然后在新的 sheet.

中过滤它和 returns 数据

宏是在Excel 2010年设计的,我在我们公司将Microsoft Office从2010更新到2019后立即注意到了这个问题。(Windows是在同一天从2007更新到10,但我认为问题出在 Excel,因为我在一些仍然装有 Office 2010 的 PC 上再次测试了它,宏的运行速度与 运行 通过 VBE 一样快)。管理员不禁止创建和编辑宏。

根据要求添加更多信息:

我没有添加代码,因为这不是特定宏的问题,但我注意到最慢的是那些与数组交互的代码。除此之外,因为我在 Office 2010 中使用 sheet 内的按钮时没有发生这种情况,可能是 Office 2019 中的一个错误。

我所有宏的一个共同点是我遵循微软的建议来加速宏,我使用了这段代码:

Sub SubName()

    Call DeactivateSystemFunctions

    'Rest of the code

    Call ReactivateSystemFunctions

    End Sub

在哪里

Sub DeactivateSystemFunctions()
    Application.ScreenUpdating = False
    Application.DisplayStatusBar = False
    Application.Calculation = xlCalculationManual
    Application.ActiveSheet.DisplayPageBreaks = False
    Application.EnableEvents = False
End Sub


Sub ReactivateSystemFunctions()
    Application.ScreenUpdating = True
    Application.DisplayStatusBar = True
    Application.Calculation = xlCalculationAutomatic
    Application.ActiveSheet.DisplayPageBreaks = True
    Application.EnableEvents = True
End Sub

我没有在我的任何宏中使用 .activate.select,并且在格式化时我总是尝试将最大值放在 With/End 中。

我的宏通过 VBE 运行良好,但在通过我的 sheet 中的 FormControlButton 激活时花费了太多时间。正如@RonRosenfeld 所建议的,我必须为代码的每个特定部分设置一个计时器,以找出问题所在。我将计时器放在代码的开头,我不得不将停止计时器的命令移动到它的每个部分,直到我发现它变慢的地方。

我的宏创建了一个锯齿状数组,然后通过快速排序对其进行排序,由于我进行的快速排序需要多个条件进行排序,我认为问题可能出在那里,因为它是一种递归方法。

但实际上当我在另一项工作中打印排序的锯齿状数组的结果时出现了问题sheet 我使用相同的宏创建。 我这样打印数据:

NewSheet.Cells(NewSheetRow, Column1) = SortedArray(RecordNumber)(DesiredInfo1 - 1)
NewSheet.Cells(NewSheetRow, Column2) = SortedArray(RecordNumber)(DesiredInfo7 - 1)
NewSheet.Cells(NewSheetRow, Column3) = SortedArray(RecordNumber)(DesiredInfo14 - 1)

'As my jagged array is built with data from a Source Worksheet:
'RecordNumber is the (Row - 1) in the source worksheet
'DesiredInfoX is the Column in the source worksheet

仅在打印特定列时出现问题。来源 sheet 有不同的列,每个列都有不同的数据格式。唯一减慢速度的数据格式是字符串。

我去了源码工作sheet,发现了一些问题:

  • 随着文件从 excel 2000 年到 2010 年再到 2019 年,数据没有迁移,只是从 .xls 保存到 .xlsm,当我走到源代码的末尾时 sheet,我注意到它只有 65536 行(不是预期的 1048576),但有 16384 列(last=XFD)。 它只发生在源 sheet 上,这是我们有更多数据的源。同一工作簿中的其他 sheet 具有预期的 1048576 行和 16384 列。

  • 在我们开始使用 excel 2019 之后,一些本应为字符串(文本)的数据被格式化为 GENERAL/NUMBER。我不能肯定这不是人为错误,但我们的来源 sheet 是由宏填充的,而不是由人为填充的,宏强制格式化每个数据。

我为解决问题所做的工作: 我使用 VBA 而不是 copy/paste 将所有数据从所有 sheet 迁移到新工作簿。将值传递给新源 sheet 后,我强制设置了每一列的格式。所有宏也必须迁移。

在那之后,sheet 中的 FormControlButton 的工作速度与通过按 F5 直接通过 VBE 激活宏一样快。

如果有人需要:

'###Timer code
'Got it from https://www.thespreadsheetguru.com/the-code-vault/2015/1/28/vba-calculate-macro-run-time
'Put this part in the beggining of your code
Dim StartTime As Double
Dim SecondsElapsed As Double

'Remember time when macro starts
  StartTime = Timer



'Put this part where you want the timer to stop
'Determine how many seconds code took to run
  SecondsElapsed = Round(Timer - StartTime, 2)

'Notify user in seconds
  MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation


'###Migration macro:
Sub Migrate()

Call DeactivateSystemFunctions

'Source File
Dim XLApp As Object
Dim WbSource As Object
Dim WsSource As Object

Set XLApp = CreateObject("Excel.Application")
XLApp.Visible = False    

Set WbSource = XLApp.Workbooks.Open("C:\FolderFoo\FolderBar\Desktop\SourceFileName.Extension")
Set WsSource = WbSource.Worksheets("SourceWorksheetName")


'Destination File. May be set as source file or if using this workbook by simply:
Dim WsDest As Worksheet    
Set WsDest = ThisWorkbook.Worksheets("DestinationSheetName")


Dim BDR As Long
Dim BDC As Long

Dim UltR As Long
Dim UltC As Long

UltR = WsSource.Cells(Rows.Count, 1).End(xlUp).Row
UltC = WsSource.Cells(1, Columns.Count).End(xlToLeft).Column

For BDR = 1 To UltR

    For BDC = 1 To UltC
        
        If WsSource.Cells(BDR, BDC) <> vbEmpty Then
        
            WsDest.Cells(BDR, BDC) = WsSource.Cells(BDR, BDC)
   
        End If
    
    Next BDC

Next BDR

'Format your columns as needed    
With WsDest
.Columns(Column1Number).NumberFormat = "0"
.Columns(Column2Number).NumberFormat = "dd/mm/yyyy"
.Columns(Column3Number).NumberFormat = "@"
.Columns(Column4Number).NumberFormat = "@"
.Columns(Column5Number).NumberFormat = "0.000"
End With


WbSource.Close SaveChanges:=False

Call ReactivateSystemFunctions

End Sub

TLDR:我遇到了同样的问题,我认为这是鼠标指针的问题。

我的解决方案:

Dim Cursor As XlMousePointer
Cursor = Application.Cursor
Application.Cursor = xlWait

-- YOUR CODE HERE --

Application.Cursor = Cursor

长版: 我在我的一个宏中注意到了一个类似的问题,它似乎发生在单独操作大量单元格时(即循环遍历数百或数千个单元格并更改它们的值)。

当您从 FormButton 或 ActiveX 按钮启动鼠标指针时,您可能会注意到鼠标指针会发生剧烈变化,但是当您从 VBE 启动宏时,它不会那样做。

在我的例子中,如果我将焦点从 excel window 上移开,宏甚至开始 运行 更快 - 就像将鼠标移到 [=28 上一样简单=] start-menu 按钮或 windows 任务栏中的应用程序改进了宏的性能。

我没有进一步研究这个,但我得出结论,鼠标指针的不稳定变化实际上是性能的杀手,所以我做了以下事情:

在更改单元格之前,我将鼠标指针设置为“默认”以外的值。当你这样做时,它会停留在那里,并且在你操作细胞时不会改变。之后我将鼠标指针设置为它在我的宏之前的任何状态。

从那以后我就没有遇到过同样的问题。