Excel keeps crashing when I set a certain worksheet - vba

The workbook keeps crashing when it gets to the
Set wsEDF = Worksheets("edf master") line. I have tried to delete the sheet and then reinstate it and the same thing happens. Am a bit confused.
Sub CopyGroups()
Application.ScreenUpdating = False
Set wsMarex = Worksheets("marex master")
Set wsMQ = Worksheets("macquarie master")
Set wsEDF = Worksheets("edf master")
There is an end sub plus all the variables were declared at the top. Also at one point the macros worked fine. So have gone back to an old version and will look at changing that based on some advice below.

There's no sheet named edf master in the active workbook. Watch for whitespace (leading and/or trailing).
If the active workbook is ThisWorkbook (i.e. the workbook that contains the code that's running), then you don't need any of this.
Look at the Project Explorer (Ctrl+R). Under "Microsoft Excel Objects" you'll find a class module for every single sheet in your workbook. Click one, then hit F4 to display the Properties box.
In the sheet's properties, you'll see it has a (Name) property, which is probably saying something like Sheet1. Change it to something meaningful, e.g. MarexMasterSheet, or MacquarieMasterSheet, or EDFMasterSheet.
Then you don't need wsMarex, wsMQ and wsEDF anymore - they're already declared for you, as global-scope Worksheet instances. So, say the next line of code was this:
Debug.Print wsMarex.CodeName
Now you can do this instead:
Debug.Print MarexMasterSheet.CodeName

Related

VBA - excel closes the previous workbook on opening the new one

I have a strange problem, I suscpect it's connected to the version of the Excel, but I'm not sure at all. I can't figure it out alone so I need your help. I have a macro, which operates on a fresh workbook - it's not saved anywhere, as the worker will save it manually afterwards. The macro is a .xlam format add-in, adding a couple of buttons to the ribbon and these buttons start the code.
Inside the code I have simple lines for opening a new workbook, chosen earlier by an user:
Application.DisplayAlerts = False
Set wbMPA = Workbooks.Open(MPA_file)
Application.DisplayAlerts = True
Earlier, the code sets active workbook as an object/workbook the macro will mainly work on (tried both versions):
Set dwb = Application.ActiveWorkbook
and later in the code
dwb.activate
OR:
dwb = ActiveWorkbook.Name
and then
workbooks(dwb).Activate
The lines are in separate subs, but the variable is globally declared.
The code works fine until the opening of wbMPA (watching it in the locals all the time). When I try to open the new file with the code above, the earlier workbook (dwb) just closes itself from unknown reasons.
The error I get from the 1st method is this:
error screenshot
The second one gives a simple "Subscipt out of range".
The errors, however, are not a problem. The problem is the cause of them, which is closing of the workbook from unknown reasons.
It happens only when I open the completely new workbook (using the excel icon on the Start bar) - when I do it from File -> New -> Blank Workbook using already opened workbook, the error does not occur.
Another strange thing - me and my colleague from work use 2013 version of Excel. I never have this error, she has it every time.
This is a general scheme of the code, other things are meaningless in this case because there are no other manipulations of workbooks/worksheets.
Dim dwb As Object
Dim wbMPA As Object
Sub_1()
Set dwb = ActiveWorkbook
Set wbMPA = Workbooks.Open(MPA_file)
Call Sub_2
End Sub
Sub_2()
dwb.Activate
End Sub
I get an error on the activation of dwb in Sub_2, because it closes itself for God knows what the reason on the opening of wbMPA in the Sub_1.
If you have only opened a blank workbook (clicking Excel from Toolbar, for example) and then you open any named workbook before making any changes to the blank workbook, the blank workbook will disappear. I believe that is normal/expected behavior.
I can't speculate why this happens on one computer but not another, but this is always how I have observed new/blank documents (Excel, PowerPoint, Word) to behave, and assume this to be the normal behavior. You may have some different option/configuration on your Excel environment which is changing this default behavior, or maybe you are slightly altering the blank file before running the macro, and your co-worker isn't, etc.
A word of caution to avoid relying on ActiveWorkbook -- and especially in this case if the expectation is to always Set dwb to a new/blank workbook, the best way to do that is to explicitly create a new/blank workbook, rather than relying on the user to manually open a new/blank target workbook.
Set dwb = Workbooks.Add
If, on the other hand dwb must be assigned to some other known/existing workbook, then you should be either providing the file path to an Open statement, or the workbook name to the Workbooks collection.
On a related note, it's almost never necessary to Activate a workbook, see here:
How to avoid using Select in Excel VBA macros
And further note: your variables aren't globally scoped, they're scoped only to the module using Dim statement. A public declaration uses the Public keyword, not the Dim keyword. Both module-scoped and global-scoped should be used with caution (Public moreso than module-scoped) and in most cases it's preferable to pass objects/variables by reference to dependent subs and functions:
How to make Excel VBA variables available to multiple macros?

Coping a worksheet without it being activated

I'd like to copy a worksheet at the end of my workbook without it becoming active.
I use this code to copy my "Template" sheet at the end:
ThisWorkbook.Sheets("Template").Copy after:=ThisWorkbook.Sheets(ThisWorkbook.Sheets.Count)
But then my new sheet "Template(2)" become the active sheet.
I'd like to remain on "Template" even after the copy.
Is it possible ?
Is it possible?
It's not. .Copy activates the new sheet, that's just how it is. However nothing stops you from (re-)activating the original sheet after:
With ThisWorkbook.Worksheets("Template")
.Copy after:=ThisWorkbook.Workheets(ThisWorkbook.Worksheets.Count)
.Activate
End With
Notice I'm using the Worksheets collection here. The Sheets collection can contain non-worksheet objects, such as a Chart sheet, which is typically not what you're looking for - the Worksheest collection only contains actual Worksheet object.
Note that finding your template sheet in the ThisWorkbook.Worksheets collection everytime you need to use it is not a necessity, and makes your code more frail than it needs to be.
Each Excel object (VBA object actually) has a (Name) property (on top of the Name property which refers to whatever the worksheet is labelled as) that you can edit in the Properties pane (press F4 in the editor) - that name must be a legal VBA identifier, and what VBA does with it is pretty nifty: it declares a global-scope object variable with that name, so if you name your "Template" sheet TemplateSheet, then you can do this:
With TemplateSheet
.Copy after:=ThisWorkbook.Workheets(ThisWorkbook.Worksheets.Count)
.Activate
End With
And so on for every "static" worksheet (i.e. sheets that aren't generated by code). By referring to worksheets by their Name property (the tab label), your code will start failing as soon as a user decides to name the tab something else. By referring to the corresponding global-scope identifier, you can label the worksheet tab whatever you like, the code won't care at all.

Excel VBA Allow user to select an already open workbook and attach variables to selected workbook

With Excel 2013 VBA, I am familiar with setting the value of a Workbook variable with:
Set oWBSource = Workbooks.Open(strFileToOpen) 'Works well.
In my situation though, sometimes the Workbook is already open on the desktop. I am trying to find a more elegant way to "select" that spreadsheet and then attach my variable to that workbook to operate on. The code is running on a separate "master" spreadsheet.
Currently, I am asking the user if the file is already open. If so, then:
Dim rng As Range
Set rng = Application.InputBox("Select any cell on workbook to operate on.", "Click Workbook Cell", Type:=8) 'Stops code and allows user to select a cell on an open spreadsheet
Dim sTest As String 'variable used to test.
sTest = ActiveCell.Value 'Testing to see what value code is seeing.
sTest = ActiveWorkbook.Name 'Testing to see what value code is seeing
Set oWBSource = Workbooks(ActiveWorkbook.Name) 'Works if selected Workbook is maximized and minimized.
If I run the above code and when it runs the inputbox, if I click one cell on the spreadsheet I want the code to operate on and allow the code to continue, the variables still reference the Workbook where the code resides rather than the "selected" workbook. If, while selecting one cell, I also maximize and minimize the spreadsheet (basically Activate it) and then click a cell and allow the code to continue, the active spreadsheet is set and it seems to work. I realize the cell reference is doing nothing. But the pause allows me to "Activate" the desired spreadsheet.
I am looking for a more elegant way to handle attaching my code to an already open spreadsheet. My current solution is clunky. Isn't there a way to have the user select the open spreadsheet and then have my code "act" on that spreadsheet?
I know this is a weird question. Be kind rating it please??!!
If I understand correctly what you're trying to do, just use the rng to resolve the selected Workbook:
Set oWBSource = rng.Parent.Parent
rng.Parent is the Worksheet a Range is a part of, and the .Parent of a Worksheet is its Workbook.

Accessing Excel sheet without mentioning its name in VBA program

How can I refer Excel sheet using VBA which has only one sheet without mentioning the sheet name in my program? Actually the sheet name might change next time with new data and it is creating a problem in my automation process.
If your macro is running on the same file, you can simply refer to it using the global ActiveWorksheet object.
If you are loading it from somewhere else, you will be probably doing something like this:
Dim objWorkbook as Workbook
Dim objWorksheet as Worksheet
Set objWorkbook = Workbooks.Open("my-file.xlsx")
Set objWorksheet = objWorkbook.Worksheets(1)
To add something to #Mr.E. answer, note that each sheet as 2 names:
- the tab name, visible by the users, appearing within parenthesis in the Project Explorer
- the vba sheet name, appearing first in Project Explorer
So Sheets("MyList").Range(myRange) could be the exact equivalent of
Sheet1.Range(myRange) and, of course to Worksheets(1).Range(myRange) if you have only 1 sheet.

VBA logic when using macros from personal.xls

I run a spreadsheet report that holds about 50 columns of data for anywhere from 1 to 5000 rows. I'm only interested in 4 columns, but they are never in the same location as these reports are set-up a bit differently for each client. I then take those 4 columns and paste into a new workbook that I can import into another program.
I have three macros created that accomplish this task flawlessy if ran from the local file. When I load them into the personal.xls for use on various files I have issues. Specifically workbook/worksheet referencing issues.
Parts of the macro run to the sheet I intend from them to result on, while other parts act on the personal.xls file itself. This confuses me because I don't have any lines that use commands such as 'thisworkbook' or 'activeworksheet'.
For example:
- The first line is coded to rename Sheet1. The macro renames Sheet1 in personal.xls.
- The next line is the first of four Find commands that locate where the columns i'm interested are located and then move them. This macro runs perfectly on the sheet I intend.
I think my best course is to begin each macro by naming the active workbook and then breaking out each command to the workbook level instead of starting with Worksheets, Range, etc.
Can anyone help me understand what VBA is thinking when performing macros from personal.xls and how to best avoid the macros being run on that sheet itself?
There are two approaches you can take. I use one or both in my code - it's not a one or the other situations.
Declare Variables
Start by defining each sheet that you want to work on in a variable. I generally stay at the sheet level, but that's just a personal choice. If you'd rather be at the workbook level, that's OK too. A procedure might looks like:
Dim shSource as Worksheet
Dim shDest as Worksheet
Set shSource = Workbooks("SomeBook").Worksheets(1)
Set shDest = ActiveWorkbook.Worksheets("Summary")
then whenever I reference a Range or Cells or anything else on a sheet, I preface it with that sheet object variable. Even if I need to get to the workbook, I start with the sheet. If I needed to, for instance, close the Source workbook from the above example, I would use
shSource.Parent.Close False
I set up the sheet variables I need and then everything I do is in terms of those variables.
Edit
If you're opening or creating workbooks, then variables is definitely the way to go. For example, if you're opening a workbook, you could use one of these two examples
Dim wb As Workbook
Set wb = Workbooks.Open(C:\...)
Dim ws As Worksheet
Set ws = Workbooks.Open("C:\...).Worksheets(1)
or creating new, one of these two examples:
Dim wb As Workbook
Set wb = Workbooks.Add
Dim ws as Worksheet
Set ws = Workbooks.Add.Worksheets(1)
With Blocks
When I'm only trying to get at something one time, it seems like a waste to set up a bunch of variables. In those cases, I use a With Block so I can still have fully qualified references, but without a bunch of clutter in my code.
With Workbook("MyBook")
With .Worksheets("First_Sheet")
.Range("A1").Value = "stuff"
End With
With .Worksheets("Second_Sheet")
.Range("G10").Formula = "=A1"
End With
End With
I probably prefer the variable method, but I use them both.
Edit 2: Implicit Referencing
You should always explicitly reference your workbooks and worksheets, but it's still instructional to know how Excel will behave if you don't. A line of code that starts like Range("A1").Value = ... is called an unqualified reference. You're referencing a range, but you're not saying which sheet its on or which workbook that sheet is in. Excel handles unqualified references differently depending on where your code is.
In a Sheet's Class Module (like where you use sheet events like SelectionChange), unqualified references refer to the sheet represented by that module. If you're in the Sheet1 module working in the Change event and you code x = Range("G1").Value then the G1 you are referring to is on Sheet1. In this case, you should be using the Me keyword rather than relying on Excel.
In any other module (like a Standard Module), unqualified references refer to the ActiveSheet. The same x = Range("G1").Value code in a Standard Module refers to G1 on whichever sheet has the focus.
Excel's treatment of unqualified references is very reliable. You could easily create robust code by relying on Excel to resolve the qualified references. But you shouldn't. Your code will be more readable and easier to debug if you qualify every reference. I qualify every reference. And that's not one of those things I "always" do except when I'm lazy - I really do it 100% of the time.