access an array in a different sub - arrays

I have a sub that creates an array and fills it with data, but I would like to use the same array (with the data recorded from previous sub) in a different sub/function. Is there a way to achieve that.
I'm quite new to VBA, so maybe I'm missing something obvious here.
Thanks in advance.
EDIT:
'//FIRST CODE
Dim MyResults() As String
'
'
'Fill MyResults() with data
'
'
Call ComboToText
'//SECOND CODE
Private Sub ComboToText()
'// If there is more than one item in MyResults() use combo box. For one item use Textbox.
Dim n As Long
If UBound(MyResults) > 1 Then
txtPCB.Visible = False
With cmbPCB
.Visible = True
For n = LBound(MyResults) To UBound(MyResults)
.AddItem MyResults(n)
Next n
.Style = fmStyleDropDownCombo
End With
Else
txtPCB.Text = MyResults(1)
End With
End Sub
Whenever I'm trying to run, VBA insists on declaration of MyResults() in second code too. If I declare it again, wouldn't I lose the data that's already in it?

As YowE3K says, you can pass the array as an argument to another sub:
Dim MyResults() As String
'Fill MyResults() with data
Call ComboToText(MyResults)
'//SECOND CODE
Private Sub ComboToText(MyResults() As String)
...
It's fine to use the same name in both Subs, as I did, but you can also use a different name in the second Sub.

Related

How to trim values in an array in VBA?

I got a problem I just cant fix. I have a string, want to split it at ";" (that is working) and then trim the values.
Dim cell As String
Dim objects() As String
cell = Range("X74").Text
objects= Trim(Split(cell, ";"))
I get my error on the Trim-function. I then tried the following approach:
For Each object In objects
object = Trim(object)
Debug.Print object
Next
This works, but doesnt save the trimmed value to my objects-array.
Despite naming your variables objects and object, they are an array of simple Strings resp. a simple String, and in VBA a string is not an object.
In your For Each-Loop, you are copying a string to the variable object, and no matter what you do with it, it doesn't change the content of the objects-array.
If you really need to change the content of the objects-array, use a loop like that:
Dim i As Long
For i = LBound(objects) To UBound(objects)
objects(i) = Trim(objects(i))
Debug.Print objects(i)
Next
And you should think about changing the name of your variables...
I would try to avoid vba names as variables:
Sub tst()
Dim yourcell As String, i As Long
Dim yourobjects() As String
yourcell = Range("X74").Text
yourobjects = Split(yourcell, ";")
For i = LBound(yourobjects) To UBound(yourobjects)
yourobjects(i) = Trim(yourobjects(i))
Debug.Print yourobjects(i)
Next i
End Sub

How Do You Return True If A String Contains Any Item In An Array Of String With LINQ in VB.NET

I could not find this question on stack overflow but if it is here, please let me know and I will take it down.
Using LINQ in VB.NET, how do you return True if a string contains one of the items in an array of strings?
This is this is the code in multiple lines. How do you do this in one line with LINQ in VB.NET?
Sub Main
Dim endPointTimeoutText As Array = {"endpoint timeout", "endpoint is not available"}
Dim strResult As String = "endpoint is not available sample text."
Dim booleanResult As Boolean = False
For Each item As String In endPointTimeoutText
If strResult.Contains(item) Then
booleanResult = True
Exit For
End If
Next
Console.WriteLine(booleanResult) 'Only included this for the example
End Sub
The expected result would be 'True' or 'False' depending on if the string (strResult) contained one of the values in the Array Of Strings (endPointTimeoutText)
You turn it around, mentally - don't ask "for this string X, which of these things in this array are in that string", you ask "for this array of strings, which of them are in this one string X":
Dim whichStringsArePresent = endPointTimeoutText.Where(Function(ett) strResult.Contains(ett))
Dim firstImeoutStringFound = endPointTimeoutText.FirstOrDefault(Function(ett) strResult.Contains(ett))
Dim wasATimeout = endPointTimeoutText.Any(Function(ett) strResult.Contains(ett))
etc
By the way it would make your code read more nicely if you make it so that Collections of things have plural names. Consider something more like this:
Dim wasATimeout = endPointTimeoutTexts.Any(Function(ett) strResult.Contains(ett))
It's subtle, but significant in terms of readability
Thank you Caius Jard for your help on this. I am going to post the complete program for what I'm going to use as the answer below.
I needed to use a List instead of an Array so that I could use the 'Any()' method. Thanks again Caius, I really appreciate it!
Sub Main
Dim endPointTimeoutText As String = "endpoint timeout,endpoint is not available"
Dim endPointTimeoutList As New List(Of String)
Dim strResult As String = "endpoint is not available sample text."
endPointTimeoutList = endPointTimeoutText.Split(",").ToList()
Dim areAnyStringsPresent As Boolean
areAnyStringsPresent = endPointTimeoutList.Any(Function(itemInEndPointTimeoutList) strResult.Contains(itemInEndPointTimeoutList))
Console.WriteLine(areAnyStringsPresent)
'This code produces the following output:
'True
End Sub

