I need to understand how I can relate the array of controls I dim in VBA code with the related form and the syntax etc. needed in the code to manipulate the array.
I'm wanting to populate and present an array of textboxes with strings that have been constructed as a result of processing data in a series of tables.
As an initial test, I've tried the following code. I've not yet thought of any way I might attempt to create an array on the surface of a form.
I have several text books on VBA but none of them seem to have anything to say on this.
Can anyone throw any light on this or recommend a more advanced text book?
Dim mytext(20) As TextBox
Dim x As Long
For x = 0 To 19
mytext(x).Value = str(x)
Next x
This results in an error at line 4:
Object variable or With block variable not set
How are you populating your array of Textboxes?
Since Textboxes are objects, you'll need to use Set, e.g.:
Dim mytext(20) As TextBox
Set mytext(0) = Text0
Set mytext(1) = Text2
Set mytext(2) = Text4
Set mytext(3) = Text6
...
Aside, Str is a built-in function in VBA, it should not be used as the name of a
variable.
Related
I am attempting to pass a range from a RefEdit control in a userform to an array in VBA using statements like:
y0 = Range(RefEdit1.value)
I thought by using the .Value property, this would exclude formatting from whatever selection the user made in RefEdit1 and just the raw, unformatted values would be stored in y0. However, this is NOT happening: When I test it and select a range with currency values, the formatting is stored in y0 and, of course, is problematic for future calculations.
I even tried this:
y0 = Range(RefEdit1.value).value
But that did not work either. Any assistance is appreciated.
===============================
Thank you for your response. See the screenshots below. The numeric values with the currency format in M2:M21 are selected using RefEdit1. Notice the actual value printed in the function bar (highlighted in the red box): These are the values that I want to store in y0 (the raw, unformatted, UNROUNDED values):
Here is the code:
And here are the values that are printed to P35:
Not only has it retained the unwanted formatting, it has rounded the values. Any ideas? IMPORTANT: It is a standard feature of this particular application that the user has the option to include the column name. Therefore, the leading element in this selection is often (not always) alphabetic. Might this be an operative factor in the problem?
===============================
As per Michal's most recent response, I tried the following, but the problem still persists.
Any further assistance is very much appreciated.
Not sure if it's going to suit your needs but it seems to work:
Option Base 1
Private Sub CommandButton1_Click()
Dim y0() As Double
Dim rng As Range
Set rng = Range(RefEdit1)
ReDim y0(rng.Count)
For a = 1 To rng.Count
y0(a) = rng.Item(a)
Next
Range("H2").Resize(rng.Count, 1) = Application.Transpose(y0)
End Sub
After further research, I found that using the .Value2 property instead of .Value addressed this issue:
I am working on an excel sheet, which collects data from a website. A few words about this website:
- it is independant from me, I can not change its struckture
- it should look like a table, but it is not. The structure is like this:
<h4>blabla</h4><span class="address">blabla</span><span class="state_x">blabla</span>
<h4>blabla</h4><span class="address">blabla</span><span class="state_x">blabla</span>
<h4>blabla</h4><span class="address">blabla</span><span class="state_y">blabla</span>
The trick is the "state_?" class, its name can change (but only the end of it).
What am I doing now?
- collect all the data into arrays
- of course I will get "state_x" and "state_y" arrays
- go through the arrays, and write everything to a sheet
The problem:
When I get to the "state_?" arrays, I already don't know, where its data came from.
The best would be to have only one "state" array, which can collect data from any "state_?" classes. Of course this code doesn't work, but to show the logic:
Dim state As Variant
Set state = ieApp.Document.getElementsByClassName("state_*")
How could this work? Any help is appreciated, please consider, that I am new in vba.
NEW INFOS
I have found some further help by analysing the source HTML code. Each row is nested in a <div class="listitem"> </div>. Is it possible to create an array, where each element is a complete "listitem" div, and with a for loop extract the data from these elements, as written above?
Each "listitem" div can contain only one "state_?" class. So this way I wouldn't loose the information, where the data comes from.
Try querySelectorAll with selector e.g. "*[class^='state_']" which should select all elements which have class name that starts with text state_. More about selectors here. HTH
Dim states As IHTMLDOMChildrenCollection
Set doc = ie.document
Set states = doc.querySelectorAll("*[class^='state_']")
If (Not states Is Nothing) Then
Dim i
For i = 0 To states.Length - 1
Debug.Print states(i).innerHTML
Next i
End If
someone knows if it's possible create a fixed size ArrayList? Or I have to use necessarily an array?
I try with this
Dim array As ArrayList
array = New ArrayList(10)
and
array.Capacity = 10
But I can add more than 10 items, and it doesn 't show me any kind of error how I expected.
Thanks
Just use an Array this size will not change unless you explicitly code it to.
Dim myArray(9) As String 'or whatever object you need Integer, etc.
Note that specifying 9 will create 0-9 i.e. 10 items in your array
(ArrayLists are bad in many many ways so don't use them)
Capacity of ArrayList tells the maximum number of items ArrayList can currently hold. Capacity will be increased automatically at run time when more items are added in the ArrayList.
For fixed size, use Array as mentioned below:
Dim intArray(9) As Integer
If you are wanting to store different types in your collection you can use;
Dim myArray(5) As Object
If you wanted to read them back as the type you put them in as you would have to convert their type back what they were originally.
I do not recommend this as an approach. If you want to do this then I suggest you create a custom object such as a class or structures that will contain properties for each of the values you wish to set.
I am working on a very old visual basic project. I have to rewrite the load and save function of the project. Therefore I wanted to create an array of controls which have all relevant textboxes and checkboxes included. I want to iterate through that array to be able to save the data into a textfile or load from it.
I have looked on the internet of how you can define those arrays, but it doesn't seem to work for me. Maybe I am doing something wrong, cause I am not an expert in Visual Basic.
I have tried to make it work this way:
Dim tbList As TextBox = { Form1.Text1, Form1.Text3, _
Form1.Text10, Form1.Text11, Form1.Text12, Form1.Text13, _
Form2.Text1, Form2.Text3, Form2.Text4, Form2.Text5, _
Form2.Text10, Form2.Text11, Form2.Text12, Form2.Text13, _
Form3.Text1, Form3.Text3, Form3.Text4, Form3.Text5, _
Form3.Text10, Form3.Text11, Form3.Text12, Form3.Text13, _
Form3.Text17, Form3.Text18, Form3.Text19, Form3.Text20, _
Form4.Text1, _
Form5.Text1, Form5.Text2, Form5.Text3, _
Form6.Text2, _
Form7.Text2}
Or with a list:
Dim tbList As New List(Of Controls)
The thing is Visual Basic always tells me there are some kind of compiling issues. There is no real explantation for this issue in VB, so I am asking here.
Your code isn't compiling because it is vb.net code. It should go without saying (but I'll say it anyway) that vb6 and vb.net are not the same thing.
If you want to use an array, you will have to dimension the array with a number that is one less than your number of textboxes (if I counted correctly there are 32 in your example):
'// array is zero based so 0 to 31 = 32 items
Dim tbList(31) As TextBox
tbList(0) = Form1.Text1
tbList(1) = Form1.Text3
'//...I'll leave the rest as an exercise for the programmer
tbList(31) = Form7.Text2
Dim i As Integer
Dim tb As TextBox
'// To loop and work with each textbox
For i = 0 To UBound(tbList)
Set tb = tbList(i)
'// do something with tb
Next
An easier way to do it, however, is to work with a collection:
Dim tbList As New Collection
tbList.Add Form1.Text1
tbList.Add Form1.Text3
'//...I'll leave the rest as an exercise for the programmer
tbList.Add Form7.Text2
Dim tb As TextBox
'// To loop and work with each textbox
For Each tb In tbList
'// do something with tb
Next
Yes, you can use a collection if you want to go to the trouble. But an even easier way to work with it is to use VB6's (now obsolete) control array implementation. Most of us were disappointed when we found it was no longer available in .Net!
All you have to do to get control arrays in VB6 is create a bunch of controls with the same name. (They do have to be the same type of control; you can't make arrays of, say, text boxes and combo boxes.) Start with one text box, name it what you want, and copy it. You will be asked if you want to create a control array. Say yes, copy as many as you want. You will notice that the Index property is no longer blank, starting with 0 and incrementing from there. You will also notice that all of the event handlers have an "Index As Integer" argument to them. This way, you can use the same event handler for all of them, evaluating the Index argument to find out which member of your array is firing the event.
Here is the old doc for it. Microsoft makes it hard to find. :)
I am currently working on a module that is meant to populate three ActiveX ListBoxes. Each will be populated with the same values: choices for axes titles on a graph (X-axis, Primary Y-Axis and Secondary Y-Axis). I have a function called "FillBox" that takes a ListBox as an argument and populates it.
Originally I used the following to accomplish this:
Sub FillAllBoxes()
FillBox X_BOX
FillBox Y1_BOX
FillBox Y2_BOX
End Sub
I was informed that I cannot use a Union to compact this code because of the MSForms.ListBox object type. There are many other subs that perform a repeated operation on each box, so it appears that some sort of array would be best to use.
So far, the only way I have found to define this array of ListBoxes is the following, though I am unsatisfied with the fact that the return value is a Variant but I can't seem to get it to work if I define it as Function BOX_ARRAY() As MSForms.ListBox:
Function BOX_ARRAY() As Variant
Dim Temp(1 To 3) As MSForms.ListBox
Set Temp(1) = X_BOX
Set Temp(2) = Y1_BOX
Set Temp(3) = Y2_BOX
BOX_ARRAY = THIS_ARRAY
End Function
I can then use this sub, though I needed to explicitly define the argument to FillBox as ByVal, because BOX_ARRAY is a variant.
Sub FillAllBoxes()
For j = LBound(BOX_ARRAY) To UBound(BOX_ARRAY)
FillBox BOX_ARRAY(j)
Next j
End Sub
A) Is there any way to have a function return an array that is not a Variant?
B) Would it be wise to stick with my original method of just repeating the function explicitly for each list box or is it worth using arrays for this type of operation?
C) In the function BOX_ARRAY is there a way around defining a Temp array and just populating the returned array right off the bat?
Here goes:
There are many other subs that perform a repeated operation on each box
Simply pass the ListBox to a function that operates on listboxes, e.g.:
Sub MyExample()
EnableListBoxes Array(Me.ListBox1, Me.ListBox2, Me.ListBox3)
End Sub
Sub EnableListBoxes(boxes as Variant)
Dim lbox as variant
For each lbox in boxes
lbox.Enabled = True
Next
End Sub
Alternatively you can pass the entire form/worksheet/whatever contains the listboxes, and iterate over the collection containing them (e.g., UserForm.Controls, etc.) You'd need to do some additional logic to make sure you're operating on the right type of form control, but that is relatively easy to do.
I can't seem to get it to work if I define it as Function BOX_ARRAY() As MSForms.ListBox
Of course not, because an MSForms.ListBox is a single object. You can't expect to return an array of anything in to a function that is designed to return an object.
Is there any way to have a function return an array that is not a Variant?
Perhaps use a subroutine and pass the arguments ByRef. You don't need to return a value if you are operating on the reference directly, rather than a local copy of it. See Chip Pearson for some detailed explanations/examples:
http://www.cpearson.com/excel/passingandreturningarrays.htm
Sub TestByRef()
Dim i as Integer
i = 1
ChangeValue i
Debug.Print i
End Sub
Sub ChangeValue(ByRef x as Integer)
x = 3
End Sub
In the function BOX_ARRAY is there a way around defining a Temp array and just populating the returned array right off the bat?
Not that I can think of. Perhaps with a class module and the class _Initialize method, you could automatically assign one of the class properties. But I think that ultimately is the same method: creating a temporary array that defines the return value. It is hard to tell for sure since you don't provide enough code (e.g., where are the variables? are they even declared?