Global Variables for Worksheet Names - excel

I need to declare global variables for worksheet names so that if a worksheet name needs to be changed, it can be changed in one spot. This will help to prevent a user from having to dig through each macro to find where each worksheet name was used.
Below is what I have for my global variables. When used this way you get the "Invalid Outside Procedure" for the each of the "Set" instances. I know that the "Set" needs to be inside a procedure but how can I avoid that so that I only have to change the name in one spot for all macros.
Option Explicit
'Global Variables
Dim WS As Worksheet
Dim VB As Worksheet
Dim DB As Worksheet
Dim ED As Worksheet
Dim OC As Worksheet
Dim SH As Worksheet
Dim SL As Worksheet
Set WS = Sheets("WorkSheet")
Set VB = Sheets("VBA Codes")
Set DB = Sheets("Dashboard")
Set ED = Sheets("Extra Details")
Set OC = Sheets("Occupancy")
Set SH = Sheets("Shrinkage")
Set SL = Sheets("SL Impact")
Just in case what I described above does not make sense. The following is an example:
Example: I changed the name of a worksheet from "Dashboard" to "Summary". To avoid changing all instances of "Dashboard" in the macros, I only need to change the global variable to "Summary".

Public workbook as workbooks
Public worksheet as worksheets
Have function init.
Function init()
Set workbook = thisworkbook
set worksheet = workbook.worksheets("sheet1")
End function
Call the init method once in the workbook open sub. The public object should be sustained for other use.
If you want to show the progress in dashboard follow this tutorial: https://youtu.be/zH8eleVVpm8

Related

Sum values from one Worksheet in another Worksheet

I am trying to sum values from my original worksheet in specific cells in my newly created worksheet, which has a template to fill out.
When I used macro recorder, it references the worksheet name, which would not be useful as the worksheet name changes depending on which worksheet I am working in when I run the code.
So I tried changing the worksheet name to a variable "XCXX".
The first argument works so I thought everything was okay, however, on the second argument, it keeps trying to open a file, when it should simply go back to XCXX and pull the values.
Is it a problem with my activesheet changing?
Sub AddWorkbooks()
Dim ChangeOrder As Range
Dim XCXX As Worksheet
Dim CoForm As Worksheet
Set XCXX = ActiveSheet
Set CoForm = Worksheets("+CO Form+")
'Set wbNew = Workbooks.Add
CoForm.Copy After:=Sheets(ActiveSheet.Index)
With CoForm
Range("A6:D6").Select
ActiveCell.FormulaR1C1 = XCXX.Range("D2").Value
Range("AD81").Select
ActiveCell.FormulaR1C1 = "='XCXX'!R[-64]C[-24]+'XCXX'!R[-64]C[-23]"
End With
End Sub
This should be close:
Sub AddWorkbooks()
Dim ChangeOrder As Range
Dim XCXX As Worksheet, wb As Workbook
Dim CoForm As Worksheet, CoFormCopy As Worksheet
Set wb = ActiveWorkbook
Set XCXX = ActiveSheet
Set CoForm = wb.Worksheets("+CO Form+")
CoForm.Copy After:=XCXX
Set CoFormCopy = XCXX.Next 'the copy of "+CO Form+"
With CoFormCopy 'assuming you want to work with the copy?
.Range("A6:D6").Value = XCXX.Range("D2").Value
.Range("AD81").FormulaR1C1 = _
Replace("='<nm>'!R[-64]C[-24]+'<nm>'!R[-64]C[-23]", "<nm>", XCXX.Name)
End With
End Sub
Note when using With you need to use a period to link (eg) Range() with the object used in the With statement, otherwise it defaults to the active sheet.
Also generally there's no need to select a range to do something with it.

Can you call a module from a userform whose variable is declared from a combo box?

I created a userform sub that will allow the user to choose from the open workbook to use as the reference workbook using a combo box. My current script is returning an error that workbooks(wb) is not defined - I assume this is because the variable is defined in two different modules and the combo box is not in the module being called. Ideally would like to use the userform below
Private Sub Go_Click()
If ComboBox1.ListIndex = -1 Then
MsgBox "Please select a workbook name and try again"
Exit Sub
End If
Dim wb As Variant
wb = ComboBox1.List(ComboBox1.ListIndex)
Call GenerateReportUserForm
End Sub
To call this sub:
Sub newMacro()
Dim copyNames As Range, pasteNames As Range, copyAmounts As Range, pasteAmounts As Range, copyDates As Range, pasteDates As Range, _
copyPayment As Range, pastePayment As Range
' For cheques only
Set copyNames = Workbooks(wb).Worksheets(2).Columns("F")
Set copyAmounts = Workbooks(wb).Worksheets(2).Columns("AR")
Set copyDates = Workbooks(wb).Worksheets(2).Columns("AI")
Set copyPayment = Workbooks(wb).Worksheets(2).Columns("AJ")
Set pasteNames = Workbooks("VBA Workbook.xlsm").Worksheets(1).Columns("A")
Set pasteAmounts = Workbooks("VBA Workbook.xlsm").Worksheets(1).Columns("C")
Set pasteDates = Workbooks("VBA Workbook.xlsm").Worksheets(1).Columns("D")
Set pastePayment = Workbooks("VBA Workbook.xlsm").Worksheets(1).Columns("E")
copyNames.Copy Destination:=pasteNames
copyAmounts.Copy Destination:=pasteAmounts
copyDates.Copy Destination:=pasteDates
copyPayment.Copy Destination:=pastePayment
End sub
Thanks!
wb clearly wants to be a String representing the name of a workbook. Declare it as such.
Dim wbName As String
wbName = ComboBox1.List(ComboBox1.ListIndex)
Side note, name your controls. AvailableFilesBox tells so much more than ComboBox1.
Now, what you want is to pass this variable as an argument; do not use a global variable unless you absolutely MUST.
Call GenerateReportUserForm
Not sure what this is supposed to be doing, but it's not calling newMacro. If you want to make it call newMacro, then change it to this:
NewMacro wbName
Or if you really really want to keep that redundant and distracting Call keyword:
Call NewMacro(wbName)
Note: give that macro a meaningful name that describes what the macro does. "new macro" might be clear now, but not so much once there are 4-5 newer macros in that project - and newMacro2 is NOT an option!
Now, in order to pass wbName as an argument, the procedure needs to declare that it takes a parameter - like this:
Public Sub NewMacro(ByVal wbName As String)
Inside that procedure scope, you don't need to constantly dereference the Workbook object. Do it once, store the object reference into a local variable, then use that variable:
Dim wb As Workbook
Set wb = Workbooks(wbName)
Turns out, that macro doesn't really care for the workbook's name; what it really actually wants is a Workbook object. So, let's make it the caller's responsibility to provide a Workbook.
First we change the signature to take a Workbook parameter:
Public Sub NewMacro(ByVal wb As Workbook)
Then we change the form code to supply it:
Dim wb As Workbook
Set wb = Workbooks(ComboBox1.List(ComboBox1.ListIndex))
NewMacro wb ' or: Call NewMacro(wb)
Remember to always put Option Explicit at the top of every module; Rubberduck can help you find & fix this, and other issues in your code.

Why cannot I not access a worksheet by name?

I'm using Excel 2013. I can access a worksheet by iterating through the worksheets and checking the Name property, but I cannot find it individually by using the worksheet name as a key.
Do I really have to iterate through all the worksheets and then all the pivot tables to find the one I need to refresh?
This works:
Dim oWorksheet As Worksheet
Dim oPivot As PivotTable
For Each oWorksheet In ActiveWorkbook.Worksheets
If oWorksheet.Name = "FPSpivot" Then
For Each oPivot In oWorksheet.PivotTables
oPivot.PivotCache.Refresh
Next oPivot
End If
Next oWorksheet
This doesn't work:
Dim oWorksheet As Worksheet
oWorksheet = ActiveWorkbook.Worksheets("FPSpivot")
I get the old chestnut:
Object variable or With block variable not set.
Why?
Ideally, I just want the single line:
ActiveWorkbook.Worksheets("FPSpivot").PivotTables("FPSpivot").PivotCache.Refresh
Surely this must be possible?
The error
Object variable or With block variable not set.
occurs because if you work with objects you need to use Set.
Dim oWorksheet As Worksheet
Set oWorksheet = ActiveWorkbook.Worksheets("FPSpivot")
Additionally:
Are you sure you mean ActiveWorkbook (the workbook which has focus / is on top) or did you mean ThisWorkbook (the workbook the code is written in)? Makes a huge difference and in most cases you need ThisWorkbook.

VBA Global Object Variables

I need some help with global variables. The code I have below needs to be accessed by a multiple Modules and a User form. My attempts to make them a global failed.
Dim wb As Workbook
Dim ws As Worksheet
Set wb = Workbooks.Open("Some.xlsm")
Set ws = wb.Worksheets("Some Sheet")
I have tried making a module to hold them but ran into a runtime error. My program works fine if I copy this code to each function that uses it but that becomes messy. I would like to set it up to just have to change the two lines in order to affect the entire file. When I made a new module it did not like Dim.
Edit:
Public wb As Workbook
Public ws As Worksheet
Public Sub modVariables()
Set wb = Workbooks.Open("V:\My Stuff\Templates\Work Order Batch Creation Template\Sandbox\WorkOrderDatabase.xlsm")
Set ws = wb.Worksheets("Description - Processes")
End Sub
Just declare them as public variables like the following:
Public wb As Workbook
Public ws As Worksheet
Thats how it should look like:

Declaring variable workbook / Worksheet vba

