I have a sub with an optional workbook argument. I want an If to check whether that variable was passed, and if not set the variable to the active worksheet.
Sub SaveWorkbook(NewPathName As String, Optional Workbook As Workbook)
'This is very simplified, the real thing has various other parameters
If IsNull(Workbook) Then Set Workbook = ActiveWorkbook
'Then loads more stuff
End Sub
Things I have tried include:
IsNull(Workbook)
IsEmpty(Workbook)
Workbook = Nothing
None trigger the If statement so the code attempts to continue with Workbook set to Empty, and then hits errors.
Do not use the word "Workbook" as the variable name. Try it like this:
Sub SaveWorkbook(NewPathName As String, Optional wb As Workbook)
If wb Is Nothing Then
MsgBox "workbook not set"
Set wb = ActiveWorkbook
End If
MsgBox wb.Name
End Sub
In VBA the isMissing function only works, if you declare the parameter as Variant. See in the description
This should work:
Sub SaveWorkbook(NewPathName As String, Optional Workbook As Variant)
'This is very simplified, the real thing has various other parameters
If isMissing(Workbook) Then Set Workbook = ActiveWorkbook
'Then loads more stuff
End Sub
Related
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.
I have two workbooks, "Test1" and "Test2" each with a sheet inside. The code is inside the "Test1" workbook, inside the "ThisWorkbook" module.
I have a Vlookup in the sheet "Mytest1" inside the "Test1" workbook, that simply does a Vlookup with workbook "Test2" inside sheet "Mytest2". Both workbooks are password protected, I am having an issue where if I have the workbook "Test2" opened on another computer, I get a prompt to "Enter Password" for "Test2" when I open my "Test1" workbook. I need to have the Vlookups autoupdate without any prompts for password entries or the second workbook opening up.
I have posted screenshots below of both workbooks and code, alongside the code itself. Please edit or ask me any questions to clarify anything.
Private Sub Workbook_Open()
Workbooks.Open Filename:="\\FILEPATH\Databases\Test 2.xlsm", Password:="Swarf", Updatelinks:=3
ActiveWorkbook.Close SaveChanges:=True
End Sub
I dont have time to test, but will later. I'd try rewriting VLOOKUP as a wrapper round VLOOKUP like so
Function VLOOKUP_BYPASS(LookFor As Variant, Rng As Excel.Range, lngCol As Long) As Variant
Dim strWorkbook As String
strWorkbook = Rng.Parent.Parent.Name
If WORKBOOKOPEN(strWorkbook) Then
VLOOKUP_BYPASS = Application.WorksheetFunction.VLookup(LookFor, Rng, lngCol, False)
Else
VLOOKUP_BYPASS = "NA"
End If
End Function
Function WORKBOOKOPEN(strWorkbookName As String) As Boolean
WORKBOOKOPEN = False
Dim wb As Excel.Workbook
On Error GoTo eHandle
Set wb = Workbooks(strWorkbookName)
WORKBOOKOPEN = True
Exit Function
eHandle:
End Function
This is the solution I came up with, I simply made the file I am using to reference my Vlookup ("Test 2" Workbook) open up as a read-only file!
Private Sub Workbook_Open()
Workbooks.Open Filename:="\\FILEPATH \Databases\Test 2.xlsm", Password:="Swarf", Updatelinks:=3,ReadOnly:=True
ActiveWorkbook.Close SaveChanges:=False
End Sub
I was thinking if its possible to set a Master Workbook in Excel VBA and access it on all procedures and functions?
Since I am pretty new to VBA I don't understand the syntax VBA is using..
Dim MasterWB as Workbook
Set MasterWB = Workbooks.Open("Path to my Workbook")
But if I want to access it in an another Procedure or Function I'll get a Object Definition Error.
I don't want to declare the Object in every Sub or Function.
Thanks a lot!
There are two ways of doing this:
The good practice:
Option Explicit
Sub Test()
Dim MasterWB As Workbook
Set MasterWB = Workbooks.Open("Path")
UseWb MasterWB
End Sub
Sub UseWb(wb As Workbook)
wb.Close
End Sub
The you shouldn't use practice:
Option Explicit
Public MasterWB As Workbook
Sub Test()
Set MasterWB = Workbooks.Open("Path")
UseWb MasterWB
End Sub
Sub UseWb()
wb.Close
End Sub
The first one allows you to pass the Workbook Variable as parameter to other functions in this case you can't use ByVal but other variables like Integeror Long can be used as ByVal instead of (per default) ByRef.
ByVal means you are only passing the value of that variable, so you won't modify it on the function.
ByRef means you pass the reference, so the other function can modify that original variable.
The second way only allows you to use the variable as a reference so there might be changes on it without noticing.
Hope this clears out a bit your question.
I'm new to vba and I'm trying to make an excel macro that loops through a selected folder and the file tabs. It will then call another sub to copypaste certain cells. I got a compile error(procedure declaration does not match description of event or procedure having the same name) when trying to pass through the values.
Part of the first sub
Set wb = Workbooks.Open(Filename:=myPath & myFile)
For Each sht In ActiveWorkbook.Sheets
CommandButton5_Click strSourceSheet, strDestinationSheet
Next sht
Second sub
Sub CommandButton5_Click(strSourceSheet As String, strDestinationSheet As String)
Dim strSourceSheet As String, strDestinationSheet As String, sourceData As String
strSourceSheet = "Sheet1"
strDestinationSheet = "Sheet1"
Sheets(strDestinationSheet).Cells(1, "A") = Sheets(strSourceSheet).Cells(2, "A").Value
End Sub
In Excel, the "tabs" are called sheets. (or worksheets)
Folders (or directories) are file related and are completely different.
as per Comintern, I'd suggest that you rename sub 2 to something like this (give it a meaningful name):
CopySelectedCells(strSourceSheet As String, strDestinationSheet As String)
and then call that from sub 1.
If you have a button called CommandButton5 then you probably need to have a click event for it. Create a third sub:
Sub CommandButton5_Click()
End Sub
Note on parameters:
you'll get further with your code if you set your parameters in sub 1 before you call sub 2
good luck.
I want to update a worksheet. The name of the worksheet changes with the date.
As an example the worksheet would have been named
"Hello World 6.13" on Monday
"Hello World 6.17" today
How can I looks for the sheet name that starts with "Hello World" and ignores the date code?
They way I would go about this would be to loop through the sheets in the active workbook and make the comparison, and when the correct sheet "Hello World x.xx" is found set it as a reference, and use this reference to run any further code.
Let searchTerm = "Hello World"
For Each ws In ActiveWorkbook.Sheets
If Left(ws.Name, Len(searchTerm)) = searchTerm Then
Set hwSheet = ws
Exit For
End If
Next ws
'do some code eg:
With hwSheet
.Range("A1").Value = "Hi"
End With
So the spreadsheet you want to capture is always the same sheet, in the same workbook? If I've got this right, you can use the codename of the worksheet in the client's workbook, such as Sheet1 instead of the worksheet name.
Dim wb As Workbook, ws as Worksheet
Set wb = Workbooks("Client.xls")
wb.Activate
Set ws = Sheet1
You would have to activate the appropriate workbook before using the sheet codename. To be sure this works, it would be prudent to change the client's sheet codename to something unique (if it isn't already) if that is within your purview.
Posted below is a version of Oliver's code that addresses working with the found sheet inside the loop, rather than the last found match.
A couple of other minor tweaks
The string version of Left$ is quicker than the variant Left
if you set an object in a loop, should set it back to nothing before retesting (which is not evident in the code below as I used the existing ws)
code
Sub Updated()
Dim ws As Worksheet
For Each ws In ActiveWorkbook.Sheets
If Left$(ws.Name, 11) = "Hello World" Then
With ws
'do something
End With
End If
Next ws
End Sub
Another option to return all partial sheet matches without a loop is in Adding Sheet Names to Array in Excel VBA
While I liked #Carrosives answer (https://stackoverflow.com/a/37882970/5079799). I decided to functionalize it. In that regard, I didn't want to use LEFT or RIGHT but InSTR.
Here is what I got:
Public Function FindWorksheet(PartOfWSName As String) As Worksheet
For Each ws In ActiveWorkbook.Sheets
If InStr(ws.Name, PartOfWSName) > 0 Then
Debug.Print ws.Name
Set FindWorksheet = ws
Exit For
End If
Next ws
End Function
Sub TestingSpot_Sub()
Dim PartOfWSName As String
PartOfWSName = "Testz"
Dim ws As Worksheet
Set ws = FindWorksheet(PartOfWSName)
ws.Activate
End Sub
This should be enough:
Sub CallTheRealThing()
Call SelectSheets("Sheet")
End Sub
Sub SelectSheets(NameNeededinSheet As String, Optional Looked_Workbook As Workbook)
Dim WorkSheetProject As Worksheet
If Looked_Workbook Is Nothing Then Set Looked_Workbook = ThisWorkbook
For Each WorkSheetProject In Looked_Workbook.Worksheets
If InStr(WorkSheetProject.Name, NameNeededinSheet) Then: WorkSheetProject.Select: Exit Sub
Next WorkSheetProject
End Sub
You may change it to a Function instead of sub to know if it could select the sheet or not