troubleshoot excel flickering in formula window after vba calculate event - vba

Symptoms
After completing a VBA macro that runs whenever a calculation event occurs, my workbook enters a strange semi-lock state. The symptoms are:
When highlighting any cell with contents, the formula bar or window flickers several times per second.
I can enter formulas and formula arrays in any blank cell and calculation proceeds as normal, although flickering continues.
Switching between auto/manual calculate has no effect on the flickering.
The array formulas associated with the calculation event take on a strange property: While editing them in the formula bar, if I press ENTER nothing happens. Normally for an array formula I would get an error, but for these, the cursor just stays in the formula editing window unless I press CTRL+SHIFT+ENTER. See below for relevant details on the application.
For context:
My application is a VBA add-in that uses UDF's to pull read-only data from a remote MySQL server. The workflow involves piggy-backing on the calculate event in order to get around the fact that excel UDF's can't alter the size of the formula that is calling them. The process goes:
user enters formula
formula creates a 'query' item that is stored in a global collection
upon calculation, a subroutine processes all the queries, sends SQL queries to the remote database, receives the response, resizes the formula region to fit the size of the returned data, and stores the returned data in another global collection
when the calling region is resized, the formula function automatically runs again. This time, it sees that data is waiting in the second global collection and that the data is the right size, and it writes the data to the worksheet, preserving the formula
Based on the debug window, it looks like my calculate event has finished when the flickering begins to occur. All of my global collections are empty. I'm not sure what the application is doing when it locks in this way or how to get more data on the problem. It only occurs occasionally.
Has anyone encountered something like this before?

Hopefully it helps someone who has the same or similar problem. In my case there were no formulas in workbook and no calculate events. Still - after macro executed, values populated by the macro in formula window were flickering.
After debugging, it came out that on line with array paste, macro was repeatedly going back to start of procedure, while pasting only part of data. After I fixed calculation of array values, so that arguments for timeserial functions were correct, pasting complete array succeeded without retreating to start of sub.

Related

Is there an event in Excel that runs when the application opens and before cells are calculated?

I'm trying to prevent Excel from recalculating cells containing my UDFs (because they run slowly).
My aim is to cache all the cell values by address in a dictionary store when the application first loads, the UDF will return a value from the store if it exists, otherwise it'll do a full recalculation.
I've attempted using the Workbook_Open() event to gather all the formulas in the sheet when the application loads. My issue is that the Workbook_Open() event fires after excel tries to recalculate all the cells.
Is there an event that runs before Workbook_Open()?

Pause VBA Macro to allow manual input of data

I have an Excel workbook macro that opens another workbook and starts copying data into it and formatting it. At one point in the process, I want the macro to pause and let the user manually enter data into the target workbook and then resume processing.
MsgBox, Application.Wait(), and Sleep are all application modal and will not let the user update anything in the other workbook while they are executing.
I found this while searching for a solution. It gets me halfway there in that I can manipulate the other sheet but only with my mouse. No keyboard presses get sent to the workbook.
Any ideas on getting all the way there?
I was thinking that I could just have two macros. The user would run one, then perform his manual tasks, then run the other. This appears to work but I would have to convert everything to globals so hopefully, someone has a better idea.
Thanks!
Depending on the macro being run to copy and paste, is the main concern with user intervention during execution of the macro getting the active cell/sheet (if being used) back to being active after the user manipulates something.
I'd recommend storing the active cell/sheet address in a variable prior to the Application.Wait() and then setting the active cell to that stored value on resume.
Without a posting of what your macro is doing though, it is hard to know if this suggestion helps your current situation.

Using Excel while macros are running

