Declaring arrays in VBA, option explicit - vba

I'm new to Excel applications with VBA.
I've been told to declare all the variables throughout my code, by using the "Option Explicit" statement.
In the code below (which is only a small part of the actual program), I'm trying to read the contents of the range C4:L6 and assigns those to the variable "Bar":
Option Base 1
Option Explicit
Sub My_PROGRAM()
Dim Bar() As Long
Bar = Worksheets("Sheet1").Range("C4:L6").Value 'Reads the contents of the range
End Sub
I keep getting a Run-Time error '13' - type mismatch.
My question is, how do I declare a 2D array? I tried Dim Bar(1 to 3, 1 to 10) but that didn't work either.
If I don't use Option explicit, the program works just fine
Option Base 1
Sub My_PROGRAM()
Bar = Worksheets("Sheet1").Range("C4:L6").Value 'Reads the contents of the range
End Sub
Thank you

Related

Excel VBA "Subscript out of range" Run Error '9'

I have tried to implement the following code so that I can read a cell value and then places this value into another cell on the same Worksheet.
The worksheet has the following name: TestUserGuidance (Has no spaces)
The code is as follows:
Sub GuideTest()
Dim dblPower, dblMass, dblRatedSpeed, dblRefLength, dblAwot, dblEngineSpeed, dblRoadSpeed As Double
Dim dblPMR As Double
dblPower = Worksheets("TestUserGuidance").Cell("B1").Value
Worksheets("TestUserGuidance").Cell("E1") = dblPower
End Sub
Could anyone please advise where I'm going wrong?
Thanks
I think vba can't find the TestUserGuidance sheet. If I run the following in the immediate window I get an "Object doesn't support this property or method" error:
?worksheets(1).cell("A1")
If I run this, I get the error you mention "Subscript out of range":
?worksheets("non-existent sheet").cell("A1")
This suggests to me that the active workbook is incorrect since you would have gotten the other error if vba was able to find the worksheet. Can you try adding ThisWorkbook (and also use range)?
dblPower = ThisWorkbook.Worksheets("TestUserGuidance").Range("B1").Value
ThisWorkbook.Worksheets("TestUserGuidance").Range("E1") = dblPower
Another option would be to rename your worksheet:
Then you won't have to worry about the active workbook (and also get intellisence):
shtTestUserGuidance.Range("E1") = shtTestUserGuidance.Range("B1")
Also, I would suggest you make all the corrections suggested by others. You will likely have other issues moving forward otherwise.
Lastly, if the worksheet is like a template and the structure won't change, you'd be better off just using a formula (i.e. E1's formula: =B1). Even if there's conditional logic, it might be easier to maintain as a formula rather than vba code.
Here are some troubleshooting steps:
Toggle a break point on the line where dblPower is set by clicking on the grey area to the left:
Also open the Immediate window if it's not already there by pressing ctrl+g:
When you run the code, it should pause at the break point. Now you can inspect what's in scope. Try typing the following into the Immediate window and press enter:
?Worksheets("TestUserGuidance").Name
or
?ActiveWorkbook.Name
Note that you can also step through the code line by line by pressing F8 while the cursor is somewhere within the subroutine. Bottom line is that you may need to examine the code line by line in order to figure this out.
This is the way to make your code working:
Sub GuideTest()
Dim dblPower, dblEngineSpeed, dblRoadSpeed As Double ' first two are of variant type
Dim dblPMR As Double
dblPower = Worksheets(1).Range("B1").Value
Worksheets(1).Range("E1") = dblPower
End Sub
When you use "E1" or "B1" you should use Range, not Cells. In my answer Worksheets(1) refers to Worksheets("TestUserGuidance").
Only dblRoadSpeed is declared as double.
To fix it, declare all your variables as individual, in vba you can do in 2 ways.
Dim dblPower As Double, dblMass As Double
Or
Dim dblPower As Double
Dim dblMass As Double
Also, you don't need to declare any variable to do what you are doing.
You can copy the value in one step.
Worksheets("TestUserGuidance").Range("E1").Value = Worksheets("TestUserGuidance").Range("B1").Value

Data Type of Named Range

I have a named range in Excel called StartDates for instance. The named range only contains dates. Example code below:
Sub test2()
Dim dat_readdates() As Date
dat_readdates = Range("StartDates").Value
End Sub
This always results in the proverbial Run-time error '13': Type mismatch.
A simple change and it works fine.
Sub test2()
Dim var_readdates() As Variant
var_readdates = Range("StartDates").Value
End Sub
Is there a known rule that data must be read in as variant data type? Clearly for speed I would like to use the data type most appropriate to the data being read.
Do I need to read it as variant and then use cDate to convert to a another variable of date type? Can I do a mass conversion such as:
dat_readdates = cDate(var_readdates)
No, unfortunately. Values are fetched from Excel as Variants. When fetching a single cell, you can directly convert it to the appropriate type, i.e.
Dim x as Long
x = myCell.Value
In the code above, first myCell.Value is fetched as a Variant, then converted by VBA to long (to execute the assignment) if the conversion is possible, otherwise run-time error.
With multiple-cell ranges, it's more tricky. The range.value returns a Variant Array. Unfortunately, VBA does not provide automatic conversion of a Variant array into a typed array. Therefore the following wont work:
Dim x() as Long
x = myRange.Value
VBA does not allow conversion of arrays like with simple variables; even if the programmer is sure that all the variants in the array are of the desired type (i.e. Long in the example above).
To emphasize, forget about excel; the following wont work in VBA:
Dim varArray() ' a variant array
varArray = Array(1, 2, 3, 4, 5)
Dim longArray() as Long
longArray = varArray ' <-- type mismatch. No conversion from variant array to typed array.

Calling a function from macro

I am trying to use the function: Cells(Rows.Count, 14).End(xlUp).Row to determine the last row with data. This and similar formulas appear in many spots in my VBA code. My spreadsheet is quite complex and I often need to add columns. So rather than referring to Column 14, I'd like to use a value I can easily change in only one place. I am using a named Column of sorts that I only need to update in one place. Items sold appears in column N. I realize that this code is very simple, but I simplified it down for the sake of asking a question. When I try to run the Test sub, I a compile errror: ByRef argument type mismatch and the variable Item_Sold. The reason I am using a letter is that Range() needs a letter, but Cells().End(xlUp).Row needs a number.
It works if I move: Items_Sold = "N" to the sub from the function, but this means this code would have to go in every sub rather than in just one function.
Function:
Function ColNum(ColumnNumber As String) As Integer
Dim Items_Sold As String
Items_Sold = "N"
ColNum = Range(Replace("#:#", "#", ColumnNumber)).Column
End Function
Macro:
Sub Test()
Dim Total_Items_Sold As Integer
Total_Items_Sold = Cells(Rows.Count, ColNum(Items_Sold)).End(xlUp).Row
End Sub
Use a Global constant.
At the top of your module, outside of any Sub/Function:
Const COL_NUM As Long = 14
Usage:
Sub Test()
Dim Total_Items_Sold As Long
Total_Items_Sold = ActiveSheet.Cells(Rows.Count, COL_NUM).End(xlUp).Row
End Sub
Add a global variable at the beginning of the code by writing
public Items_Sold as String
that will solve your ByRef problem. But still you will have problem with undeclared value of Items_Sold when invoking Test() unless you set the value of Items_Sold somewhere before.

Populate UserForm Combo Boxes with default values

TierStructureTierStructureI am trying to populate two comb boxes on a userform w/ VBA and set a default value for the same boxes based on a ws function. I think I can figure out the ws function, but I'm having a little trouble with arrays and the default values.
Private Sub UserForm_Initialize()
Dim TierStructure() As Variant
TierSturucture = Array("Composite", "2-Tier", "3-Tier", "4-Tier", "5-Tier", "6-Tier")
StopLossCombo.List = TierSturucture
AdminCombo.List = TierSturucture
StopLossCombo.Value = TierStructure(1)
AdminCombo.Value = TierStructure(1)
End Sub
The error I receive is "run time error 9 - subscript out of range".
You have a typo - "TierSturucture" in two places.
To avoid this in the future, make sure each module has "Option Explicit" at the top. You can automate this via Tools>Options>Editor>Require Variable Declaration. This will make sure any variable has been declared, and thereby catch misspellings.
Also, note that you don't need to declare TierStructure as an array. Variant variables can hold arrays by themselves. So, just use:
Dim TierStructure As Variant

VBA point variable to range

I want to point to a cell as a range in VBA. I've tried using:
Dim range
range = Sheet("sheet").Range("A1")
But this just returns the value in the range. What I actually want is the range object so I can manipulate it, e.g. by setting range.Value = "Hello"
Any ideas?
First, I strongly recommend you to make explicit declaration of variables in your code mandatory. Go to Tools - Options, in the Editor tab check "Require variable Declaration", or put Option Explicit in the first line of all your scripts.
Second, I think there is a small typo in your code, it should be Sheets.("sheet").
To answer your question, with range = Sheets("sheet").Range("A1") you are assigning a value variable, not an object. Therefore the default variable of the range object is implicitly assigned, which is value. In order to assign an object, use the Set keyword. My full example code looks like this:
Option Explicit
Public Sub Test()
Dim RangeObject As range
Set RangeObject = Sheets("Sheet1").range("A1")
RangeObject.Value = "MyTestString"
End Sub
This should put the text "MyTestString" in cell A1.
Edit: If you are using named ranges, try RangeObject.Value2 instead of RangeObject.Value. Named ranges do not have a Value property.