Get Codename from property and pass as a variable - excel

I have a function that takes a sheetname as a parameter like
Sub do_things(sheetCodeName as Variant)
sheetCodeName.Cells(1,1) = "Hello"
End Sub
I want to be able to get the codename of a given sheet using something like ActiveSheet.Codename and pass that as the codename parameter to my do_things subroutine. However, I get
Run-Time error '424' Object Required.
This seems to be because ActiveSheet.Codename is a string while actually typing the codename in the subroutine call passes it as a worksheet.
Is there a way for me to gather the codename of a sheet and pass it to my do_things sub without having to manually type it?

The simpler solution is just to pass a Worksheet object:
Sub do_things(ByVal ws As Worksheet)
ws.Cells(1,1).Value = "Hello"
End Sub
You can just pass the ActiveSheet directly if needed. Trying to use the .CodeName is unnecessary.

You could just pass the ActiveSheet, but if you can't do that for some reason you can change your sub:
Sub do_things(sheetCodeName as Variant)
Worksheets(sheetCodeName).Cells(1,1) = "Hello"
End Sub
It doesn't work now because the string is not an object.

Related

Can I take implicitly take a worksheet argument in a with statement?

I have a sub that looks like this:
Public Sub CategoryChange(ChangeWS As Worksheet, NewCategory As String, StartDate As String, EndDate As String)
...
End Sub
And I'm wondering why this works:
Sub Test()
Call CategoryChange(ActiveSheet, Range("A1"), Range("A2"), Range("A3"))
End Sub
and this doesn't work (compile error, argument not optional):
Sub Test2()
With ActiveSheet
Call CategoryChange(, Range("A1"), Range("A2"), Range("A3"))
End With
End Sub
If my sub is expecting a worksheet variable and I'm writing within a With statement, why won't it implicitly take my worksheet?
You can't do that because the syntax doesn't work that way. With only provides a shortcut to reference members of an object, not the object itself. It doesn't "magically" inject the object into a missing reference to the variable. It only looks for expressions that start with a period (.) with no reference in front and injects the object reference.
If your example actually compiles, then Range must be referring to some other reference, not ActiveSheet.Range. Otherwise, you would do this:
With ActiveSheet
Call CategoryChange(ActiveSheet, .Range("A1"), .Range("A2"), .Range("A3"))
End With
With just lets you access the properties and methods of an object without having to specify the object each time:
Worksheets(1).Range("A1").Select
Is the same as:
With Worksheets(1)
.Range("A1").Select
End With
the period is needed; missing arguments are still treated as missing arguments. In your example, this should work:
With ActiveSheet
Call CategoryChange(Worksheets(.Name), Range("A1"), Range("A2"), Range("A3"))
End With
as .Name will return the name of the object referenced by the With block. But it hardly seems worth the effort!

Sub inside a UserForm can't receive Worksheet as parameter

for my internship I have to do some excel UserForms and vba macros.
I have a Private Sub inside my UserForm and i need to pass a WorkSheet as parameter to it. But i always get
"Execution error 438"
when the Sub is called.
What bothers me is that FirstBlankColumn works but FillAllBox doesn't.
I tried:
-putting FillAllBox in Public and neither Private nor Public
-turning FillAllBox into a Function
-changing the way i pass the Worksheet (ie: Set ws = Worksheets("ExportedData") then passingws)
'''vba
Private Function FirstBlankColumn(ws As Worksheet) As Long
'Yadda yadda does some stuff
'
'returns the number of the first blank column
End Function
Private Sub FillAllBox(ws As Worksheet)
' we never get to the FillBox calls
FillBox UserBox, ws
FillBox StockTransBox, ws
FillBox SemaineBox, ws
FillBox LocationBox, ws
FillBox ValeurBox, ws
End Sub
Private Sub UserForm_Initialize()
' displays correctly the number of the first blank column
MsgBox FirstBlankColumn(Worksheets("ExportedData"))
' Throws "error 438" upon call
FillAllBox (Worksheets("ExportedData"))
End Sub
'''
For a long time i passed the Sheet names and String to pass sheet as parameters. But having to call the sheet list in every function/sub to retrieve my sheet isn't optimised.
I'd like to be able to directly pass Sheets or Worksheets as parameter, reliably.
Thanks in advance.
This issue is your use of parentheses(()). Remove those from your call and you should be good to go.
Here is Microsoft's documentation on the use of parentheses.
Sub procedures, built-in statements, and some methods don't return a value, so the arguments aren't enclosed in parentheses
Function procedures, built-in functions, and some methods do return a value, but you can ignore it. If you ignore the return value, don't include parentheses. Call the function just as you would call a Sub procedure. Omit the parentheses, list any arguments, and don't assign the function to a variable.
FillAllBox Worksheets("ExportedData")

VBA EXCEL: Apply sub to another worksheet from module