There are a half-dozen answers to this. "Open a second instance" "Have a pause" Etc. I'm not looking for that.
I'm looking for the user of the workbook to be able to manipulate the workbook while the macro is running. I've seen this working before, where the user could scroll around, change tabs, even add and remove data, all while the macro was running. Unfortunately, I couldn't get permission to look at the code (And committing CFAA violations ins't my cup of tea), so I have no idea how they did it.
How can you enable a user to edit the workbook as macros are running? For a specific example, I have Conway's Game of Life running. Users select cells to flip live/dead, then can run a macro to run the entire thing. I think it'd be nice for users to be able to change cells as the macro is running. (which is a second on select macro)
Thank you
Sorry just reread the question. I wouldn't expect the permutation to run for very long - not long enough to interrupt really.
But if it does, then the advice about using lots of DoEvents stands.
The other option is that you can use the OnTime event to have a "heartbeat"
VBA Macro On Timer style to run code every set number of seconds, i.e. 120 seconds
You can set the timer to say 3 seconds. Every time the OnTime event occurs you do one step of your permutation. In the three seconds in between they can edit.
Refactor your macro to use Events. In which case, you would have a series of event handlers (instead of one monolithic macro) to respond to various triggers. This is assuming that the macro is influenced by what the user is doing in the worksheet.
One way of (sort of) doing this is to use a Modeless Userform (UserForm.Show vbModeless)
The user form stays visible but the VBA stops running when the form is shown and the user can then interact with Excel. Then when the user clicks a button on the form the code behind the button starts running again.
So in reality the user is either interacting with Excel or interacting with the form ...

Refresh UserForm without refreshing worksheet

While working with Excel, I have many times faced the problem with Screen Refreshing.
Most of the time, in order to speed up VBA, programmers will use Application.ScreenUpdating = False. This will temporarily (until cancelled) stop screen refreshing. Unfortunately, there are cases, such as implementing progress bar, when you actually want to show some progress to the user. The problem is that the already mentioned command has stopped all screen refreshing.
This means, that even if on your UserForm you call a command to change a label (e.g. which would state Processing transaction 15 of 250) but you simply cannot get it to display.
What some people do in this case, is to temporarily enable ScreenUpdating, and right away disable it. This procedure is unfortunately unreliable, as if you have some difficult procedure (inserting complex formulas into cells) you are not guaranteed all the time that it will also refresh the label itself. Also the problem with this approach is, that you repaint not only your desired UserForm, but also Worksheet as well, and therefore this 'refresh' slows down your code quite a bit.
How can you refresh UserForm without refreshing the whole Excel?
The answer is simple.
Let's say that your userform is named frm_Main, so then in your VBA code you can simply call frm_Main.Repaint.
Simple as that!

Is it possible to undo a macro action? [duplicate]

This question already has answers here:
Building Undo Into an Excel VBA Macro
(3 answers)
Closed last year.
I want to know if we can undo the macro action by any chance. I am using the excel sheet as a form and I am having a submit button(Macro) which takes the sum of counts of the sheet(based on the form input) and stores it in the next sheet.
My problem is, if we press the submit button without completing it or if we press it twice, the sum which I store in the next sheet, becomes inaccurate. If there a way we can undo the macro actions in excel? I tried using the undo button, but it didn't work for macros. Is there a way we can undo it?
Can we add another macro which would undo the previous macro's work?
I agree with all the commenters who've suggested that the best practice is to validate the starting conditions and/or input values before allowing the macro to make any changes. However, validation is often very complex and totally impractical in a lot of "we need it now" situations.
Here are two very easy things I can suggest:
1) Have the macro save the workbook before any changes are made, but not save the workbook after the changes have been made. This way, if you see something went wrong, you can just close and reopen the workbook and you'll be back to where you were before the macro did whatever the macro does.
2) Have the macro save copies of any affected worksheets before taking any action, so, if things go wrong, you can revert (or create a macro to revert) back to the starting point.
The first option requires the least amount of code, just:
ThisWorkbook.Save
before letting the macro do whatever the macro does.
I frequently use this method when testing macros.
The second option is a little more complex, but not much:
ThisWorkbook.Worksheets("YourWorksheet").Copy(After:=ThisWorkbook.Worksheets("NameOfSheetYouWantItToAppearAfter")
Note that this will activate the copy. If necessary, you can reactivate the original worksheet like this:
ThisWorkbook.Worksheets("OriginalWorksheet").Activate
I hope that helps!