I want to declare a public array, create it and then use it in another sub.
This is exapmle of what I wrote:
Public array1() As String
Sub Create_Array()
Dim array1(1 To 4) As String
array1(1) = "1"
array1(2) = "2"
array1(3) = "A"
array1(4) = "B"
End Sub
Sub Show_Some_Index()
Dim a As String
a = array1(1)
MsgBox (a)
End Sub
I get Error 9: "Subscript out of range".
Couldn't find an answer, what am I doing wrong?
Variable array1() in Sub Create_Array is scoped to that procedure - basically it's a local variable that's only ever accessible within that procedure, and it happens to have the same name as another public field declared elsewhere, so what's happening is that Show_Some_Index is working off an array that hasn't been initialized yet.
Dim is used for declaring variables. If you mean to re-dimension an array that's in-scope, use the ReDim keyword.
A better approach would be to use a function that returns the array, instead of relying on global variables.
I want to declare a public array, create it and then use it in another sub.
In that case remove the Dim Statement from your code. Further to what Mat explained, here is another way to make your code work
WAY 1
Public array1(1 To 4) As String
Sub Create_Array()
array1(1) = "1"
array1(2) = "2"
array1(3) = "A"
array1(4) = "B"
Show_Some_Index
End Sub
Sub Show_Some_Index()
Dim a As String
a = array1(1)
MsgBox (a)
End Sub
WAY 2
Public array1(1 To 4) As String
Sub Create_Array()
array1(1) = "1"
array1(2) = "2"
array1(3) = "A"
array1(4) = "B"
End Sub
Sub Show_Some_Index()
Create_Array
Dim a As String
a = array1(1)
MsgBox (a)
End Sub
Once you initialize it, you should be able to use it in other procedures.
Related
I have a problem transferring a 2D array between two userforms.
When I click on a CommandButton in userform1, it will open userform2. Then I click on CommandButton in userform2 for creating a 2D array. After this I terminate userform2 and want to transfer my 2D array into userform1.
My best try is calling a function in userform1 click event. I put this function into the userform2 module. But my userform2's function doesn't see 2D array from another subs in userform2. Private Sub userform_terminate() can see this 2D-array which was created in Private Sub CommandButton1_Click() but my function doesn't.
userform1:
Private Sub CommandButton1_Click()
dim results()
results = userform2.get2dArray()
End Sub
userform2:
Private myArray()
Private Sub CommandButton1_Click()
ReDim myArray(1 To 2, 1 To 2)
myArray(1, 1) = "arg1"
myArray(2, 1) = "arg2"
myArray(1, 2) = "arg3"
myArray(2, 2) = "arg4"
End Sub
Private Sub userform_terminate()
'here i can see every args in myArray
...
end sub
Function get2dArray()
'that function I called from userform1
userform2.show vbModal
get2dArray = myArray 'but myArray is empty
End Function
I want to transfer myArray from userform2 back to the main form userform1.
The main problem is userform2.get2dArray doesn't see the private variable myArray in userform2 module.
Making myArray global is also impossible.
Use a public function in a standard module (not in a userform) which takes an optional parameter (your 2D array).
The parameter is then stored in the function as a static variable. The next time the function is called, if the parameter is missing, then return the stored static variable. Here is the example:
Public Function store2DArray(Optional my2DArray As Variant) As Variant
Static storedArray As Variant
If IsMissing(my2DArray) Then
store2DArray = storedArray
Else
storedArray = my2DArray
End If
End Function
The usage would then be like this to store the array:
Sub Userform2Button1_Click()
store2DArray myArray
End Sub
This is how you would retrieve the array:
Sub Userform1Button2_Click()
myArray = store2DArray
End Sub
I am so confused, and endless googling is so far defying me.
I have a sub that collected unique values in Column C into an array. Now that the array is created, I need to use it in a different sub so I can loop through the values.
I have tried passing it as an argument but then I can't figure out how to run the new sub that has arguments, i.e.:
Sub useArray(ByRef varArr() As String)
how in the world do I run useArray? And useArray should be the main sub, anyways, so I am just confused about how I could then run the main sub and use this array variable that has already been defined/populated.
I tried using my sub that gets the unique values as a function, but it doesn't pass the values in the array back to the main sub. At the end of the function AND in the main sub I have:
MsgBox varArr(1)
In the function, it returns the first value. Back in the sub it returns an error.
An assistance would save my sanity!
The preferred method is going to be turning your Sub into a Function:
Function useArray(ByRef varArr() As String) As string()
varArr(2) = "changed it"
useArray = varArr
End Function
Which you would call by:
Sub test()
Dim a(2) As String
a(0) = "a0"
a(1) = "a1"
a(2) = "a2"
MsgBox useArray(a)(2)
End Sub
Sub Main()
Call DoSomethingWithArray(PopulateArray)
End Sub
Function PopulateArray() As Variant
PopulateArray = Array("foo", "bar") ' return some array
End Function
Sub DoSomethingWithArray(ByVal someArray As Variant) ' process array
Dim i As Integer
For i = LBound(someArray) To UBound(someArray)
Debug.Print someArray(i)
Next i
End Sub
i have some array and a combobox in excel vba, when from is active program set hozelistname value to combobox1. arrays is like below:
hozelistname=("zahedan","zabol")
hozezahedan=(1,2,3,4)
hozezaol=(5,6,7)
now when combobox1 change, i want it show the list of selected array. for example when i select zahedan from list i want it alert the value of zahedan array named hozezahedan and also for zabol.
i wrote the below code but not working! any body to help me?
Private Sub ComboBox1_Change()
dim arrayname,str as string
dim i as integer
arrayname = "hoze" & ComboBox1.text
for i= lbound(arrayname) to ubound(arrayname)
msgbox(arryname(i))
next
End Sub
Option Explicit
Private dicArrays As Scripting.Dictionary
Sub SetUP()
Dim arrTestOne(5) As String
Dim arrTestTwo(10) As String
Set dicArrays = New Scripting.Dictionary
dicArrays.Add "TestOne", arrTestOne
dicArrays.Add "TestTwo", arrTestTwo
End Sub
Sub Reference_Example()
Dim a() As String
a = dicArrays("TestTwo")
End Sub
I hope this explains a little better.
Its unclear what you are after but does the below help you through it?
'This block of code goes right at the top of the form
Option Explicit
Dim hozelistname(1) As String
Dim hozezahedan(3) As String
Dim hozezabol(2) As String
Private Sub ComboBox1_Change()
Dim i As Integer
Dim AryLocal() As String
'set the local array based on the combobox
Select Case Me.ComboBox1
Case "zahedan"
AryLocal = hozezahedan
Case "zabol"
AryLocal = hozezabol
Case Else
ReDim AryLocal(0)
End Select
'show the local array
For i = 0 To UBound(AryLocal, 1)
MsgBox (AryLocal(i))
Next
End Sub
Private Sub UserForm_Activate()
Dim LngCounter As Long
'Set up the lists
hozelistname(0) = "zahedan"
hozelistname(1) = "zabol"
'Set up each result
hozezahedan(0) = "1"
hozezahedan(1) = "2"
hozezahedan(2) = "3"
hozezahedan(3) = "4"
hozezabol(0) = "5"
hozezabol(1) = "6"
hozezabol(2) = "7"
'set the combobox
For LngCounter = 0 To UBound(hozelistname, 1)
Me.ComboBox1.AddItem hozelistname(LngCounter)
Next
End Sub
The next steps would be populating the ComboBox and arrays based on list written in Excel and not hardcoded ones.
I have a function that returns a string array
Function getAr() As String
Dim tmpAr(3) As String
getAr(0) = "Hallo"
getAr(1) = "I"
getAr(2) = "Am"
getAr(3) = "I"
getAr = tmpAr
End Function
In a Sub I want to reassign the returned string array like
Sub test()
Dim tmpAr() As String
ReDim tmpAr(UBound(getAr))
Debug.Print tmpAr(0)
Debug.Print tmpAr(1)
End Sub
The error is
assigning to data field is not possible.
I guess that is because I have to dimension the strAr to the same dimension as the myfunc arry. But I just do not get that information.
Could anyone help me here?
Your function and sub both need changing:
Function getAr() As String()
Dim tmpAr(3) As String
tmpAr(0) = "Hallo"
tmpAr(1) = "I"
tmpAr(2) = "Am"
tmpAr(3) = "I"
getAr = tmpAr
End Function
Sub test()
Dim tmpAr() As String
tmpAr = getAr
Debug.Print tmpAr(0)
Debug.Print tmpAr(1)
End Sub
You don't need to know the dimension to assign an array, but your code wasn't correct.
Here is my amended version :
Function getAr() As String()
Dim tmpAr(3) As String
tmpAr(0) = "Hallo"
tmpAr(1) = "I"
tmpAr(2) = "Am"
tmpAr(3) = "I"
getAr = tmpAr
End Function
Notice the String(), this is how you declare the type of a function returning an array.
Also, you were dimensionning tmpAr and tried to affect values to getAr which wasn't set and as you started, it is much easier to work with a temp variable that you'll assign to the function's output at the end of the manipulations.
And your ReDim ReDim tmpAr(UBound(getAr)) was working but did not pass the array, this how you do it tmpAr = getAr and you don't even need to use ReDim before! ;)
Sub test()
Dim tmpAr() As String
tmpAr = getAr
Debug.Print tmpAr(0)
Debug.Print tmpAr(1)
End Sub
I'm having a bit of a problem working with arrays in VBA, where the same would be trivial in (almost) any other language:
Public Function getArray() As MyType()
'do a lot of work which returns an array of an unknown length'
'this is O(N^2) or something equally intensive so I only want to call this once'
End Function
Public Sub doSomething()
Dim myArray() As MyType
Set myArray = getArray() 'FAILS with "Cannot assign to array error"'
End Sub
I think it might be that I need to define the length of the array in advance, or ReDim a dynamic array. But I don't know the length of the returned array ahead of time, and I'd like to avoid calling the function twice:
Public Sub doSomething()
Dim myArray(0 To UBound(getArray()) As MyType 'not entirely sure if this would work, but it involves calling getArray twice which I'd like to avoid
Set myArray = getArray()
End Sub
In C# or Java the equivalent would be:
public MyType[] getArray(){
//do some work and return an array of an unknown length
}
public void doSomething(){
MyType[] myArray;
myArray = getArray(); //one line and I don't need to define the length of array beforehand
}
When assigning arrays of custom objects in vba you need to pass them around as variants I've included a full working sample.
Class Module named MyType:
Public Once As Integer
Public Twice As Integer
Public Thrice As Integer
Code in standard module:
Public Function getArray() As MyType()
Dim i As Integer, arr() As MyType
'do a lot of work which returns an array of an unknown length'
'this is O(N^2) or something equally intensive so I only want to call this once'
For i = 0 To Int(Rnd() * 6) + 1
ReDim Preserve arr(i)
Set arr(i) = New MyType
arr(i).Once = i
arr(i).Twice = i * 2
arr(i).Thrice = i * 3
Next i
getArray = arr
MsgBox "Long process complete"
End Function
Public Sub doSomething()
Static myArray() As MyType
Dim i As Integer
If UBound(myArray) = -1 Then
myArray = getArray()
End If
For i = LBound(myArray) To UBound(myArray)
Debug.Print myArray(i).Once & vbTab & _
myArray(i).Twice & vbTab & _
myArray(i).Thrice
Next i
End Sub
Public Sub Test()
Dim i As Integer
For i = 1 To 3
Debug.Print "Run Number " & i & vbCrLf & String(10, "-")
doSomething
Debug.Print
Next i
End Sub
The first time you run doSomething an array of random length will be generated and you will see a message box that says "Long process complete". Subsequent calls to doSomething will re-use the array created the first time.
If you copy this code and just run the Test sub it will call doSomething three times. You will see the message box once and the output of doSomething in the immediate window three times.
Well, you could pass the array as a reference to the function like this:
Public Sub MyFunc(ByRef arr() As MyType)
...
End Sub
Dim myArr() as MyType
MyFunc myArr
Inside the function you can ReDim your array as wanted.
It is indeed possible to return an array from a function in VBA. According to MSDN:
[Y]ou can also call a procedure that returns an array and assign that to another array. [ . . . ] Note that to return an array from a procedure, you simply assign the array to the name of the procedure.
So you just need to modify your existing code by removing Set from the assignment statement:
Public Function getArray() As MyType()
'do a lot of work which returns an array of an unknown length'
'this is O(N^2) or something equally intensive so I only want to call this once'
End Function
Public Sub doSomething()
Dim myArray() As MyType
myArray = getArray
End Sub
I think you just need to get rid of the set in Set myArray = getArray()
This behaves properly:
Option Explicit
Public Function getArray() As Integer()
Dim test(1 To 5) As Integer
test(1) = 2
test(2) = 4
getArray = test
End Function
Public Sub doSomething()
Dim myArray() As Integer
myArray = getArray()
Debug.Print (myArray(2))
End Sub