Excel VBA Object Variable Not Set issue, possible improper Redim usage? - arrays

I am running into an error with the below code. When I debug, I find the line causing my problem:
Options(a) = New Element
The error displayed is Object Variable or With Block Variable Not Set. With msg boxes I have found the value of a to be 0 at the time of the crash and the TotalItems to be 7. The Element object initialization is empty. I call the PopulateChildren method from another method within the same class. Am I using ReDim improperly? It seems like maybe it isn't increasing the size of my array... I have noticed examples of using it like this...
ReDim Preserve Options(0 to TotalItems)
...but it doesn't seem to do any different when I try it. Anyone have any idea what is going on?
Dim Options() As Element
Dim TotalItems As Integer
Dim Children(100) As Integer
Private Sub PopulateChildren()
ReDim Preserve Options(TotalItems)
For a = 0 To TotalItems - 1
Options(a) = New Element
Options(a).Populate (Children(a))
Next a
End Sub
Thanks

Since Element is Object, you should use Set:
Set Options(a) = New Element

easy, put your dim options inside the SUB, or ...
public dim options()
sub ...
'your code
end sub
of course options doesn't exit for your sub like you wrote it ! so the error showing...

Related

VBA Array Public Method cant be modified by components

I'm working with a rather complex problem in VBA and I decided to structure it in different classes.
One of the classes containd an array and I need to modify the component individualy outside the class.
The problem can de reduced to the definition of the class
Public a As Variant
Private Sub Class_Initialize()
ReDim a(5) As Double
' Set some value
a(1) = 20
End Sub
And a sub to access the data:
Sub Test()
Dim b As New DummyTest
b.a(4) = 7
Debug.Print (b.a(1))
Debug.Print (b.a(4))
End Sub
The result on the debug window is 20 0. I've checked this result with an inspection and confirm that the property a cannot be modified from the exterior of the class.
Funny part is that the property can be modified if replaced by other array, for example:
Sub Test2()
Dim b As New DummyTest
b.a = Array(1, 2, 3, 4, 5)
Debug.Print (b.a(1))
Debug.Print (b.a(4))
End Sub
Behaves as expected. I'm confused as element access is allowed inside the class context and in any other situation, but in this specific case it doesn't wotk. There is no error msg, it simply refuses to change the content of the array.
I'll find work around solutions but missing this way to access data is being a really PITA.
Hope you can help me with this issue.
Thank you in advance!
Your "property" is breaking encapsulation, which pretty much defeats its entire purpose.
Public a As Variant
From a public interface standpoint, this is a read-write property (if you added a new class module with Implements DummyTest you'd have to add Property Get and Property Let members for it). From the class' standpoint, it's a public instance field.
When a class encapsulates an array, a collection, a dictionary, or any other data structure, the last thing you want is for that data structure to be publicly exposed, with anyone anywhere being able to just overwrite the class' entire internal state as it pleases - you're not getting any of the advantages of classes that way.
First step to proper encapsulation is to make the instance field Private. Next step is to expose actual Property accessors. You want the array data to be writable? Expose an indexed Property Let member for it.
Private a As Variant
Private Sub Class_Initialize()
ReDim a(0 To 10)
End Sub
Public Property Get Value(ByVal index As Long) As Variant
Value = a(index)
End Property
Public Property Let Value(ByVal index As Long, ByVal newvalue As Variant)
a(index) = newvalue
End Property
This code behaves exactly as advertised:
Public Sub Test()
Dim b As DummyTest
Set b = New DummyTest
b.Value(4) = 7
Debug.Print b.Value(1)
Debug.Print b.Value(4)
End Sub
Note that because the array is encapsulated, that client code is absolutely unable to re-assign the array itself: the array is abstracted away and only accessible through the means exposed by the class.
Reference variable in VBA must be declared, so that we know what type of object we are referring to
i.e. Dim b As DummyTest ' No new required in this step
Before using a declared reference to store information create an instance of the Class.
i.e. Set b = New DummyTest
This might seem confusing but is actually very logical. Because b is a Class the Dim statement sets up b to hold the address of a DummyTest object. At the time of the Dim statement no object has been created (no memory allocated) so the address of b is nothing (no value or null). The set statement tells VBA to create an instance of your DummyTest class (allocate the memory it needs) and puts the address of the instance (memory) into variable b. Then because VBA knows that b points to an instance of a class you never see the address of b when you use it, just the data to which b is pointing. You can get the the address b is holding using the function Objptr but this is only something you would do in very special/specific circumstances

public array loaded from useform vba

Iam creating a macro, and I need to access the array that is created and filled in useform (button_click action) in module.
Private Sub CommandButton1_Click()
Dim tmojo As Worksheet
Dim mojocell As Range
Set tmojo = Sheets("table mojo")
colls = tmojo.Range("N1").End(xlToLeft).Column
i = 1
For Each cCont In Me.Controls
If TypeName(cCont) = "ComboBox" Then
If cCont.Enabled = True Then
If cCont.Value = Empty Then
MsgBox "you havent specified all the columns"
Exit Sub
End If
ReDim Preserve collname(i)
collname(i) = cCont.Value
i = i + 1
End If
End If
Next cCont
Call createregion
End Sub
I fill the array collname with values from multiple comboboxes (column names). Then I want to call createregion sub which is located in module and I want to access the values in collname().
im getting error saying that:
Constants, fixed-length strings, arrays, user-defined types, and Declare statements not allowed as Public members of an object module
I need to access this array in multiple subs, is there any workaround?
Thank you in forehand.
The proper way is to transfer your UserForm code into a regular module, and declare your array as public, on the top of the module, before every subs :
Public MyArr()
When you transfer your code, you will need to call the subs into your UserForm's events, and so change all the Me and Me. to the full name of your UserForm.
And if you are lacking time, you can simply declare on the top of the UserForm module :
Dim MyArr()

VBA - Adding a listbox to an array

I've been searching around online, and just want to know how to add a bunch of ListBoxes from my Userform to my array. Here's what I have so far:
Dim LBArray() As Variant
Private Sub UserForm_Initialize()
ReDim LBArray(7) As Variant
FirstNameTextBox.Clear
LastNameTextBox.Clear
HotelCIDate.Clear
HotelCODate.Clear
HotelNameBox.Clear
HotelConfStatus.Clear
HotelConfNumber.Clear
LBArray(0) = FirstNameTextBox
LBArray(1) = LastNameTextBox
LBArray(2) = HotelNameBox
LBArray(3) = HotelCIDate
LBArray(4) = HotelCODate
LBArray(5) = HotelConfStatus
LBArray(6) = HotelConfNumber
End Sub
This should work, but it doesn't actually add the listboxes to the array. All the elements are either "" or Null, and I can't modify the ListBox objects from the array. Anyone know why this is happening?
A listbox is an Object, so you need to use the Set keyword when assigning an object, otherwise it will return the object's default property (which in this case I think is the .Value property)
Set LBArray(2) = HotelNameBox
Etc.
I don't think it's really necessary to do this, and actually it seems unnecessary and confusing! Later in your code, you're going to need to refer to ListBox(i) or to the objects by name.
If you need to iterate over the listboxes and perform some operations on them, you can always do:
Dim ctrl as MSForms.Control
For each ctrl in UserForm1.Controls
If TypeName(ctrl) = "ListBox" Then
** Code to do something with each listbox
End If
Next

How to convert a text file to an array in Visual Basic 2008 line by line?

I am newer to Visual Basic and I am trying to get into file reading. From what I've found online I haven't found anything that wasn't entirely confusing to me.
I am trying to make a simple game to test some dialogue things and I want the options of what you can say to be predetermined. Right now I have a few sentences in arrays, but what I really want to do is just type everything into a text file with a different item on each line and then convert each line to a separate item of an array.
What I have right now is:
Dim convoStarters() As String = {"Hello", "Who are you?", "Who the hell are you?"}
What I want to do is take information from a text file organized like so:
Hello
Who are you?
Who the hell are you?
and put each line into an array that looks exactly like the one I have above (except of course, I'd add more things to the text file).
Thank you for helping a new guy out, have a nice day.
First of all you have to find out, how many elements are necessary for your array.
By counting the numbers of '","' + 1 you have the numbers of elements existing in your string.
Please have a look in string methods like instr(), mid(), left(), rtrim(), ltrim() ..
With the number of elements you found you can REDIM array, or REDIM PRESERVER array
for your example REDIM strArr(nrElements) or if you need to add some elements without
loosing content use REDIM PRESERVE strArr(nrElements).
Then you can fill it up:
for x = LBound(strArr,1) to Ubound(strArr,1)
strArr(x) = Stringpart(x)
next x
Always open your "direct window" in VBA Editor under menu "view" and use debupg.print strArr(x)
Assuming you meant VB.NET and not VBA (both for the tag to Visual Studio and for the purpose of development a game), you can use a StreamReader to read the file line by line and adding the elements to the string then:
VB.NET SOLUTION
Note: if you didn't do yet, to interact with any file (input or output) you need to import the IO of the system, which means state this on top of your code:
Imports System.IO
...then...
GLOBAL VARIABLES (on top of the module, out of any sub/function)
Dim myStringElements As Integer
Dim convoStarters() As String
SUB CODE
Public Sub yourSub()
myStringElements = 0
Dim sr As StreamReader = New StreamReader(path) 'this object will read the text file
Do While sr.Peek() >= 0 'this will loop through the lines until the end
AddElementToStringArray(sr.ReadLine()) 'this will add the single line to the string array
Loop
sr.Close()
End Sub
PUBLIC FUNCTION BODY (another sub that makes the adding job)
Public Sub AddElementToStringArray(ByVal stringToAdd As String)
ReDim Preserve convoStarters(myStringElements)
convoStarters(myStringElements) = stringToAdd
myStringElements += 1
End Sub
VBA SOLUTION
But if as of your comment you rather meant VBA, then the logic is the same but the syntax is slightly different:
GLOBAL VARIABLES
Dim myStringElements As Integer
Dim convoStarters() As String
SUB CODE
myStringElements = 0
Open "C:\Users\Matteo\Desktop\Test.txt" For Input As #1
While Not EOF(1)
Line Input #1, DataLine ' read in data 1 line at a time
AddElementToStringArray (DataLine) 'this will add the single line to the string array
Wend
PUBLIC FUNCTION BODY
Public Sub AddElementToStringArray(ByVal stringToAdd As String)
ReDim Preserve convoStarters(myStringElements)
convoStarters(myStringElements) = stringToAdd
myStringElements += 1
End Sub

Is it possible to dimension a new variable based on array value?

I have a lot of fields for which I would need to define a new variable. The list of fields is likely to change, so I'd like to put the listing of fields in a string to populate an array. From there, I want to loop through the array and dimension the variable. When I run code similar to below, I get the compile error "Constant expression required." If something like this isn't possible, is there a better way to achieve a similar result?
Public Sub Test()
Dim strFields as String
Dim arrFields() as String
strFields = "Field1|Field2|Field3"
arrFields = split(strFields,"|")
For Each x In arrFields()
Dim arrFields(x) As String
Next x
End Sub

Resources