Reference an array declared in a different userform

I'm not an experienced VBA programmer but I've been trying to create an Excel Spreadsheet that is able to manage a basketball team.
In it I've got a primary userform where I have declared an array, 'selectedPlayers'.
This primary userform has a for loop that starts up the secondary userform 'i' times.
I have not been able to access the primary userform's 'i' and 'selectedPlayers' from the secondary one.
I've been able to find a workaround the 'i' by creating a non-visible textbox in the first userform, that I'm able to reference from the second one.
I've tried declaring both of them as public, but yet I'm not able to call upon it from the second userform.
part of the code for the first userform:
i = 0
Do While Not i = Int(txtNumberPlayers)
frmGameDataSecondary.Show
i = i + 1
Loop
second userform:
Private Sub cmdDone_Click()
frmGameData.selectedPlayers(frmGameData.i) = lbxPlayer.Value
Unload Me
End Sub
Private Sub UserForm_Initialize()
With Me.lbxPlayer
For Each LR In LO.ListRows
exitSequence = False
For k = 1 To Int(frmGameData.txtNumberPlayers)
If frmGameData.selectedPlayers(k) = blablabla.Value Then
exitSequence = True
End If
Next k
If !exitSequence Then
.AddItem blablabla.Value
End If
Next LR
End With
End Sub
The main problem is that array contents are cleared after the sub is finished.
I was also messing around with this idea and there is a really good thread I started with tons of great information from various awesome people
Calling an Array Upon User Form Terminate/Close VBA
Forms in VBA are Objects, and can be treated like any other Class module. This means that you can add properties to them. If you need to pass information back from a form, all you need to do is grab a reference to it, then Hide it instead of Unload it. Treat it like a dialog and let the calling code handle it's create and destruction (I'm assuming from your code that it is modal).
Something like this:
In the first UserForm:
For i = 0 To 1
Dim second As frmGameDataSecondary
Set second = New frmGameDataSecondary
second.Show
'Execution suspends until the second form is dismissed.
selectedPlayers(i) = second.Player
Unload second
Next i
In the second UserForm:
Private mPlayer As String
'This is where your returned information goes.
Public Property Get Player() As String
Player = mPlayer
End Property
Private Sub cmdDone_Click()
mPlayer = lbxPlayer.Value
'Control passes back to the caller, but the object still exists.
Me.Hide
End Sub
You can declare properties inside of parent form which will manipulate the array from outside. The child form needs to have a reference to parent so it can call this properties. HTH
Parent form
Option Explicit
' I have not been able to access the primary userform's
' 'i' and 'selectedPlayers' from the secondary one
Private selectedPlayers As Variant
Public Function GetMyArrayValue(index) As Variant
GetMyArrayValue = selectedPlayers(index)
End Function
Public Sub SetMyArrayValue(index, newValue)
selectedPlayers(index) = newValue
End Sub
Private Sub UserForm_Click()
Dim i
i = 0
Do While Not i = Int(txtNumberPlayers)
With New secondaryUserForm
Set .ParentForm = Me
.SetIndex = i
.Show
End With
i = i + 1
Loop
End Sub
Private Sub UserForm_Initialize()
selectedPlayers = Array("A", "B", "C")
End Sub
Child form
Option Explicit
Private m_parent As primaryUserForm
Private m_index As Integer
Public Property Let SetIndex(ByVal vNewValue As Integer)
m_index = vNewValue
End Property
Public Property Set ParentForm(ByVal vNewValue As UserForm)
Set m_parent = vNewValue
End Property
Private Sub cmdDone_Click()
' frmGameData.selectedPlayers(frmGameData.i) = lbxPlayer.Value
m_parent.SetMyArrayValue m_index, "lbxPlayer.Value"
Unload Me
End Sub

How do I change one value in an array but leave the rest alone? - VB