Trying to get a sub from a module to run within another worksheet. In a sense to stop using redundant ranges and keep it streamlined.
i.e.
-Module object-
Public sub method1()
{
Range("B4:B23") = ""
Range("C4:C23") = ""
'Empties these ranges...
}
-worksheet(s)-
sub project)
{
with sheet1 (or on any sheet 2,3,4,5... etc.)
Call module1.method1
'but this method only works on the module object, not in the context of the 'specified worksheet where it is needed
End with
Ideally to clear the data in ranges by using method1 in ANY worksheet. Every reference I tried just runs the module1 method without any effect or makes a useless reference to the method or worksheet. Just trying to save on code space by not writing direct references to every sheet which is formatted identical.
You can do this with a sub (ClearCells) that accepts a variable number of arguments via the ParamArray keyword. Then you can simply call the ClearCells sub and pass it the worksheet objects you want to clear the same ranges in, as in the DoClear sub. You can add more ranges as needed to the Union function in the GetRanges function.
Sub DoClear()
ClearCells Sheet1, Sheet3
End Sub
Sub ClearCells(ParamArray wkshts() As Variant)
Dim vWs As Variant
Dim ws As Worksheet
For Each vWs In wkshts
Set ws = vWs
GetRanges(ws).Clear
Next vWs
End Sub
Function GetRanges(ws As Worksheet) As Range
With ws
Set GetRanges = Union(.Range("B4:B23"), _
.Range("C4:C23"))
End With
End Function
Or assuming you are calling the method from the sheet you want to clear, you can just use ActiveSheet:
Public Sub Method1()
ActiveSheet.Range("B4:B23").Clear
ActiveSheet.Range("C4:C23").Clear
End Sub

How do I pass a Range object for use in another function?

I have a button someone can click. This button will create a range and pass it to another function that changes the value of that range.
Sub CommandButton21_Click()
Dim example As Range
Set example = Range("A1")
test (example)
End Sub
This function does not work. For some reason the range cannot be used by the other function.
Function test(x As Range)
x.Value = "changed"
End Function
Any help? The error says "Object required". I have tried to pass stuff like [A1] or making it a variant with no luck.
You can't "Call" a function, you Call a sub.....try this:
Sub CommandButton21_Click()
Dim example As Range
Set example = Range("A1")
MsgBox test(example)
End Sub
Function test(r As Range) As String
r.Value = "Changed"
test = "O.K."
End Function
Use Call:
Call test(example)
If you will not return any value, use Sub rather than Function.

How do you store a worksheet reference in a VBA object?

This is going to seem trivial to those of you steeped in Excel object programming but it's beat me.
In the past, I've done the following in Excel's vba to restore the activesheet before exiting a subroutine..
sub foo()
dim cursheet
cursheet = ActiveSheet
someOtherSheet.activate
....
cursheet.activate
end sub
That works fine. I attempted to do something similar using objects and after several different approaches, wrote the following in a new Problem class...
''''''''''''''''''''''
' sheet property
''''''''''''''''''''''
Public Property Get sheet() As Worksheet
Set sheet = psheet
End Property
Public Property Let sheet(Value As Worksheet)
Set psheet = Value
End Property
Public Sub saveCursheet()
Me.sheet = ActiveSheet
End Sub
Public Sub activateSheet()
Me.sheet.Activate
End Sub
In my code, I invoke the methods this way...
Sub TallyQuizScore()
Dim curStudent As Problem
Set curStudent = New Problem
curStudent.saveCursheet
Worksheets("QuizTallies").Activate
...
curStudent.activateSheet
End Sub
When I attempt to execute curStudent.activateSheet, I get an error saying I need an object. So I reran the calling code and stepped through the saveCursheet method. I see the activesheet get stored but notice that the sheet object disappears as soon as I hit the setter's end property line. I don't know if that's an artifact of the debugger or if the sheet really does get tossed when I hit the end property line but whatever it is, the object is gone when I attempt to reactivate it when I'm done.
The frustrating thing is what I really wanted to write in my caller was
curStudent.sheet = Activesheet
and
curStudent.sheet.Activate
by somehow inheriting the builtin worksheet methods but that led to a rabbit's warren of code as I tried to make it work.
So three questions:
Why did the sheet I stored in saveCursheet disappear?
What do I need to change to make the code work?
What do I need to do differently from the above approach to make the curStudent.sheet = Activesheet and it's partner, curStudent.sheet.Activate approach work?
You need a module-level variable to store the value while your code is doing other things. Note that it's private.
Also, as caught by ja72, in the case of objects it's Set, not Let:
UNTESTED:
Private m_Sheet as Worksheet
Public Property Get Sheet() As Worksheet
Set sheet = m_Sheet
End Property
Public Property Set Sheet(Value As Worksheet)
Set m_Sheet = Value
End Property
Public Sub saveCursheet()
Me.Sheet = ActiveSheet
End Sub
Public Sub activateSheet()
Me.m_Sheet.Activate
End Sub

Resources