PictureBoxes in an Array - arrays

Okay so I've got two problems with this code:
I have 8 picture boxes, I'm trying to run a check on a randomly generated number, to see if it matches the number at the end of the picture box (IE if the random number = 8, another constant gets put into picture box 8 and no other, but only if there isn't already something in it).
I have done it by simply running out every check as a single if statement but... 180 if statements later... that's too much to code.
I'm trying to (as you can see) run it through several while loops. The main part I'm having trouble with is assigning a particular picture box in the array with an image from the array. I can get an image using the imgName and imgPictures(i) using it in the format PictureBox1.Image = imgPictures(i), but not replacing PictureBox1.Image with picBoxes().Image.
Using the MsgBoxes that I've left in the code, the loops and if statements run "Debug1" and "Debug2" but none of the others... Why is this?
I'll leave the code and see what you guys can make of it.
Dim i As Integer = 1
Dim x As Integer = 1
Dim rndnumber As Integer = mathsclass.get_randomnumber()
Dim imgPictures(20) As Image
Dim picBoxes(8) As PictureBox
picBoxes = New PictureBox() {PictureBox1, PictureBox2, PictureBox3, PictureBox4, PictureBox5, PictureBox6, PictureBox7, PictureBox8}
Dim imgName As String = ("_" & i)
imgPictures(0) = My.Resources.ResourceManager.GetObject(imgName)
picBoxes(x).Image = imgPictures(i)
While (i <= 20)
MsgBox("Debug1")
rndnumber = mathsclass.get_randomnumber()
imgName = ("_" & i)
imgPictures(i) = My.Resources.ResourceManager.GetObject(imgName)
x = 0
While (x < 8)
MsgBox("Debug2")
If ((randomnumber = i) & (randomposition = x)) Then
MsgBox("Debug3")
picBoxes(x).Image = imgPictures(i)
Else
While (rndnumber = randomnumber)
MsgBox("Debug4")
rndnumber = mathsclass.get_randomnumber()
End While
MsgBox("Debug5")
If ((randomnumber <> rndnumber) & (randomposition <> x)) Then
MsgBox("Debug6")
imgName = ("_" & rndnumber)
imgPictures(i) = My.Resources.ResourceManager.GetObject(imgName)
picBoxes(x).Image = imgPictures(i)
End If
MsgBox("Debug7")
End If
MsgBox("Debug8")
x += 1
End While
MsgBox("Debug9")
i += 1
End While