Imagine you have 7 values 50/50/50/50/50/50/50 and you want to change just one when a criteria is me so it becomes 50/50/50/49/50/50/50 But then it saves this new array so if another criteria is met it could become something like 49/50/50/49/50/50/50
I've tried this a hundred times and it just doesn't work. Heres what I have so far
Dim StreamReader As New System.IO.StreamReader("D:\CALLUMS STUFF\Coursework\Stock.Txt")
Dim StreamRead As String
Dim StreamArray() As String
Dim X As String
Do StreamReader.Peek() <> -1
StreamRead = (StreamReader.ReadLine())
StreamArray = StreamRead.Split("/")
X = StreamArray(9)
Loop
Dim C As String
C = X - 1
Select Case CmbSize.SelectedIndex
Case 0
Dim StockWriter As New System.IO.StreamWriter("D:\CALLUMS STUFF\Courseworkd\Stock.Txt")
StockWriter.Write(C(9))
End Select
You really need to use Option Strict On. You've got so much implicit conversion going on I'm surprised that even comes close to working. Look at what I put below and try implementing parts of it and see if it doesn't help out.
btw, I wrote it as a console application. So if you want it to actually work on your machine, you'll have to add a reference to System.windows.Forms in the project settings and you'll have to change the file paths in the constructors for the streamreader/writer.
Contents of C:\StackOverflow\stock.txt
50/50/50/50/50/50/50
Option Strict On
Imports System.IO
Module Module1
Sub Main()
Dim arrfileContents As String()
' Get the data
Using sr As New StreamReader("C:\StackOverflow\stock.txt")
arrfileContents = sr.ReadToEnd.Split(CChar("/"))
End Using
' I'm guessing at what cmbSize is... A ComboBox made sense since you
' have cmb in the name and you are accessing the .SelectedIndex
' property which a ComboBox has. If you wanted, a ListBox would also
' work instead
Dim cmbSize As New System.Windows.Forms.ComboBox
' Add the items to the Combobox. For simplicity I'm just going to
' put the contents of the file in the ComboBox.Items. That way I
' know that the arrFileContents.count and cmbSize.Items.Count are
' the same.
cmbSize.Items.AddRange(arrfileContents)
' Need this to select something other that the first item
' This would be like setting criteria to be matched, if this were
' a winforms application I would be putting this in the method that
' handles the SelectedIndexChanged event
cmbSize.SelectedIndex = CInt((cmbSize.Items.Count - 1) / 2)
'Get and change the Value if valid
Dim tempvalue As Integer
If Integer.TryParse(arrfileContents(cmbSize.SelectedIndex), tempvalue) AndAlso tempvalue <> Integer.MinValue Then
tempvalue -= 1
arrfileContents(cmbSize.SelectedIndex) = tempvalue.ToString
End If
' Write the data back out
Using sw As New StreamWriter("C:\StackOverflow\stock.txt")
sw.Write(String.Join("/", arrfileContents))
End Using
End Sub
End Module

How to clear the entire array?

I have an array like this:
Dim aFirstArray() As Variant
How do I clear the entire array?
What about a collection?
You can either use the Erase or ReDim statements to clear the array. Examples of each are shown in the MSDN documentation. For example:
Dim threeDimArray(9, 9, 9), twoDimArray(9, 9) As Integer
Erase threeDimArray, twoDimArray
ReDim threeDimArray(4, 4, 9)
To remove a collection, you iterate over its items and use the Remove method:
For i = 1 to MyCollection.Count
MyCollection.Remove 1 ' Remove first item
Next i
For deleting a dynamic array in VBA use the instruction Erase.
Example:
Dim ArrayDin() As Integer
ReDim ArrayDin(10) 'Dynamic allocation
Erase ArrayDin 'Erasing the Array
Hope this help!
It is as simple as :
Erase aFirstArray
Find a better use for myself:
I usually test if a variant is empty, and all of the above methods fail with the test. I found that you can actually set a variant to empty:
Dim aTable As Variant
If IsEmpty(aTable) Then
'This is true
End If
ReDim aTable(2)
If IsEmpty(aTable) Then
'This is False
End If
ReDim aTable(2)
aTable = Empty
If IsEmpty(aTable) Then
'This is true
End If
ReDim aTable(2)
Erase aTable
If IsEmpty(aTable) Then
'This is False
End If
this way i get the behaviour i want
[your Array name] = Empty
Then the array will be without content and can be filled again.
ReDim aFirstArray(0)
This will resize the array to zero and erase all data.
i fell into a case where clearing the entire array failed with dim/redim :
having 2 module-wide arrays, Private inside a userform,
One array is dynamic and uses a class module, the other is fixed and has a special type.
Option Explicit
Private Type Perso_Type
Nom As String
PV As Single 'Long 'max 1
Mana As Single 'Long
Classe1 As String
XP1 As Single
Classe2 As String
XP2 As Single
Classe3 As String
XP3 As Single
Classe4 As String
XP4 As Single
Buff(1 To 10) As IPicture 'Disp
BuffType(1 To 10) As String
Dances(1 To 10) As IPicture 'Disp
DancesType(1 To 10) As String
End Type
Private Data_Perso(1 To 9, 1 To 8) As Perso_Type
Dim ImgArray() As New ClsImage 'ClsImage is a Class module
And i have a sub declared as public to clear those arrays (and associated run-time created controls) from inside and outside the userform like this :
Public Sub EraseControlsCreatedAtRunTime()
Dim i As Long
On Error Resume Next
With Me.Controls 'removing all on run-time created controls of the Userform :
For i = .Count - 1 To 0 Step -1
.Remove i
Next i
End With
Err.Clear: On Error GoTo 0
Erase ImgArray, Data_Perso
'ReDim ImgArray() As ClsImage ' i tried this, no error but wouldn't work correctly
'ReDim Data_Perso(1 To 9, 1 To 8) As Perso_Type 'without the erase not working, with erase this line is not needed.
End Sub
note : this last sub was first called from outside (other form and class module) with Call FormName.SubName but had to replace it with Application.Run FormName.SubName , less errors, don't ask why...
Only use Redim statement
Dim aFirstArray() As Variant
Redim aFirstArray(nRows,nColumns)

Resources