When does the activeworkbook/activesheet change? - excel

I have some questions about the activeworkbook/activesheet properties, would appreciate your help:
In any instances, there would be at maximum only one activeworkbook or no, and that applies to activesheet. Is that right?
If properties like ranges,cells,... are not fully qualified when used, they are by default meant to be that of the activeworkbook.activesheet. Is that right?
Will the activeworkbook change to another workbook by vba actions other than activating the other workbook?
When I use wb.ws.range(cells(x1,y1),cells(x2,y2)), are the cells implied to be the cells of wb.ws? Or do they need to be qualified?
Is it possible to run the vba codes stored in the modules of a workbook without activating the workbook?
Thank you.

In any instances, there would be at maximum only one activeworkbook or no, and that applies to activesheet. Is that right?
Yes. .ActiveWorkbook returns a Workbook object that represents the workbook in the active window (the window on top).
If properties like ranges,cells,... are not fully qualified when used, they are by default meant to be that of the activeworkbook.activesheet. Is that right?
Yes
Debug.Print rng.Parent.Name '<~~ This will give you the name
Will the activeworkbook change to another workbook by vba actions other than activating the other workbook?
Yes it is possible. For example if you send your Active Workbook to Back or minimise it then if the next window in zOrder is a workbook then that will get activated
When I use wb.ws.range(cells(x1,y1),cells(x2,y2)), are the cells implied to be the cells of wb.ws? Or do they need to be qualified?
Only if ws is active then yes else they will refer to Activesheet and hence it is always good to fully qualify your objects
With ws
Set Rng = .Range(.Cells(x1, y1), .Cells(x2, y2))
End With
Is it possible to run the vba codes stored in the modules of a workbook without activating the workbook?
Yes. You can use Application.Run

Related

How to copy a sheet and ensure it is at the end of all other sheets?

sheetCopy.Copy After:=ThisWorkbook.Worksheets(Worksheets.Count)
I use the code above to create a copy of a template worksheet in Excel.
Most of the time it creates the tab at the end which is what I want but sometime it creates new tab somewhere in the middle.
Is there a way to ensure it is copied to the end of the sheets?
(Thisworkbook.Worksheets.Count)
The issue
When working with a Workbook, Worksheet, Range, or other similar objects, it's best to avoid implicit member calls.
Most of these default to whatever is active. For instance, Worksheets.count is the same as ActiveWorkbook.Worksheets.count.
In your code you were almost there as you correctly used ThisWorkbook when accessing the Worksheets Collection; however, the Worksheets.count is defaulting to the ActiveWorkbook.
The Solution
To fix it, I like using With blocks to help shorten the code, and make it easier to be explicit in my refrences.
With ThisWorkbook
sheetCopy.Copy After:=.Worksheets(.Worksheets.Count)
End With

Running excel macro on multiple files

I have an excel spreadsheet with a very complex macro. The spreadsheet takes a file (imported through a button on the sheet), and runs statistics on it. is there any way to automate the macro to run on multiple files in a folder?
Thanks in advance
The macro identifies the worksheets from which it draws data and these sheets are in a workbook, which is also identified. Hence, by changing the name of the source(s) in the code, perhaps even dynamically, you can make the same macro perform its magic on other workbooks.
With that said, since VBA absolutely needs a workbooks to identify a worksheet and must have a worksheet in order to identify a cell, VBA will provide a default for either if the code doesn't mention another. Therefore the innocent Cells(1, 1) or Range("A1:B10") you may see in your code in fact stand for ActiveWorkbook.ActiveSheet.Cells(1, 1) or ActiveWorkbook.ActiveSheet.Range("A1:B10"). Therefore, if you want to change the default workbook for another the process is to first introduce a variable to specify the workbook and worksheet and then change the object assigned to that variable.
In a less generic way, let me presume that you don't have syntax like Range("A1:B10") in your code at all but Worksheets("Sheet1").Range("A1:B10"), identifying the worksheet but not the workbook. Let me further presume that the sheet names are the same in all the workbooks on which you want to run the code. In that case you would make the change as shown below.
Dim Wb As Workbook
Set Wb = ActiveWorkbook 'or perhaps ThisWorkbook (=the one having the code)
' and then change all applicable instances to
Wb.Worksheets("Sheet1").Range("A1:B10")
Now you can change the code to specify another workbook simply with:-
Set Wb = Workbooks("My workbook.xlsm")

ActiveWorkbook.Saved versus ThisWorkbook.Saved versus Me.Saved

