I am building a sheet to extract data from a list of job openings that I need to sort and filter by location and by BU. I need the code to count the number of openings then pass that information back to the main sub to use in creating additional pages and to loop the sub. I keep getting the above error in this segment. Any thoughts on what I am doing wrong?
Sub Organize_Data()
Dim A As Integer
Dim B As Integer
Dim C As Integer
Worksheets.Add().Name = "Calculations"
Find_Unit
Find_Locations
Count_BU_Data
Count_Country_Data
Count_Raw_Data
End Sub
Function Count_BU_Data(A As Integer)
ActiveWorkbook.Worksheets("Calculations").Range("B3", Worksheets("Calculations").Range("B3").End(xlDown)).Rows.Count
End Function
Your UDF:
Function Count_BU_Data(A As Integer)
Takes an argument (A As Integer) which you haven't specified as being an Optional argument. You call the function from your other routine without supplying this argument:
Sub Organize_Data()
Dim A As Integer
Dim B As Integer
Dim C As Integer
Worksheets.Add().Name = "Calculations"
Find_Unit
Find_Locations
Count_BU_Data '// <~~ No argument passed to function.
Count_Country_Data
Count_Raw_Data
End Sub
Hence the 'Argument not optional' error.
Seeing as that function doesn't appear to actually use the argument, you can either remove it from the function header:
Function Count_BU_Data() As Long '// Note I've included a return value...
Or make it an optional argument
Function Count_BU_Data(Optional A As Integer) As Long
You can also specify a default value if the optional argument isn't supplied
Function Count_BU_Data(Optional A As Integer = 1) As Long
Related
I have an array where in column A different article names are listed. Now I want to add up the values corresponding to some of these article names. Since the number of article names is not constant I am passing the names on as a ParamArray.
All of this works well for elements one to the end of the ParamArray, but an error message "Object variable or with block variable not set" appears when I try to find the row of the article number placed in ParamArray(0). Nevertheless, accessing ParamArray(0) is not a problem, but Vba refuses to find the corresponding row.
Here is the code calling the function (col_ML is the column of the values that are added up):
.Cells(63, col_year).Value = Compute_sum_ML(col_ML, "17.8.32.000", "17.8.42.000")
Here is the function itself:
Function Compute_sum_ML(col_ML As Integer, ParamArray article() As Variant) As Double
Dim row_article As Integer
Dim result As Double
row_article = 0
result = 0
For i = 0 To UBound(article, 1)
row_article = d_ML.Range("A:A").Find(What:=article(i),LookIn:=xlValues).row
If row_article <> 0 Then
result = result + d_ML.Cells(row_article, col_ML).Value
End If
Next i
Compute_sum_ML = result
End Function
Also I tried defining the ParamArray as string since only strings will be passed on to it but it forces me to define it as variant.
The following works for me. I have replaced your sheet code name reference with Worksheets("Sheet1").
Note I have added a test for if a match found.
Option Explicit
Public Sub test()
Debug.Print Compute_sum_ML(2, "17.8.32.000", "17.8.42.000")
End Sub
Public Function Compute_sum_ML(ByVal col_ML As Integer, ParamArray article() As Variant) As Double
Dim row_article As Long, i As Long, result As Double, found As Range
row_article = 0
result = 0
For i = 0 To UBound(article, 1)
Set found = Worksheets("Sheet1").Range("A:A").Find(What:=article(i), LookIn:=xlValues)
If Not found Is Nothing Then
row_article = found.Row
result = result + Worksheets("Sheet1").Cells(row_article, col_ML).Value
'Exit For ''<==If only one match wanted.
End If
Set found = Nothing
Next i
Compute_sum_ML = result
End Function
Data:
I have a dynamic array of strings DMAs which I declare globally.
Dim DMAs() As String
I ReDim the array and assign values to it in the CreateArrayOf function which is of type String() that returns an array of type String()
DMAs = CreateArrayOf(Sites, 2, "", False)
Public Function CreateArrayOf( _
ByRef arrayFrom() As String, _
Optional ByVal numOfChars As Integer = 2, _
Optional ByVal filterChar As String = "", _
Optional ByVal filterCharIsInteger As Boolean = False _
) As String()
Dim i As Integer, _
j As Integer, _
strn As Variant, _
switch As Boolean, _
strArray() As String
'numOfChars 2 for DMA with no filterChar
'numOfChars 3 for W with filterChar "W"
'numOfChars 3 for A with filterChar "A"
'numofChars 2 for D with filterChar "D"
ReDim strArray(LBound(arrayFrom) To LBound(arrayFrom)) 'required in order to
'not throw error on first iteration
For i = LBound(arrayFrom) To UBound(arrayFrom) 'iterate through each site
switch = False
For Each strn In strArray 'iterate through the array to find whether the
'current site already exists
If strn = Mid(arrayFrom(i), 1, numOfChars) And Not strn = "" Then
switch = True
End If
Next strn
If switch = False Then 'if it doesn't exist add it to the array
ReDim Preserve strArray(1 To UBound(strArray) + 1)
strArray(UBound(strArray) - 1) = Mid(arrayFrom(i), 1, numOfChars)
End If
Next i
CreateArrayOf = strArray 'return the new array
End Function
When I attempt to pass the DMAs array to another function OutputAnArray
Private Sub OutputAnArray(ByRef arrayToOutput() As String)
Dim i As Variant
Dim x As Integer
x = 1
For Each i In arrayToOutput
Cells(x, 6).Value = i
x = x + 1
Next i
End Sub
I get the "Type mismatch: array or user-defined type expected". Throughout the whole process I only mess with string arrays.
If I take the content of the OutputAnArray function and put it in the parent function where I'm calling it from, everything's fine.
Any help is appreciated.
I changed all String definitions to Variants
Private Sub OutputAnArray(ByRef arrayToOutput() As Variant)
The culprit was still there, so then after a whole lot of attempts to get this to compile, I removed the () from the arrayToOutput parameter and it started working.
Private Sub OutputAnArray(ByRef arrayToOutput As Variant) 'fixed
What is still perplexing is the fact that in the following function definition, the () are needed for arrayFrom.
Public Function CreateArrayOf(ByRef arrayFrom() As Variant, _ ...
I really don't get it, if anyone has any idea of an explanation, I'd love to hear it.
From the documentation:
"Arrays of any type can't be returned, but a Variant containing an array can."
If follows that the function "CreateArrayOf" does not return an array of strings: it returns a variant containing an array of strings.
The variant cannot be passed as a parameter to a function expecting an array of strings:
Private Sub OutputAnArray(ByRef arrayToOutput() As String)
It can only be passed to a function expecting a variant:
Private Sub OutputAnArray(ByRef arrayToOutput as Variant)
Conversely, DMA is an array of strings:
Dim DMAs() As String
DMA can be passed to a function expecting an array of strings:
Public Function CreateArrayOf(ByRef arrayFrom() As String, _ .
And finally, "Type mismatch: array or user-defined type expected" is a generic type mismatch message. When you pass an array of the wrong type, or a variant array, and get the error "array expected", it's not particularly helpful.
There is no problem with returning typed arrays from functions or passing typed arrays to functions as arguments. The following works as expected:
Option Explicit
Sub asdfasf()
Dim DMAs() As String
DMAs = CreateAnArray()
OutputAnArray DMAs
End Sub
Private Function CreateAnArray() As String()
Dim arr() As String
ReDim arr(1 To 5)
Dim i As Long
For i = LBound(arr) To UBound(arr)
arr(i) = i
Next
CreateAnArray = arr
End Function
Private Sub OutputAnArray(ByRef arrayToOutput() As String)
Dim i As Long
For i = LBound(arrayToOutput) To UBound(arrayToOutput)
Debug.Print arrayToOutput(i)
Next
End Sub
Now, you never show how you actually pass the DMAs array to OutputAnArray.
I'm willing to make an educated guess that you are doing
OutputAnArray (DMAs)
which will indeed result in
Type mismatch: array or user-defined type expected
You cannot freely put parentheses in that manner. They have special meaning.
If you want parentheses to be used when calling a sub, you must use Call:
Call OutputAnArray(DMAs)
And if you don't care, omit the parentheses like in the example above:
OutputAnArray DMAs
I had the same error while passing an array (of user defined type) as an argument to a function ByRef.
In my case the problem was solved using the keyword "Call" in front of the function or the sub being called.
I don't really understand it, but to me it seems like VBA is trying to interpret the function/sub a couple of different ways in the absence of "Call" - which leads to the error message.
I personally try to avoid converting anything to a variant as long as possible.
Working with Visual Basic in Visual Studio 2013. I need to take input from a textbox on form1 and use it as an integer in functions of a module. When I call one of the functions on form1 after a click event, I get an error for invalid arguments on the public function integers. How can I get the text passed to the module and then treated as an integer?
This is what I have on form1. This worked okay on the last project, which required the calculations to be performed and displayed only on form1. This project requires calculations to be performed in a module I created, and then displayed in labels on form2. (I'm still very new to this).
'Define inputs as public variables
Public intNumber1 As Integer
Public intNumber2 As Integer
'Create Function to validate inputs as integers
Public Function ValidateInputFields() As Boolean
'Try to convert each input to integer. If not, return error message, clear input, and return focus
If Not Integer.TryParse(txtNumber1.Text, intNumber1) Then
MessageBox.Show("Please enter only whole numbers.")
txtNumber1.Clear()
txtNumber1.Focus()
Return False
End If
If Not Integer.TryParse(txtNumber2.Text, intNumber2) Then
MessageBox.Show("Please enter only whole numbers.")
txtNumber2.Clear()
txtNumber2.Focus()
Return False
End If
Return True
End Function
This is the error message I get:
Error 1 Argument not specified for parameter 'intNumber1' of 'Public
Function AddInt() As Integer'.
This is the function I've written in the module:
'Create function to pass the values and add
Public Function AddInt(ByVal intNumber1 As Integer, intNumber2 As
Integer) As Integer
'Define intSum
Dim intSum As Integer
'AddInt adds numbers 1 and 2
intSum = intNumber1 + intNumber2
'Return the result
Return intSum
End Function
Text from a TextBox will be of type String and you need to convert it to an integer after checking whether its content can be safely interpreted as a number.
Something like this :
Dim num As Integer
If Not Integer.TryParse(TextBox1.Text, num) Then
'... it's not an integer, so don't try to use it
Else
'... call method using "num" as your integer parameter
End If
This is how I finally got my function calls to work correctly:
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles
btnAdd.Click
'create instance for results form and define sum variable
Dim frmResults As New Results
Dim intSum As Integer
'If inputs are valid, display the integer sum on results form
If ValidateInputFields() Then
'Call Add Integer function from module
intSum = AddInt(intNumber1, intNumber2)
'Send answers to Results form and display
frmResults.lblNumber1Result.Text = intNumber1.ToString()
frmResults.lblOperatorResult.Text = "plus"
frmResults.lblNumber2Result.Text = intNumber2.ToString()
frmResults.lblEqualsResult.Text = intSum.ToString()
frmResults.ShowDialog()
End If
Everything worked once I added the (intNumber1, intNumber2) right after the function call of AddInt.
The ValidateInputFields() function is the TryParse method that #mcrimes was helping me with earlier. This did handle any non-numeric inputs or blanks left as it did in my previous project.
Thanks again #Jonathan and #mcrimes for all of your help.
New to VBA. Was trying to create a constant that references a named column in my worksheet and am getting an error. Is this something you can do in VBA or is my syntax just wrong?
Example:
Public Const ColNum As Integer = [SomeColumn].Column
A constant must be able to be evaluated at the time the code is compiled (ie. before it runs)
This is OK:
Const A as Long = 10 'constant value
and this:
Const B As Long = A 'from another constant
or even
Const B As Long = A * 10 'constant expression
but not this:
Const B As Long = ActiveSheet.Columns.Count 'errors
because ActiveSheet.Columns.Count can only be determined at runtime
The compile error tells you what's wrong: Constant expression required
In other words, as #roryap mentions, you can only use a literal value for a Constant expression, you can't assign it anything that must be evaluated at runtime. A possible workaround is to use constant strings (i.e., your range's Name) and assign elsewhere as needed
From your parent/main procedure, call on another procedure which will assign to the module-level or public variables
Option Explicit
Const MyColumnName as String = "Dave_Column"
Dim ColNum as Integer
Sub main()
Call InitializeVariables
'The rest of your code ...
MsgBox ColNum
End Sub
Sub InitializeVariables()
'Use this procedure to assign public/module scope variables if needed
ColNum = Range(MyColumnName).Column
End Sub
Alternatively, ColNum can be a function with optional parameters, which when left blank would return the range based on the Constant string, or you could specify a different range name/address to return another column number:
Option Explicit
Const MyColumnName as String = "Dave_Column"
Sub main()
MsgBox ColNum
MsgBox ColNum("H1")
End Sub
Function ColNum(Optional name$) As Integer
If name = vbNullString Then
name = MyColumnName
End If
ColNum = Range(name).Column
End Function
Note: this will fail if the named range doesn't exist :)
I would like to be able to only pass q as argument to a function, so that the user does not have to enter a string "q".
I have a function defined in a module
Function doThis(val As Variant)
MsgBox CStr(val)
' Here is a comparison of val with other strings and additional code
End
I call it from my worksheet:
=doThis(q)
And the messagebox returns
Error 2029
I have tried with String and Boolean as value type as well, but only variant fires the function.
Is it possible to receive a q as argument?
Quite simple. First create a Defined Name for q
Secondly in a standard module:
Function doThis(val As Variant)
MsgBox CStr(val)
doThis = ""
End Function
Finally in the worksheet: