Closing a userform that is in workbook A from workbook B - vba

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.

Related

Application.ScreenUpdating = False not working switching between Excel sheets or workbooks

The function Application.ScreenUpdating = False is not working whenever switching between worksheets or workbooks in Excel. This function alone worked fine in Excel 2010, but doesn't work in later versions from what I can tell. I am now using the office 365 desktop version of excel. In these later versions, the command only prevents updating when selecting cells or doing things within a specific worksheet, but for my purposes I need a form to pull data from a second worksheet which causes flickering.
Is there a way to prevent the screen from updating/flickering with SheetB briefly when it gets activated in this macro?
Sub ActivateSheetB()
Application.EnableEvents = False
Application.ScreenUpdating = False
Application.Calculation = xlCalculationManual
Sheets("SheetB").Activate
End Sub
I've had the same thing happen to me forever and it's fairly annoying but from my own observation, I believe that application.screenupdating = false is still working. What I mean by that is your code is still being sped up. Other than it visually being annoying and making users think they broke excel this is still an effective method for speeding up your workbook even when switching between sheets.
Hopefully someone comes along with a better answer than mine because I'd love to know what that answer is as well xD

Setting calculation mode to automatic in Excel workbook activate event disables inter-workbook copy-paste

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.

Application.Calculation depending on workbook

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

How do I disable and enable macros on the fly?

I would like to test an Excel VBA app I made.
However the VBA code messes around with the visibility of cells and that's a pest when editing the sheet.
Is there an option is enable and disable macro's on the fly without having to
Close the sheet
Change the macro settings
Reopen the sheet
Close the sheet
Change the macro settings.
etc.
As far as I know, you can't enable / disable macros from an opened workbook on the fly.
Yet, you shouldn't have to because macros are only triggered thanks to a user click.
The only case I would see is for the Event Procedures (Worksheet_Change or else).
You could then create procedures to activate / deactivate events and call them from buttons in your worksbook:
Sub enableEvents()
Application.EnableEvents = True
End Sub
Sub disableEvents()
Application.EnableEvents = False
End Sub
You can also try these tips from Chris Pearson website using global vars you would change depending on your needs:
Public AbortChangeEvent As Boolean
And check if afterwards:
Private Sub Worksheet_Change(ByVal Target As Range)
If AbortChangeEvent = True Then
Exit Sub
End If
'
' rest of code here
'
End Sub
To disable macros on the fly, use "Application.EnableEvents = False" via the Immediate window in the VBA editor (and "Application.EnableEvents = True" to turn them back on).
You can also hold down SHIFT when you open a document to disable macros.
As of Excel 2010* there's actually an option on the "Developer" tab which allows you to disable macros as easy as ABC. Design Mode lets you do just that!
*Maybe even earlier versions.
I often fire Macros when opening a workbook but sometimes I don't want the Macro to fire so I can work on the code. So what I put a Macro in a separate workbook that does the following:
Disables macros
Opens the workbook in question
Enables macros
Then closes the original workbook
Leaves the second workbook open
Here's the code:
Sub OpenClose()
'Opens Workbook below with Macors disabled
'After it is open Macros are enabled
'This Workbook then closes without saving changes, leaving only the workbook below open
'************************************************************
'User only needs to change the workbook name on the next line
WorkbookToOpenNoMacros = "Gaby.xlsm"
'************************************************************
Dim wb As Workbook
Set wb = Application.ThisWorkbook
Application.EnableEvents = False
Application.Workbooks.Open (ActiveWorkbook.Path & "\" & WorkbookToOpenNoMacros)
Application.EnableEvents = True
wb.Saved = True
wb.Close SaveChanges:=False
End Sub
I have Office 2013 and I found a button on the VBA window that did this for me very easily.
There's a play, pause and stop button on the toolbar. In Excel, they are actually called, Run Macro, Break and Reset.
Click the Break button (pause) and any running macros should stop running. I only tested it on one macro but seems reasonable to presume that this will work in general.
Also, I believe those buttons were there for many versions of Excel, so it's worth checking earlier versions.

Copy method fail due to memory

In my workbook, I copy the current sheet to keep as a record of a sale. Eventually, the workbook fills up with sales and at some point throws an error when I try to copy another sheet. After saving, then completely exiting Excel, then reloading the file, I can continue without problems. I'm guessing it's a memory issue, but I'm not quite sure how to solve it without restarting Excel. I can't remember the wording of the error exactly, but it went along the lines of "Copy method of worksheet failed". FWIW I use "Application.CutCopyMode = False" at the end of the macro that copies the sheet.
1st edit:
I'd like to post all of the code, but there's just so much of it (mostly not related to updating values, input verification, etc. etc.); if I post everything, I'd have to post all of the other functions for it to make sense. Suffice it to say, here's what I think is applicable:
ActiveSheet.Copy After:=Sheets(3)
...(more code)...
Call resetInterface(True, True, (wasScreenUpdating), (wasProtected))
and for the "resetInterface" function:
' Final operations for a typical function/sub '
Function resetInterface(Optional calc As Boolean = False, Optional ccmode As Boolean = False, Optional scrUpdate As Boolean = True, Optional protectWS As Boolean = False)
With Application
If calc Then
.Calculation = xlCalculationAutomatic
.Calculate
End If
If ccmode Then .CutCopyMode = False
.ScreenUpdating = scrUpdate
End With
If protectWS Then ActiveSheet.Protect
End Function
There used to be a problem when copying sheets in Excel that the CodeName property of the Worksheet object would be appended with a 1 and get to be too long. I think it's been fixed, but it would depend on what version you're using.
Open the VBA (Alt+F11) and show the Project Explorer (Ctl+R). Look at the CodeNames of your copied sheets. Are they Sheet1, Sheet2, etc..? Or are they Sheet1, Sheet11, Sheet111, etc...? If the latter, this may be causing the problem. See http://support.microsoft.com/kb/177634
Or it could be that you have a workbook level name, see http://support.microsoft.com/?kbid=210684
The error you're referring to is:
Excel VB run-time error 1004: "Copy method of Worksheet class Failed"
Can you post the macro you've written?