I want to read-in the values of a column in an excel workbook (starting at
cell(3, 1)) using a Sub which will then deliver the array to the main function, but the values obtained within the sub aren’t returning to the array in the main function.
I currently have values in
Cells(3, 1) and
(4, 1) and I know the Sub works because I put in a message box within the Sub and it reads both values.
I’ve tried turning the Sub into a function, changing the name of the Sub parameter to same name as the array in the main function (tr_des), and a lot of stuff like that.
Option Explicit Private Sub cmd_openform_Click() '"Main" function Dim tr_des() As String Call getDescriptions(tr_des) uf_TestSelector.Show vbModal 'shows properly MsgBox tr_des(1) 'shows empty MsgBox End Sub
Sub getDescriptions(ByRef des_array() As String) Dim descrip As String, size As Integer Dim i As Integer i = 0 size = 1 ReDim des_array(size) Do While Cells(i + 3, 1).Value <> "" des_array(i) = Cells(i + 3, 1).Value MsgBox des_array(i) 'opens MsgBox with correct value both times size = size + 1 ReDim des_array(size) i = i + 1 Loop End Sub
MsgBox tr_des(1) to return a value from the column from the excel worksheet but it always returns an empty MsgBox
You need to use
If you do
MsgBox des_array(i) after your
ReDim, you’ll see the values are gone 🙂
Preserve) re-allocates the array to the specified dimensions. Using
ReDim Preserve is how you increase the size of the array without wiping out its content.
If you use the
Preservekeyword, you can resize only the last array dimension and you can’t change the number of dimensions at all. For example, if your array has only one dimension, you can resize that dimension because it is the last and only dimension. However, if your array has two or more dimensions, you can change the size of only the last dimension and still preserve the contents of the array.
ReDim Preserve as one approach to solve your issue. I recommend a different programming approach that avoids the expensive VBA
Preserve action (performance hit can be noticeable on large arrays, but may not be important in your case).
This approach uses a functional paradigm where a new array is calculated. The following is a simple re-write based on your code.
Option Explicit Private Sub cmd_openform_Click() '"Main" function Dim tr_des As Variant tr_des = getDescriptions uf_TestSelector.Show vbModal 'shows properly MsgBox tr_des(1) End Sub Function getDescriptions() as Variant Dim tValidRange as Range Dim i As Integer Set tValidRange = Nothing ' Not really required but nice to be explicit i = 0 Do While Cells(i + 3, 1).Value <> "" If tValidRange is Nothing Then Set tValidRange = Cells(i + 3, 1) Else Set tValidRange = Union(tValidRange,Cells(i + 3, 1)) 'Set tValidRange = tValidRange.Resize(tValidRange.Rows.COunt + 1,1) ' Alternate approach End If i = i + 1 Loop getDescriptions = tValidRange.Value ' Places values into an array. End Sub
Of course, the new way of thinking leads to further refinement of the code.
Function getDescriptions() as Variant Dim tValidRange as Range Dim tRangeToCheck as Range Dim i As Integer Set tValidRange = Nothing ' Not really required but nice to be explicit Set tRangeToCheck = Cells(3,1) 'This really should be fully qualified but ... ' ... you have not provided enough information for an example. Do While tRangeToCheck.Value <> "" If tValidRange is Nothing Then Set tValidRange = tRangeToCheck Else Set tValidRange = tValidRange.Resize(tValidRange.Rows.Count + 1,1) ' expand range down by one row. End If Set tRangeToCheck = tRangeToCheck.Offset(1,0) ' move down one row Loop getDescriptions = tValidRange.Value ' Places values into an array. End Sub