问题
I have a macro in excel 2019 which runs in less than 1 second directly through VBE (by pressing F5), or when I configure a button to the macro in the Ribbon (through options>customize ribbon).
However, when I create a button (FormControlButton) inside the sheet area, and associate the same macro to this button, the macro takes at least 7 seconds to run.
In any case, the macro runs normally, without any error message, just the delay when activated through the button inside the sheet. Other macros are slower as well, but this one is the most noticeable.
If this information helps, my macro builds a jagged array with data (~4000 records) that is in another sheet, then sorts the array by bubble/quicksorting (tested both to check if the problem could be here, and it wasn't), then filters it and returns data in a new sheet.
The macros where designed in excel 2010, and I noticed the problem right after our company updated microsoft office from 2010 to 2019. (Our windows was updated the same day from 2007 to 10, but I think the problem is in excel, as I tested it again in some of our PCs that still had office 2010 and the macros worked as fast as if run through VBE). Creating and editing macros is not prohibited by administrators.
Does anybody have an idea of what may be happening?
Adding more information as requested:
I didn't add code because it's not a problem of a specific macro, but I noticed the ones that slowed down the most are the ones that interact with arrays. Besides that, as it didn't happen when I used buttons inside a sheet in office 2010, maybe it's a bug in office 2019.
One thing in common in all my macros is that I follow microsoft's recommendations to speed up macros, and I use this chunk of code in them:
Sub SubName()
Call DeactivateSystemFunctions
'Rest of the code
Call ReactivateSystemFunctions
End Sub
Where
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
I don't use .activate or .select in any of my macros, and while formatting I always try to put the max inside a With/End With
Thanks in advance
回答1:
Well, I'm posting an answer to my own question because this is what worked for me, maybe it will work for you too if you encounter the same problem.
My macro was working fine through VBE but taking too many time when activated through a FormControlButton inside my sheet. As @RonRosenfeld suggested, I had to set a timer to each specific part of my code to find where the problem was. I put the timer at the beggining of my code and I had to move the command to stop the timer to each part of it until I found where it was getting slow.
My macro creates a jagged array and then sorts it through Quicksorting, and as the quicksort I made takes more than one criteria to sort, I thought the problem might be occurring there, as it is a recursive method.
But actually the problem was happening when I was printing the results of the sorted jagged array in another worksheet I create using the same macro. I print data this way:
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
The problem happened only when printing specific Columns. The source sheet has different columns, each with a different data format. The only data format that slowed things down was strings.
I went to the source worksheet and noticed some problems:
As the file went from excel 2000 to 2010 to 2019 and data was not migrated but simply saved from .xls to .xlsm, when I went to the end of the source sheet, I noticed it had only 65536 rows (not 1048576 as expected), but had 16384 columns (last=XFD). It was only happening with the source sheet, which is the one we have more data in. Other sheets in the same workbook had the expected 1048576 rows and 16384 columns.
After we started using excel 2019, some of the data that was supposed to be String(Text), was formatted as GENERAL/NUMBER. I can't affirm it was not human error, but our source sheet is filled by macro, not by human, and the macro forces formatting of each data.
What I did to solve the problem: I migrated all data from all sheets, to a new workbook using VBA, not copy/paste. After passing the values to the new source sheet, I forced the formatting of each column. All macros had to be migrated as well.
After that, the FormControlButton inside the sheet is working as fast as activating the macro directly through VBE by pressing F5.
If anybody needs:
'###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
来源:https://stackoverflow.com/questions/57256541/macro-takes-more-time-to-be-executed-when-activated-through-button-inside-sheet