Am not really sure which language you are trying to use here. I mean, whether it is VB.Net or class VB6!
I assume it is VisualBasic.Net (VB.Net).
Am not sure whether I understood you clearly. So, am giving you a small example code for you to try it out. The comments in it would pretty much explain I believe.
First create a new blank project. Add 5 textboxes in it(no need to change the names of it. Just drag and drop 5 nos. of textboxes). Add a Button and then double click on it and paste the code that I have shown below:
Dim rand As New Random '~~~ for creating the random numer
Dim intTotal As Integer = 5 '~~~ I have 5 textboxes with the names ending by number from 1 to 5
Dim intUpdated As Integer = 0 '~~~ to store the total number of updated textboxes
'~~~ first of all we are looping through the textboxes(am just showing how you can fetch them via it's name. There are other ways to iterate through the controls though!)
For i As Integer = 1 To intTotal
Dim tbox As TextBox = DirectCast(Me.Controls.Item("TextBox" & i.ToString()), TextBox) '~~~ here, we are fetching the TextBox via it's "Name" property, by appending the number at the end of "TextBox". Because in my form, I have "TextBox1", "TextBox2", "TextBox3", "TextBox4" and "TextBox5"
tbox.Tag = "untouched" '~~~ just setting it's "Tag" property to some text so that we could later use it evaluate whether we have touched this textbox via the random number
'-------------------------------------------------
'if you want to do something else like loading up default text or something, you can do it here too
'-------------------------------------------------
Next
'~~~ the randomly choosing part..
Dim j As Integer = 1
Do While intUpdated < intTotal '~~~ loop until we have taken into consideration all the textboxes via random number
Dim r As Integer = rand.Next(1, intTotal + 1) '~~~ create a random number between 1 and 5 (both inclusive)
'~~~ fetch that TextBox via it's name. Note that, am appending the random number to the name "TextBox". For eg, if the random number generated was "2", it would access "TextBox2"
Dim tbox As TextBox = DirectCast(Me.Controls.Item("TextBox" & r.ToString()), TextBox)
'~~~ since we have textbox now, we are checking whether we have accessed it earlier via random number
If tbox.Tag.ToString() = "untouched" Then '~~~ if not accessed before...
tbox.Tag = "touched" '~~~ mark the textbox as accessed via random number
intUpdated += 1 '~~~ increment the counter variable that we are using for storing the number of textboxes we accessed
'-------------------------------------------------
'~~~ do whatever you want on it here.. Right now, am just inserting some text on it to show the order in which the textboxes are accessed via our random number
tbox.Text = "updated" & j.ToString
j += 1
'-------------------------------------------------
End If
Loop
After running it, I hope you will be able to get the idea. To access a control name residing in your form, you could access it like this: Me.Controls.Item("control_name_goes_here"). So you can append numbers to the string when you mention the control's name. I have used this in code above. Look at it.
BTW, you are using & which is in VB, will act like concatenation operator! ie, Dim a As String = "Akhilesh" & "B Chandran". This will store Akhilesh B Chandran in that variable a. For AND operation, you need to use AND. In C, C++, C#, etc it is && (note that there is two ampersand characters)
Also, in VB.Net, you should use MessageBox.Show() instead of the MsgBox() function. That's the better way.
Hope this will help.

Related

Is there a way to transfer all values from one array to another, then erase the original array?

