Context:
Excel 2003, Windows 7 Professional SP1
Working on workbook A, which contains custom functions.
Workbook B is opened or edited
Back to workbook A, which Workbook_Activate sub is the following:
Private Sub Workbook_Activate
ActiveSheet.Calculate
End Sub
This procedure should force the calculation of custom functions of workbook A, which cells display #VALUE during the edition of workbook B.
Below are the bugs I get on my computer, I hope you can help me with them!
When the workbook (not the whole Excel window) IS NOT in state ActiveWindow.WindowState = xlNormal (i.e. it is full screen or minimized)
OR:
When the workbook IS in state ActiveWindow.WindowState = xlNormal and the workbook has a width > 725 pixels (!)
THEN:
The function Workbook_Activate is fired all the way (good thing).
The function ActiveSheet.Calculate is not fired (or without effect).
Breakpoints don't stop the code.
You can't run any code that edits cells, or run Application.CalculateFull, without getting a display bug such as entire ranges where the text or border vanish until the ranges have been selected.
PROBLEM SOLVING:
In procedure Workbook_Activate, if we add ActiveWindow.WindowState = xlNormal before ActiveSheet.Calculate:
When the workbook IS NOT in state ActiveWindow.WindowState = xlNormal and the Excel window IS maximized
ONLY in this case, the bugs remain. It's the only case where function ActiveSheet.Calculate is not fired. ActiveWindowmethods don't fire either.
Obs.: Application.EnableEvents = False doesn't change anything. (It's probably not even triggered.)
Thank you!
I found a simple solution to avoid the bug.
Private Sub Workbook_Deactivate()
Application.Calculation = xlCalculationManual
End Sub
Private Sub Workbook_Activate()
Application.Calculation = xlCalculationAutomatic
End Sub
[Edit]
... But it was not acceptable, because the calculation was set to "Manual" by default on any other opened workbook.
The best solution is here: Excel 2003 - Display bug with conditional formatting
Related
I have an Excel add-in running a procedure that displays an OKOnly MsgBox if a certain criteria is not met, and attempts to close a userform, activate a specific workbook, and terminate code execution. In the UserForm_Terminate() event I have:
Private Sub UserForm_Terminate()
Debug.Print ActiveWorkbook.Name
Application.ScreenUpdating = True
wbk.Activate
sht.Activate
Debug.Print ActiveWorkbook.Name
End
End Sub
If I begin running the procedure with a new blank workbook active, that workbook is still the active workbook when code terminates, but both print statements above indicate that the target wbk is actually active. However if I use a breakpoint and step through wbk.Activate, the target wbk is activated as expected. The workbook and worksheet objects are both available and there is no error. Any ideas why Workbook.Activate is not behaving as expected during execution? I expected turning screenupdating on would solve my issue but no dice.
#barX He's not relying on ActiceWorkbook for code, he's just checking it to see if it's working ....
BTW Welcome to the Excel 2013 SDI bug!
Maybe following the proper way of initializing/using a Userform will help. See Mathieu's RubberDuck article on Userform.Show
On a related note, maybe changing the Parent Window Handle for the form before closing might work as well. See Keeping Userforms On Top Of SDI Windows In Excel 2013 And Up
I'm not sure if the SDI bug is my issue but it did lead me to an answer (thanks #Profex). I was not able to reproduce that bug, and there is also another path in my procedure that ends with the same Userform_Terminate() event and does reactivate the target wbk, though I can't determine what is causing the differing functionality. Nonetheless, one solution to that issue was to hide and then show the active window and that suffices in this case, though probably not ideal in many situations:
Private Sub UserForm_Terminate()
Dim win As Window
wbk.Activate
sht.Activate
Set win = Application.ActiveWindow
win.visible = False
win.visible = True
End
End Sub
In the excel sheet pictured below I would like the recalculation to stop for the top portion from Row 1-5. And what I mean with recalculation is that for example cell M2, H4, S4 have the today() formula and every time I open it it recalculates. I would like for it to calculate once and once I save as to not recalculate again once opened again. Any suggestions? I have tried
Private Sub Workbook_Open()
Application.Calculation = xlCalculationManual
End Sub
Well, setting Application.Calculation = xlCalculationManual at the time of Workbook_Open may not always assure you the desired result as there is a possibility that the Excel might be in xlCalculationAutomatic while opening your file.
So the workaround is, open Excel and set calculation to manual either in VBE or through menus and then open your file.
In VBE, type Application.Calculation = xlCalculationManual in immediate window then hit Enter and then open your file.
In Excel, for 2007 version, click on Formula Menu, go to Calculation Group, in Calculation Options select Automatic/Manual. For older versions, Tools > Options > Calculation.
I don't have the reputation to post a comment to ask a clarifying question, so I will post an answer instead (making an assumption about what your answer would be).
As long as you never want those cells to recalculate (and don't mind losing the formula), the easiest solution would be to convert them to values.
simple macro to achieve this for first 5 rows:
sub ConvertToValues()
Dim rngToValues as Range
set rngToValues = YourSheet.UsedRange.Rows("1:5").EntireRow
rngToValues.Value = rngToValues.Value
end sub
I would suggest evaluating the function in VBA on events you want.
If you want TODAY function to calculate on your request, I would create a button with a macro that reevaluates TODAY.
How I would implement this depends on if you want/need to have the cell as a formula.
If it is enough to have the calculated value, you can calculate in VBA and set the value to the cells you want.
If you want to have a formula and keep the last evaluated TODAY value, you can set the formula to the cell.
Range("M2").Formula = Date() & "other formula part"
The easiest solution is to set todays value in some cell, in VBA
Sub Macro1 ()
Range("A5").Value = Date()
End Sub
I would suggest to add the below subroutine under Workbook_Open in PERSONAL.XLSB (to be saved at %APPDATA%\Microsoft\Excel\XLSTART) so that it gets loaded whenever Excel application is launched.
Private Sub Workbook_Open()
Application.Calculation = xlCalculationManual
Application.CalculateBeforeSave = False
End Sub
While Application.Calculation = xlCalculationManual will set the calculation mode to Manual (3rd Option in the below screenshot), Application.CalculateBeforeSave = False will untick the checkbox to Recalculate workbook before saving
I have a workbook with the following VBA code to ensure the formula calculation mode is set to automatic:
Private Sub Workbook_Activate()
Application.Calculation = xlCalculationAutomatic
End Sub
If I open that workbook (let's call it WB1) and then any other workbook (WB2, opened under the same EXCEL.EXE instance), then I can't copy cells from WB2 to WB1. By "can't" I mean that when I press ctrl-v I hear Windows' "ding" sound and nothing happens.
If I use the following code instead, everything works fine.
' Now in Workbook_Open instead of Activate
Private Sub Workbook_Open()
Application.Calculation = xlCalculationAutomatic
End Sub
Is that behavior expected? Is this documented anywhere? Or is this a bug? Somehow I feel like I can't be the first person to do this.
I've tried with a C# Excel Add-In and using the equivalent Excel Interop code yields the same result.
Ok so I figured this out as I was typing the question but I'll answer anyway if someone else ever wonders...
The issue is that calling Application.Calculation = xlCalculationAutomatic makes the original workbook lose focus (the moving lines around the cells to be copied disappear, as if I had pressed escape).
Since I put my code in Workbook_Activate, it was called every time I went to copy in WB1 and caused my issue.
Moving the code to Workbook_Open is a good enough solution for me, but I like to think that making Excel non-interactive while I'm changing the calculation mode would have worked. I did not test this solution tough.
I'm new to VBA so there might be a simple answer to this question but if there is I sure haven't found it. What I am doing is copying data from several workbooks into one master workbook. I have writen the code for this and it works fine. The only problem is the workbooks where I'm retriving the data have userforms that automatically initiate when the workbook is accesed. This means that when I run my code to copy the data it hangs at each userform and wont continue until I've physically closed each userform. So my question is: Is there a way to remotely close the userforms in the raw data workbooks from my master workbook VBA code? Thanks in advance.
to close all userforms, (if you want a specific one , change my code)
sub Close_Userforms()
Dim Form as VBA.Userform 'if not work change to Object
For each Form in VBA.Userform
'can add a condition, like : if Form.name ="Whatever" then
unload Form 'if you don't want to lose the data from the userforms, Form.Hide, and later re-loop and Form.Show
next Form
edit : can also if Typename (Form)="Whatever" then , for the condition
Assuming you mean that the forms pop up when you open the workbooks, disable events before doing so:
Application.Enableevents = False
Workbooks.Open ...
Application.Enableevents = True
for example.
I would suggest trying
Application.EnableEvents = False
Further reading.
Short description: All events (Workbook_Open, Workbook_BeforeSave etc), that usually fires upon opening or closing a workbook, will be ignored.
I have written the following functions to make all macros a bit simpler (and faster). Simply place these functions in a regular module.
Public Function CalcOff()
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
Application.EnableEvents = False
End Function
Public Function CalcOn()
Application.Calculation = xlCalculationAutomatic
Application.ScreenUpdating = True
Application.EnableEvents = True
End Function
Begin your macro with:
CalcOff
And then end your macro with:
CalcOn
Remember that you need to put "CalcOn" in all places that exits the running macro.
Disabling ScreenUpdating makes the code "run in background" (nothing will be displayed).
Setting Calculation to manual improves the speed of the code, since no calculations will be made when changing data. But it's very important to exit all macros with "CalcOn", otherwise your sheet won't calculate (and that's not funny), and it will look like Excel has frozen (since ScreenUpdating would still be turned off).
However, if you by any chance happen to break a running code without exiting it the proper way (running "CalcOn"), simply close the Excel application and reopen it. Or run a macro that ends with the "CalcOn" code. Or create a new macro with that simple line.
I'm managing a workbook with more than 200 000 formulas (some really complicated array formulas) which means that I can't let Excel automatically calculate all the cells every time I click somewhere (it takes around 8 hours to calculate everything).
Instead of that, the calculation is set to manual and I have the following VBA code executed when Calculation.xlsm is opened:
With Application
.CalculateBeforeSave = False
.Calculation = xlCalculationManual
End With
I use custom buttons to calculate only some parts of the 200k cells when needed.
I noticed that Excel does keep track of that setting in each workbooks, which means that if I open my Calculation.xlsm, Excel remembers that the calculation is set to manual. If I open my Values.xlsx, Excel does remember that the calculation is set to automatic. This was before I tried to copy values from Calculation.xlsm to Values.xlsx.
Now, because I'm using VBA in Calculation.xlsm to copy values to Values.xlsx, Excel does apply the Application.Calculation setting to that workbook too, which means that if I open it with a new instance of Excel, the calculation will still be set to manually.
If I add a Application.Calculation = xlCalculationAutomatic before closing the Values.xlsx with VBA in my Calculation.xlsm workbook, it will work, but Excel will also start to compute the 200k cells in my Calculation.xlsm workbook, which I obviously don't want.
So my question is about how to actually set the calculation of Excel based on a specific workbook instead of with the Application object. This is based on the fact that Excel does keep track of that setting depending on which workbook is opened (you can just do the test and create 2 different .xlsx files, one with the calculation enabled and the other with the calculation disabled and Excel will remember these settings).
I know I could use the Worksheets.Range.Calculate method to calculate my Values.xlsx workbook before closing it, but the calculation will still be set to manual if I open it in a new instance of Excel after that.
EDIT 3:20pm: Not sure if I was clear enough, English isn't my native language. In short, I have Calculation.xlsm with VBA and Calculation set to manual. I have Values.xlsx with no VBA and Calculation set to automatic. If I open Values.xlsx with the following VBA code in Calculation.xlsm, Excel will automatically convert my Values.xlsx workbook to manual calculations.
Calculation.xlsm code:
Private Sub Workbook_Open()
With Application
.CalculateBeforeSave = False
.Calculation = xlCalculationManual
End With
End Sub
Sub someFunction()
Set WB = Application.Workbooks.Open("Values.xlsx")
Set WBws = WB.Sheets("mySheet")
DoEvents
wb.Save
WB.Close
End Sub
After the execution of someFunction(), Values.xlsx calculation is set to manual. That's the problem. I would like it to stay on automatic (and I can't add VBA to that file, it must be all done from Calculation.xlsm like above).
EDIT 3:40pm: Could I just have my big workbook with Application.Calculation set to manual, put all the data I need in the clipboard (I only need the values, not the formulas), close it (will the VBA still continue to execute even if I close the workbook from which it is executed?), set Application.Calculation to Auto (since there is no open workbook), then open the destination workbook to paste the values (will Excel still keep the data in the clipboard since the other workbook is closed?), then save and close that workbook, set back the calculation to manual (no workbook opened) and reopen the original workbook from which the code was executed?
One way to do this would be to create a new instance of Excel. While this is probably slower, and might be more difficult to work with in cases where you don't close the book/application within the function, but for simple case like your example, it may be easiest to implement:
Sub someFunction()
Dim newExcel as Excel.Application
Set newExcel = CreateObject("Excel.Application")
Set WB = newExcel.Workbooks.Open("Values.xlsx")
Set WBws = WB.Sheets("mySheet")
DoEvents
wb.Save
WB.Close
newExcel.Quit
Set newExcel = Nothing
End Sub
The Application.Calculation property is relative to that instance of the application, not other instances.
Alternatively, you can use an application-level event handler. I suspect this might be faster but I have not tested it for speed.
Modified slightly from this very similar question (which also asks about conditionally disabling an Application-level property).
If:
I was just worrying about if the code would still be executed if I close the workbook from which it is launched
Then just use the normal Workbook_BeforeClose event handler to restore the desired Application.Calculation property (for the entire application/all other open workbooks).
The rest of the answer:
Create an application-level event handler, create a class module named cEventClass and put this code in it:
Public WithEvents appevent As Application
Dim ret
Private Sub appevent_WorkbookActivate(ByVal wb As Workbook)
Call ToggleCalculation(wb, ret)
End Sub
Use the following in a standard module named mod_Caclulate:
Option Explicit
Public XLEvents As New cEventClass
Sub SetEventHandler()
If XLEvents.appevent Is Nothing Then
Set XLEvents.appevent = Application
End If
End Sub
Sub ToggleCalculation(wb As Workbook, Optional ret)
If wb.Name = ThisWorkbook.Name Then
ret = xlCalculationManual
Else
ret = xlCalculationAutomatic
End If
Application.Calculation = ret
End Sub
Put this in the Workbook_Open event handler of the workbook which you always want to be manual calculation:
Option Explicit
Private Sub Workbook_Open()
'Create the event handler when the workbook opens
Call mod_Caclulate.SetEventHandler
Call mod_Caclulate.ToggleCalculation(Me)
End Sub
This will create the event handler only when the specific workbook is opened, and the handler will toggle the Calculation property whenever you switch views to a different workbook.
Note: If you "end" run-time or do anything while debugging which would cause state loss, you will lose the event handler. This can always be restored by calling the Workbook_Open procedure, so an additional safeguard might be to add this also in the ThisWorkbook code module:
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
' Additional safeguard in case state loss has killed the event handler:
' use some workbook-level events to re-instantiate the event handler
Call Workbook_Open
End Sub