我的宏通过 VBE 运行良好,但通过工作表内的 FormControlButton 激活时花费了太多时间。正如@RonRosenfeld 建议的那样,我必须为代码的每个特定部分设置一个计时器,以找出问题所在。我将计时器放在代码的开头,我不得不将停止计时器的命令移动到它的每个部分,直到我发现它变慢了。
我的宏创建了一个锯齿状数组,然后通过快速排序对其进行排序,并且由于我所做的快速排序需要多个标准进行排序,我认为问题可能在那里发生,因为它是一种递归方法。
但实际上,当我在使用相同宏创建的另一个工作表中打印排序锯齿状数组的结果时,问题就发生了。我这样打印数据:
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
该问题仅在打印特定列时发生。源工作表有不同的列,每列都有不同的数据格式。唯一减慢速度的数据格式是字符串。
我去了源工作表并注意到一些问题:
由于文件从 excel 2000 到 2010 到 2019 并且数据没有迁移,而只是从 .xls 保存到 .xlsm,当我转到源工作表的末尾时,我注意到它只有 65536 行(不是预期的 1048576) , 但有 16384 列 (last=XFD)。它只发生在源工作表上,这是我们拥有更多数据的工作表。同一工作簿中的其他工作表具有预期的 1048576 行和 16384 列。
在我们开始使用 excel 2019 之后,一些应该是 String(Text) 的数据被格式化为 GENERAL/NUMBER。我不能肯定这不是人为错误,但我们的源表是由宏而不是人为填充的,并且宏强制每个数据的格式。
我为解决问题所做的工作:我将所有工作表中的所有数据迁移到使用 VBA 的新工作簿,而不是复制/粘贴。将值传递给新的源工作表后,我强制格式化每一列。所有宏也必须迁移。
之后,工作表内的 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