I'm running into a problem with a block of code I'm trying to develop at my job. Essentially, I'm creating a userform in excel where folks will enter data for railcars as they get loaded at a certain location (we'll call these "spot 1, spot 2, spot 3, etc.").
Sometimes they'll have to move that car to a different spot, in which case I want them to be able to keep all the information on the railcar from the first/original entry, and then erase the data from the original spot once that's done.
To accomplish this in a more streamlined fashion, I've established arrays for each of the 5 spots that reference all the cells they're entering data into on the userform:
Dim spot1information(14)
spot1information(0) = UserForm.ProductType1.Value
spot1information(1) = UserForm.ProductID1.Value
spot1information(2) = UserForm.BatchID1.Value
etc....
Dim spot2information(14)
spot2information(0) = UserForm.ProductType2.Value
spot2information(1) = UserForm.ProductID2.Value
spot2information(2) = UserForm.BatchID2.Value
etc....
And so forth for all five spots. I don't know if this makes things more difficult, but note that these array values aren't all of the same type. For instance, index (0) will be a string, but index (10) is a DATETIME and index (12) is defined as Long.
So say that they are moving a car from spot 1 to spot 2. In short, I want the code to do the following:
Replace the values of indices 0 - 6 in spot2information (which is currently empty) with the values of indices 0 - 6 in spot1information (which the user has filled on the userform).
I'm only interested in carrying over indices 0-6 because they contain the pertinent railcar information
Empty every value of spot1information to ""
To accomplish this, I tried the following code and a few variations thereof:
If OriginalSpot.Value = 1 Then
If DestinationSpot.Value = 2 Then
For i = 0 to 6
spot2information(i) = spot1information(i)
Next
For Each i in spot1information
spot1information(i) = ""
Next
End If
End If
However, this keeps coming up with a type mismatch. I figure because the data in the spot2information array is empty, and the data in the spot1information array is not, but I'm not entirely sure of a way around this.
Update: I did what was suggested below and replaced: spot1information(i) = "" with Erase spot1information
The code now essentially works! The values of array "spot2information" are now the former values of "spot1information", with "spot1information" now empty.
The 2D array suggested below also works like a charm. New problem I've been facing is that array values are updating, but the userform isn't. (note: in the future I'll be posting this type of thing as a separate question, my apologies!)
Easier to manage this as a 2D array:
Sub Tester()
Dim spots(1 To 5, 0 To 14), n As Long, i As Long
'fill your spot arrays from the form....
For n = 1 To 5
spots(n, 0) = UserForm.Controls("ProductType" & n).Value
spots(n, 1) = UserForm.Controls("ProductID" & n).Value
spots(n, 2) = UserForm.Controls("BatchID" & n).Value
'etc etc
Next n
'swap a spot with another
Debug.Print spots(2, 1), spots(3, 1)
SwapSpots spots:=spots, fromSpot:=2, toSpot:=3
Debug.Print spots(2, 1), spots(3, 1)
End Sub
Sub SwapSpots(spots, fromSpot As Long, toSpot As Long)
Dim n As Long
For n = 0 To 6
spots(toSpot, n) = spots(fromSpot, n)
spots(fromSpot, n) = Empty 'empty the source slot value
Next n
End Sub
Assuming the DataType of the arrays is the same by Index i.e. index(0) is string for all spots, Index(2) is long for all spots, and so on.
If that is the case then this part should not produce any error:
For i = 0 to 6
spot2information(i) = spot1information(i)
Next
The error should be happening in this part more precisely in the line marked with #
For Each i in spot1information
spot1information(i) = "" '#
Next
and the reason for the error it seems to be that trying to assign a string value "" to a numeric type, given the "mismatch" error.
Using For Each i in spot1information indicates that you want to "Initiate" or Erase the entire array, therefore I suggest to use this line instead of the For…Next method.
Erase spot1information
In regards this:
But I've now run into a new problem, where the values on the userform haven't updated to reflect the new values stored in the array. Do I need to somehow "refresh" the userform?
You just updated the arrays, then you need to run the procedures used to update the values of the objects affected by both arrays in the UserForm.

I'm having problems assigning values to an array I created in vb. Seems really simple but I can't figure out what I'm doing wrong

So I created an n x 2 array to hold some figures I would be inputting at runtime. Then I went ahead to add code which would add the values to the array. I wanted to know if the array was populated properly so I added code to populate a listbox with each figure inputted. However I don't think the array is populating as I think it should because the listbox isn't updating. The relevant code section is below;
N_secteion = txtNumSections.Text
Dim input_info(,) As Double = New Double(N_secteion - 1), 1) {}
Dim intIndexGrade As Integer
Dim intIndexLength As Integer
For intIndexGrade = 1 To N_secteion - 1
input_info(intIndexGrade - 1, 0) = Grade(intIndexGrade)
ListBox1.Items.Add(input_info(intIndexGrade - 1, 0).ToString())
Next
Grade(intIndexGrade) extracts values from another listbox on the form as the loop continues. This doesn't seem to be a problem since I've monitored it and it seems to pick up these values just fine. I would really appreciate some help. Been at this for too long.
N_secteion = txtNumSections.Text
Dim input_info(,) As Double = New Double((N_secteion - 1), 1) {}
Dim intIndexGrade As Integer
Dim intIndexLength As Integer
For intIndexGrade = 1 To N_secteion
input_info(intIndexGrade - 1, 0) = Grade(intIndexGrade)
ListBox1.Items.Add(input_info(intIndexGrade - 1, 0).ToString())
Next
So the issue was I wasn't looping through intIndexGrade enough times. Once this was corrected, the ListBox began to populate with all the values of the array variable because it only did so once the loop was complete.

How to create an array of Controls with different types i.e Textbox, combobox, checkbox...based on certain value