I know this might come off as a trivial question, but I can't seem to declare a workbook or a worksheet as a variable in VBA. I have the following code, but I can't figure out what I am doing wrong, it should be straight forward. Normally I don't have any problems declaring variables such as Dim i As Integer etc.
sub kl()
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ActiveWorkbook
Set ws = Sheet("name")
wb.ws.Select
End Sub
When I run the above code, I receive a type missmatch error.
Use Sheets rather than Sheet and activate them sequentially:
Sub kl()
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ActiveWorkbook
Set ws = Sheets("Sheet1")
wb.Activate
ws.Select
End Sub
If the worksheet you want to retrieve exists at compile-time in ThisWorkbook (i.e. the workbook that contains the VBA code you're looking at), then the simplest and most consistently reliable way to refer to that Worksheet object is to use its code name:
Debug.Print Sheet1.Range("A1").Value
You can set the code name to anything you need (as long as it's a valid VBA identifier), independently of its "tab name" (which the user can modify at any time), by changing the (Name) property in the Properties toolwindow (F4):
The Name property refers to the "tab name" that the user can change on a whim; the (Name) property refers to the code name of the worksheet, and the user can't change it without accessing the Visual Basic Editor.
VBA uses this code name to automatically declare a global-scope Worksheet object variable that your code gets to use anywhere to refer to that sheet, for free.
In other words, if the sheet exists in ThisWorkbook at compile-time, there's never a need to declare a variable for it - the variable is already there!
If the worksheet is created at run-time (inside ThisWorkbook or not), then you need to declare & assign a Worksheet variable for it.
Use the Worksheets property of a Workbook object to retrieve it:
Dim wb As Workbook
Set wb = Application.Workbooks.Open(path)
Dim ws As Worksheet
Set ws = wb.Worksheets(nameOrIndex)
Important notes...
Both the name and index of a worksheet can easily be modified by the user (accidentally or not), unless workbook structure is protected. If workbook isn't protected, you simply cannot assume that the name or index alone will give you the specific worksheet you're after - it's always a good idea to validate the format of the sheet (e.g. verify that cell A1 contains some specific text, or that there's a table with a specific name, that contains some specific column headings).
Using the Sheets collection contains Worksheet objects, but can also contain Chart instances, and a half-dozen more legacy sheet types that are not worksheets. Assigning a Worksheet reference from whatever Sheets(nameOrIndex) returns, risks throwing a type mismatch run-time error for that reason.
Not qualifying the Worksheets collection is an implicit ActiveWorkbook reference - meaning the Worksheets collection is pulling from whatever workbook is active at the moment the instruction is executing. Such implicit references make the code frail and bug-prone, especially if the user can navigate and interact with the Excel UI while code is running.
Unless you mean to activate a specific sheet, you never need to call ws.Activate in order to do 99% of what you want to do with a worksheet. Just use your ws variable instead.
Third solution:
I would set ws to a sheet of workbook wb as the use of Sheet("name") always refers to the active workbook, which might change as your code develops.
sub kl()
Dim wb As Workbook
Dim ws As Worksheet
Set wb = ActiveWorkbook
'be aware as this might produce an error, if Shet "name" does not exist
Set ws = wb.Sheets("name")
' if wb is other than the active workbook
wb.activate
ws.Select
End Sub
Just coming across the same problem.
What you need to do is to declare ws as Object
Also it should be:
Set ws = wb.Sheets("Sheet1")
And should not be:
Set ws = Sheet("Sheet1")
The code below are working to me.
sub kl()
Dim wb As Workbook
Dim ws As Object
Set wb = ThisWorkbook
Set ws = wb.Sheets("Sheet1")
MsgBox ws.Name
End Sub
Try changing the name of the variable as sometimes it clashes with other modules/subs
Dim Workbk As Workbook
Dim Worksh As Worksheet
But also, try
Set ws = wb.Sheets("name")
I can't remember if it works with Sheet
to your surprise, you do need to declare variable for workbook and worksheet in excel 2007 or later version. Just add single line expression.
Sub kl()
Set ws = ThisWorkbook.Sheets("name")
ws.select
End Sub
Remove everything else and enjoy.
But why to select a sheet? selection of sheets is now old fashioned for calculation and manipulation.
Just add formula like this
Sub kl()
Set ws = ThisWorkbook.Sheets("name")
ws.range("cell reference").formula = "your formula"
'OR in case you are using copy paste formula, just use 'insert or formula method instead of ActiveSheet.paste e.g.:
ws.range("your cell").formula
'or
ws.colums("your col: one col e.g. "A:A").insert
'if you need to clear the previous value, just add the following above insert line
ws.columns("your column").delete
End Sub
I had the same issue. I used Worksheet instead of Worksheets and it was resolved. Not sure what the difference is between them.
Dim ws as Object
Set ws = Worksheets("name")
when declaring the worksheet as worksheet instead of an ojbect I had issues working with OptionButtons (Active X) in this worksheet (I guess the same will be with any Active-X element. When declared as object everything works fine.
Lots of answers above! here is my take:
Sub kl()
Dim wb As Workbook
Dim ws As Worksheet
Set ws = Sheets("name")
Set wb = ThisWorkbook
With ws
.Select
End With
End Sub
your first (perhaps accidental) mistake as we have all mentioned is "Sheet"... should be "Sheets"
The with block is useful because if you set wb to anything other than the current workbook, it will ececute properly

Resources