I write Excel VBA reports that tap into SQL databases. I'm also in a company that uses dozens of such reports, and any user could have multiple such reports open at once from multiple different sources. Because of this, it is paramount that code does not affect or interfere with any other open workbooks.
My current report unavoidably uses volatile functions, so users that open and then immediately close the file will get prompted with a Save? dialog. Searching online has always pointed to using
Private Sub Workbook_Open()
ActiveWorkbook.Saved = True
End Sub
While effective, I've never been a big fan because of the non-specific nature of "ActiveWorkbook".
Question:
What are the pros/cons/pitfalls of using any of the following options-
ActiveWorkbook.Saved
ThisWorkbook.Saved
Me.Saved
Something_I_haven't_thought_of.Saved
ActiveWorkbook
I would argue that there are no pros to using ActiveWorkbook, as a direct reference to what you're working with should always be preferable, especially in the case stated above where multiple workbooks are involved. Even in the event of opening and working with arbitrary workbooks whose names you don't specifically know (via a FSO or Dir() loop), you can always set a workbook variable equal to the return value of a Workbook.Open function.
ThisWorkbook
Any time you have code working with more than one workbook or even code working with one workbook while multiple workbooks are open, I would recommend ThisWorkbook. It is versatile in that it can be used in object code modules and generic modules to return a consistent reference to the workbook it is placed within. There really aren't any cons to explicitly specifying ThisWorkbook when that's what you mean to reference.
Me
Me and ThisWorkbook are interchangeable when using them inside the ThisWorkbook object code module, but outside of that, Me refers to the object which it is placed within. For instance Me.Name inside a worksheet object code module will get you the name of the worksheet. Doing the same inside the workbook code module will get you the name of the workbook.
For the sake of clarity and re-usability, I would personally recommend ThisWorkbook out of all 3.
Active workbook is the workbook that is in use/activated (hence can change during code execution) and thus less reliable.
This workbook is the workbook on which the code is run. Hence, a good option if that is the workbook you want to refer to.
"Me" refers to where the code is. E.g. if in sheetmodule, it refers to that sheet, if in a userform module it refers to that module, if in thisworkbook module it is the same as 'thisworkbook', etc.
Defining a variable as workbook can refer to any open workbook. Can be redefined as desired in the code and hence very flexible as long as you know the name of the book
Application.DisplayAlerts = False can be used to suppress save/overwrite requests. Which can be very handy if you do not want users to receive a prompt.
Do re-enable as this is a powerful yet 'dangerous' piece of code.

Prevent excel from activating new objects (Sheets, Charts, Workbooks)

Okay, I have an excel macro that processes a lot of data and makes a lot of charts. I inherited the code from a guy that recently retired, while the code functions it is very inefficient so I am rewriting it. One of the things I am trying to fix is he activated/selected everything. I prefer to use references and never select/activate anything.
But I am running into a problem that when I create a new workbook or chart, it will steal focus from the original workbook. This is annoying, because I usually don't add the workbook object in my references for my main workbook.
For example, when I use these lines, the new chart/workbook becomes active
Set wb = Workbooks.Add Or Set wC = wb.Charts.Add
I then use Workbooks(FileName).Activate to reactivate the original workbook
I find it annoying to have to do this every time, and was wondering if there was a way to prevent the new objects from becoming active.
Edit: I just realized that other actions cause the charts to steal focus, like moving the chart with this command wC.Move After:=wb.Worksheets(wb.Worksheets.Count)
If you declare an old worksheet after a new one I believe this accomplishes what you want. For example,
Dim newWst As Worksheet
Dim oldWsk As Worksheet
Set newWst = Worksheets.Add
Set oldWst = Worksheets("Sheet1")
Cells(1, 1) = "Test"
worked for me. It added "Test" to the old worksheet.

What to do to avoid VBA function executed in the wrong work book

I have several excel files that have timer and macros executing. But a big problem is when workbook A's macro is called, while workbook B is active. The macro is executed in the wrong book and failed.
Do I need to put windows().active at the beginning of every function?
If I have different modules how do I pass this workbook name to all of them?
This seems excessive and not right. Is there any good solution to this problem?
Looking forward to your answers
You are on the right track with this
2.If I have different modules how do I pass this workbook name to all of them
I assume that your macro is using the ActiveWorkbook property, or just using Worksheet properties like Range without qualifying them?
Instead of using ActiveWorkbook use ThisWorkbook. Instead of using Range use ThisWoorkbook.Worksheets(1).Range and so forth. Otherwise the macro will assume that the active worksheet is the one you want.
Sub MyMacro
Range("A1").Text = "Test"
End Sub
Try
Sub MyMacro(ByVal oWorksheet as Worksheet)
oWorksheet.Range("A1").Text = "Test"
End Sub
Then pass the worksheet object as a parameter.
You may also find the ThisWorkbook object useful - it is the workbook the macro resides in, or the Application.Caller object, which is the object calling the current macro, for example the Range object if it is a cell formula, or presumably the timer object in your case.
If your macros behave the way you described it, they probably depend explicitly or implicitly on
ActiveWorkbook
or
ActiveSheet
Those kind of dependencies should be avoided, if possible. The macro recorder produces such code, you should change it immediately whenever you have recorded a macro.
For example, if you have some code like
s = Range("A1").Value
Excel implicitly changes that to
s = ActiveSheet.Range("A1").Value
One can avoid that by accessing all cells, ranges, workbook parts etc. by explicitly using the right sheet or workbook object:
Dim sh as Worksheet
Set sh = .... ' Initialize sh the first time where the sheet is created or loaded
'later on:
s = sh.Range("A1").Value
By using a parameters of the form
sh as Worksheet, wb as workbook
for your subs and functions, you can pass the right sheet and workbook between modules, which answers your second question. And if you need access to the workbook where your macro resides, use ThisWorkbook.
I'd go one further... make sure your code doesn't have
Selection
or
ActiveCell
objects within them. You would need to rewrite these using the Range object.

Resources