VB.net how to create an array of Controls with different types i.e Textbox, combobox, checkbox...based on certain value
This is the code:
Public Function TestControl(c As Integer())
Dim a As Control()
Dim l As Point
Dim F As New Form
For i As Integer = 0 To c.Length - 1
If c(i) Then
a(i) = New TextBox
Else
a(i) = New ComboBox
End If
a(i).Width = 400
a(i).Height = 40
l.Y = 50 + (3 * i - 2) * a(i).Height / 2
l.X = 150
a(i).Location = l
F.Controls.Add(a(i))
Next
F.Show()
Return Nothing
End Function
When I am trying to execute the Function the following Error appears:
Variable 'a' is used before it has been assigned a value. A null reference exception could result at runtime.
I am trying to solve it but i couldn't succeed.
any Idea would very helpful for me
Thanks
To solve your immediate probem of "Variable 'a' is used before it has been assigned a value. A null reference exception could result at runtime."
Your problem is that the line
Dim a As Control()
only creates a variable a that is capable of holding an array of control objects. It doesnt actually create an array, because it doesn't know how many elements to create.
In your situation the solution is straightforward. Change the line to
Dim a(c.Length) As Control
This will create an empty array of controls that you can add your TextBoxes and ComboBoxes.

Excel VBA: What is the Maximum Number of String Elements that can be Stored in an Array

I am trying to build an add-in which would offer the user several more functions.
The basis of these functions is to search through a reasonably large data set of 1424 string elements and return the array element position(s) of each identical match.
I wish to store the data set within the VBA code as it will never change and I do not wish to store it within a spreadsheet. Upon building the array I am faced with a problem whereby on the addition of the 1278th element, the entire array disappears.
Up until the 1277th element the array works and can be interrogated. As soon as I add one more element the entire array disappears! From what I can tell I am nowhere near to the maximum number of array elements allowed in VBA so this is failing due to some other problem.
Here is a snippet of my code:
Function matsearch(ByVal MatSpec As Variant) As String
Dim i As Integer, InstanceCount As Integer, LastInstance As Integer, FirstInstance As Integer
Dim Table_1ASpecList() As String
InstanceCount = 0
LastInstance = 1
Table_1ASpecList = Array("Spec_No", "SA/AS 1548", "SA/AS 1548", "SA/CSA-G40.21", "SA/EN 10028-2", "SA/EN 10028-3", "SA/EN 10028-7", "*****Many More Elements*****")
For i = 0 To UBound(Table_1ASpecList)
If MatSpec = Table_1ASpecList(i) Then
InstanceCount = InstanceCount + 1
LastInstance = i + 1
End If
Next i
FirstInstance = LastInstance - InstanceCount
matsearch = FirstInstance & " " & InstanceCount
Any ideas as to why this is not working?????
In the Visual Basic Editor, change the IsAddIn property of ThisWorkbook to False. Activate the workbook and enter the values to be populated in Table_1ASpecList into a sheet. Give the range a name, say "MyValues". Change the IsAddIn property back to True, and then amend your code to:
Dim Table_1ASpecList() As Variant
Table_1ASpecList = Sheet1.Range("MyValues").Value

Iterating through the elements in each row of a 2d array (vb.net)

Ok let me explain my question, here I have a 4x4 array of picture boxes which looks like this:
C1 C2 C3 C4
Row 1: [] [] [] []
Row 2: [] [] [] []
Row 3: [] [] [] []
Row 4: [] [] [] []
When the user presses on one of the picture boxes the background color of the picture box changes. I am trying to iterate through each of the rows to figure out which pictures box's have a red background per row. The timer interval is set in Beats Per Minute (60000 / textbox1.text). How do I accomplish this? I made the 2d array but the iteration is not working.
Dim graph(4, 4) As PictureBox
graph(1, 1) = PictureBox1
graph(1, 2) = PictureBox2
graph(1, 3) = PictureBox3
graph(1, 4) = PictureBox4
graph(2, 1) = PictureBox5
graph(2, 2) = PictureBox6
graph(2, 3) = PictureBox7
graph(2, 4) = PictureBox8
graph(3, 1) = PictureBox9
graph(3, 2) = PictureBox10
graph(3, 3) = PictureBox11
graph(3, 4) = PictureBox12
graph(4, 1) = PictureBox13
graph(4, 2) = PictureBox14
graph(4, 3) = PictureBox15
graph(4, 4) = PictureBox16
Private Sub Button5_Click_1(sender As System.Object, e As System.EventArgs) Handles Button5.Click
Dim tempo As Integer = CInt(TextBox1.Text)
Dim BPM As Integer = 60000 / tempo
Timer1.Interval = BPM
Timer1.Enabled = True
End Sub
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
For i As Integer = 1 To 4
Select Case i
Case 1
For value As Integer = 1 To 4
If graph(1, value).BackColor = Color.Red Then
MsgBox("sfd")
End If
Next
Case 2
For value As Integer = 1 To 4
If graph(2, value).BackColor = Color.Red Then
MsgBox("sfd")
End If
Next
Case 3
For value As Integer = 1 To 4
If graph(3, value).BackColor = Color.Red Then
MsgBox("sfd")
End If
Next
Case 4
For value As Integer = 1 To 4
If graph(4, value).BackColor = Color.Red Then
MsgBox("sfd")
End If
Next
Case Else
Debug.WriteLine("Not between 1 and 10, inclusive")
End Select
Next
End Sub
Private Sub PictureBox1_Click(sender As System.Object, e As System.EventArgs) Handles PictureBox1.Click
PictureBox1.BackColor = Color.Red
End Sub
Any Help is greatly appreciated. Thank you!
Before I answer your question, here is some general advice regarding your code:
VB array indices are zero-based. An array Dim arr(4) As ... declares an array with five elements (which can be accessed by index 0 through 4). Therefore, your array declaration of graph creates an array with 25 elements when you only need 16. Such waste of memory should be avoided.
The creation of your graph could be automated. It's probably even a better idea to create all picture boxes automatically. This way, if you want to change the graph size, you just have to change a single number instead of a whole bunch of code. Similarly, the bounds of your for loops should respect the actual array bounds instead of some pre-defined constants.
When you parse user input, you should handle incorrect input. Use Integer.TryParse() instead of CInt().
As a beginner, you should turn Option Strict On (via the project settings). This avoids narrowing implicit casts that you might not be aware of. E.g. it would tell you that 60000 / tempo results in a Double and by assigning that to an Integer variable you will loose precision.
I suspect that you have similar click handlers for all picture boxes. If all handlers are doing the same work, use a single handler. The method's sender argument tells you which picture box was clicked (you can cast it to the appropriate type).
Using a For loop does not make any sense if you split the body according to the loop variable. If you do different work in every iteration, don't use a loop at all and just write the code snippets after each other. However, in your case, a loop makes sense, though not as you used it. See next section for more information.
Now to your question. If you want to gather the checked boxes per row, you should use two nested loops. The outer loops iterates the rows and the inner loop iterates columns. Before starting the inner loop, you should reset a buffer that holds the indices of the checked boxes. I use the corrected indices (0 through 3). Furthermore, I assume that the first index in the graph array specifies the row and the second specifies the column. If that's wrong, you just have to swap the according pieces of code:
Dim checkedBoxes As New List(Of Integer) 'holds the indices of checked boxes in a row
For row As Integer = 0 To graph.GetUpperBound(0)
checkedBoxes.Clear()
For col As Integer = 0 To graph.GetUpperBound(1)
...
Next
'Now report the checked boxes.
MessageBox.Show("Checked boxes of row " & row & ":" & Environment.NewLine & _
String.Join(", ", checkedBoxes))
Next
The String.Join method is used to concatenate the list of column indices to a single string, separated by ,.
Now we just need to add code to the loop body that gathers the checked boxes:
If graph(row, col).BackColor = Color.Red Then
checkedBoxes.Add(col)
Next
That's all. No awkward Switch statement, no duplicate code. There are still some improvements that could make this code more efficient, but I'll leave it with this for now.
if you want two message boxes to appear at the same time, the only way would be to run them on different threads, ie after the conditional create a thread that runs the message box to keep the loop going. A message box will halt the code on that thread and waits for user input and the only way you can run 'msgbox()' at the same instant is with multiple threads. Otherwise what you are asking is impossible.

Resources