How to respond to events for objects in an array - arrays

I have made an array of tiles (pictureboxes) in an array and need them to all do something when clicked, but don't know how. Specifically, I want to be able to place some other object on them by clicking a tile and making that object go to that tile's location. I know you may suggest looking at the mouseposition variable and having some invisible box over all the tiles to register clicks, but I would like to know how to register any event for an object in an array for anything that comes up in the future. I do know how to register events for objects which aren't in an array by the way.
The object I want to move on top of the picturebox will also be from an object array, but a different one.
Here is my code:
Public Class Form1
Dim tiles(50) As PictureBox 'This is the object array of tiles
Dim plants() As String 'I haven't set this up yet, but this will be for the objects to be 'placed' on the pictureboxes.
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Dim tileWidth As Integer = 50
Dim tileHeight As Integer = 50
Dim xindent As Integer = 10
Dim yindent As Integer = 10
For x = 0 To 9
For y = 0 To 4
ReDim Preserve tiles(x * y)
tiles(x * y) = New PictureBox With {.Visible = True, .Size = New System.Drawing.Size(50, 50), .Parent = Me, .BackColor = Color.GreenYellow, .Image = Nothing}
tiles(x * y).Location = New System.Drawing.Point(x * tileWidth + xindent, y * tileHeight + yindent)
If (x Mod 2 = 0 And y Mod 2 = 0) Or (x Mod 2 <> 0 And y Mod 2 <> 0) Then
tiles(x * y).BackColor = Color.Green
End If
Next
Next
End Sub
End Class
I simply don't know how to set up the click event handler for the array of tiles so that's why its not in the code above.
Thanks in advance for your help.

AddHandler is there for that. After the New you just need to attach a function to the event
AddHandler tiles(x * y).Click, AddressOf Tile_Click
And have a function that handles the event
Private Sub Tile_Click(sender As Object, e As System.EventArgs)
' sender represent the reference to the picture box that was clicked
End Sub
If you already know the size of the array, you should ReDim your array just once instead of each time you loop (Move the ReDim out of the loops). Also, since y is 0 on the first loop, you are basically doing a ReDim of 0 elements (x*y = 0 when y = 0)

the_lotus has already given you a great answer.
Just wanted to share a trick I often use when wiring up events with AddHandler.
Declare a temporary variable using WithEvents in your class:
Public Class Form1
Private WithEvents Tile As PictureBox
...
Now, in the two DropDowns across the top of code editor, change Form1 to Tile, and (Declarations) to Click (or whatever event you want). This will enter a method for you that has the correct method signature:
Private Sub Tile_Click(sender As Object, e As EventArgs) Handles Tile.Click
End Sub
Delete the Handles Tile.Click portion that appears at the end of the first line:
Private Sub Tile_Click(sender As Object, e As EventArgs)
End Sub
Finally, remove your temporary declaration that used WithEvents.
Now you've got a method with the correct signature that you can use with AddHandler. This is very handy for events that don't have the standard signature.

Related

Displaying an array with unknown values into a lable box

I am new to coding with visual basic.
Recently, I was tasked by my professor to write a programme that allows the user to enter five words. The words then should be sorted and displayed in alphabetical order.
To do this I decided the best approach would be to use an array.
My thinking was that if I created a counter at the start, I can create a different value for each column of the array when a button is clicked.
If the array exceeds five I have a message box pop-up that resets the code (although I realise I will also have to clear the contents of the array).
My problem arises in displaying the array. I have looked for solutions online, and none have helped me as of yet.
I need to sort the array into alphabetical order and then display it in a label box (lbl_DisplayArray). As I do not know the values of the array, this has proved tricky.
My code is below:
Public Class Form1
Dim i As Integer = 0
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim Array(4) As String
Array(i) = txt_UserWords.Text
End Sub
Private Sub btn_Next_Click(sender As Object, e As EventArgs) Handles btn_Next.Click
i += 1
If i >= 5 Then
i = 0
MsgBox("Array Limit Exceeded. Code Reset")
txt_UserWords.Text = ""
End If
End Sub
Private Sub btn_Sort_Click(sender As Object, e As EventArgs) Handles btn_Sort.Click
lbl_DisplayArray.Text =
End Sub
End Class
You'd be better off using
private myList as new List(of String).
Then to sort them you just call the .Sort() method. Just call .Add(txt_userWords.Text) to add the new string and use .Count to see how many of them you have.
When you're adding them to the label you can use
lbl_DisplayArray.Text = String.Join(vbCrLf, myList)
You'll need the list of to be a member of the class instead of a local variable (as you have declared Array). This will keep it alive and allow you to access it in other methods.
---------- edit ----------
Public Class Form1
private myList as new List(of String)
Private Sub btn_Next_Click(sender As Object, e As EventArgs) Handles btn_Next.Click
If myList.Count >= 5 Then
myList.Clear
Else
myList.add(txt_UserWords.Text)
End If
txt_UserWords.Text = ""
End Sub
Private Sub btn_Sort_Click(sender As Object, e As EventArgs) Handles btn_Sort.Click
myList.Sort()
lbl_DisplayArray.Text = String.Join(vbcrlf, myList)
End Sub
End Class

How to monitor array's and reset when limit is reached. VB.net

I have a VB.Net program that loops through array's to try to figure out where bottles are on a "conveyor". The point of this program is to visually show staff, how the conveyor works using VB.net and Labels. It's extremely difficult to explain, so I’ll do my best.
Bottle_Number(10) Bottle_Position(128)
There are 10 bottles that I want to track at all 128 stops on the conveyor.
We have a conveyor that can only fit 10 bottles. I need to track the position of each of the 10 bottles. Once bottle 11 comes on - That means bottle 1 is completed and off the conveyor. So, bottle 11 becomes bottle 1, so I need to reset the position of bottle1 to 0, and continue tracking bottles 2-9 while also tracking bottle 11(Not bottle 1). Once bottle 12 comes on it becomes bottle 2, and I need to reset the position of bottle 2 to '0' and continue tracking all bottles.
Any help would be appreciated.
Here is my code:
Public Class frmMain
Dim Product_Position(10) As Integer
Dim Inches_Per_Pulse As Integer
Dim PulseNumber As Integer
Dim Product_Counter As Integer
Dim Product_Location(10) As Integer
Dim Function1 As Integer
Dim Function2 As Integer
Dim Function3 As Integer
Dim Function4 As Integer
Dim Function5 As Integer
Dim Function6 As Integer
Dim Function7 As Integer
Dim Function8 As Integer
Dim Function9 As Integer
Dim Function10 As Integer
Dim Product_in_Tunel As Integer
Dim test As Integer
Dim Roll_OVer As Boolean
Dim Product_Counter_Test As Integer
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
lblStatus.BackColor = Color.Green
lblStatus.Text = "Conveyor Status: Running"
End Sub
Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click
lblStatus.BackColor = Color.Red
lblStatus.Text = "Conveyor Status: Off"
End Sub
Private replace_next As Integer
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
If Product_Counter = 10 Then
replace_next += 1
If replace_next > 10 Then
replace_next = 1 ' replace them in turn 1..10, then loop back to 1
Product_Position(replace_next) = 0 ' put initial position here
End If
End If
Product_Counter = Product_Counter + 1
If Product_Counter > 10 Then
Product_Counter = 1
Roll_over = True
End If
'MsgBox(Product_Counter)
'MsgBox(replace_next)
End Sub
Private Sub btnPulse_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnPulse.Click
Get_Location()
End Sub
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
PulseNumber = "0"
Inches_Per_Pulse = "1"
Roll_OVer = False
'MsgBox("Test")
End Sub
Public Sub Get_Location()
'MsgBox(Product_Counter)
If Roll_OVer = True Then
Product_Counter_Test = 10
'MsgBox("i'm stuck here")
End If
If Roll_OVer = False Then
Product_Counter_Test = Product_Counter
End If
'MsgBox(Product_Counter_Test)
'MsgBox("am I here - Yes")
For test = 1 To Product_Counter_Test
'MsgBox("This works")
Product_Position(test) = Product_Position(test) + Inches_Per_Pulse
Next
PulseNumber = PulseNumber + 1
ClearLabels()
lblProduct1Position.Text = Product_Position(1)
lblProduct2Position.Text = Product_Position(2)
lblProduct3Position.Text = Product_Position(3)
lblProduct4Position.Text = Product_Position(4)
lblProduct5Position.Text = Product_Position(5)
lblProduct6Position.Text = Product_Position(6)
lblProduct7Position.Text = Product_Position(7)
lblProduct8Position.Text = Product_Position(8)
lblProduct9Position.Text = Product_Position(9)
lblProduct10Position.Text = Product_Position(10)
End Sub
Public Sub ClearLabels()
lblProduct1Position.Text = ""
lblProduct2Position.Text = ""
lblProduct3Position.Text = ""
lblProduct4Position.Text = ""
lblProduct5Position.Text = ""
lblProduct6Position.Text = ""
lblProduct7Position.Text = ""
lblProduct8Position.Text = ""
lblProduct9Position.Text = ""
lblProduct10Position.Text = ""
End Sub
The Pulse button is what is actually driving the conveyor, each pulse (click of the button) means the conveyor is moving forward.
Right now once the program gets to bottle 11, it resets and only moves forward the "new" bottle (bottle1). It should continue incrementing the remaining bottles until they reach the end and do the same for them - Reset the position to 0 and begin counting again.
As far as I understand it, once you have 11 bottles, you don't want to reset to only one bottle, but instead still have 10 bottles, and replace one of them. You'll need a second variable to keep track of which is to be replaced.
So instead of :
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
Product_Counter = Product_Counter + 1
If Product_Counter > 10 Then Product_Counter = 1
End Sub
It would be something like:
Private Replace_Next as Integer = 0
Private Sub btnSend_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSend.Click
If Product_Counter = 10 Then
Replace_Next += 1
If Replace_Next > 10 Then Replace_Next = 1 ' replace them in turn 1..10, then loop back to 1
Product_Position(Replace_Next) = .... ' put initial position here
Else
Product_Counter = Product_Counter + 1
End If
End Sub
Your conveyor is FIFO (first-in, first-out), so rather than constantly shifting, reindexing and/or rebuilding (=reset?) an array to make it seem like it is FIFO, Net includes the Queue(Of T) collection which is FIFO.
A LinkedList(Of T) could also be used. A plain List(Of T) would also work, but if the add/remove frequency is high, that will result in the same inefficient shifting taking place under the hood that you have with an array.
The only issue is enforcement of the size limit, which is easily handled with a small class wrapper. I assume there is something interesting or identifiable about the bottles other than their position. The test code uses a sequence ID and the contents.
Friend Class Bottle
Public Property Contents As String
Public Property SequenceID As Int32
' etc
Public Overrides Function ToString() As String
Return String.Format("{0}: ({1})", SequenceID.ToString("00"), Contents)
End Function
End Class
You likely have more relevant information to show. The, the collection class:
Friend Class BottleQueue
Private mcol As Queue(Of Bottle)
Private lbls As Label()
Private MaxSize As Int32 = 10 ' default
Public Sub New(size As Int32)
MaxSize = size
mcol = New Queue(Of Bottle)
End Sub
Public Sub New(size As Int32, l As Label())
Me.New(size)
lbls = l
End Sub
Public Sub Add(b As Bottle)
mcol.Enqueue(b)
Do Until mcol.Count <= MaxSize
mcol.Dequeue()
Loop
UpdateDisplay()
End Sub
Public Function Peek() As Bottle
Return mcol.ElementAtOrDefault(0)
End Function
Public ReadOnly Property Count() As Int32
Get
Return mcol.Count
End Get
End Property
Public Function Remove() As Bottle
Dim b As Bottle = Nothing
If mcol.Count > 0 Then
b = mcol.Dequeue
UpdateDisplay()
End If
Return b
End Function
Private Sub UpdateDisplay()
Dim n As Int32
If lbls Is Nothing OrElse lbls.Count = 0 Then
Return
End If
For n = 0 To mcol.Count - 1
lbls(n).Text = mcol.ElementAtOrDefault(n).ToString
Next
For n = n To lbls.Count - 1
lbls(n).Text = "(empty)"
Next
End Sub
Public ReadOnly Property GetQueue As Bottle()
Get
Return mcol.ToArray()
End Get
End Property
End Class
The class has 2 display means built in. One updates a set of labels. Since it is a collection, it also provides a way to get the current collection in order for a collection type control such as a Listbox. An even better way would be if the collection itself was "observable", so it could be used as a datasource.
It also provides a way to Removethe next bottle manually. Removing from a specific index (e.g. Remove(3)) is antithetical to a Queue, so it isnt implemented.
test code:
' form level vars:
Private BottleQ As BottleQueue
Private BottleID As Int32 = 7
' form load, passing the labels to use
' using a queue size of FIVE for test
BottleQ = New BottleQueue(5, New Label() {Label1, Label2, Label3, Label4, Label5})
Adding an item:
Dim material = {"Napalm", "Beer", "Perfume", "Pepsi", "Cyanide", "Wine"}
' add new bottle with something in it
BottleQ.Add(New Bottle With {.Contents = material(RNG.Next(0, material.Count)),
.SequenceID = BottleID})
BottleID += 1
' clear and show the contents in a listbox:
lbQueView.Items.Clear()
lbQueView.Items.AddRange(BottleQ.GetQueue)
The BottleId arbitrarily starts at 7, the contents are random. BTW, material shows just about the only way I ever use an array: when the contents are fixed and known ahead of time. In almost all other cases, a NET collection of one sort or another, is probably a better choice.
Because it is not an observable collection (and that is a little at odds with the FIFO nature), the listbox needs to be cleared each time. That could be internal to the class like the label display is. Results:
On the right, the first 5 are shown in order; 3 clicks later, the result is on the left: everything moved up 3 and 3 new items have been added.
Note: If the code using this needs to know when/which Bottle is removed from the conveyor, the class could include a ItemRemoved event which provides the item/Bottle just removed when adding forces one out. That is probably the case, but the question doesnt mention it.

Event not firing after item updated, even after re-adding the handler

In my Program Cyrus-Beck algorithm, I have to clip the points. The points inside the clipping window have to be red. The outside is still black.
I represent point in program as rectangle and I give the event handler for delete the point. when I wanted to delete points, points outside the window is working, but points that inside polygon didn't work, event the right-click event not call.
Here is my Point class.
Ignore the Component class, because it just nothing than handler to canvas in the main window
Public Class Points
Inherits Component
Public items As List(Of Point) = New List(Of Point)()
Public rects As List(Of Rectangle) = New List(Of Rectangle)
'add element
Public Overrides Sub Canvas1_MouseMove(sender As Object, e As MouseEventArgs)
canvas.Cursor = Cursors.Pen
End Sub
Public Overrides Sub Canvas1_MouseDown(sender As Object, e As MouseButtonEventArgs)
canvas.Cursor = Cursors.Pen
If e.LeftButton = MouseButtonState.Pressed Then
items.Add(e.GetPosition(canvas))
Dim p As Rectangle = New Rectangle()
p.Width = 3
p.Height = 3
canvas.SetLeft(p, e.GetPosition(canvas).X)
canvas.SetTop(p, e.GetPosition(canvas).Y)
p.Stroke = Brushes.Black
p.Fill = Brushes.Black
rects.Add(p)
End If
End Sub
'deleting element
'this method not calling when the element has updated
Sub point_rightClick(sender As Object, e As MouseButtonEventArgs)
Dim temp As Rectangle = New Rectangle()
temp = DirectCast(sender, Rectangle)
Dim pt As Point = New Point(Controls.Canvas.GetLeft(temp), Controls.Canvas.GetTop(temp))
canvas.Children.Remove(temp)
items.Remove(pt)
rects.Remove(temp)
End Sub
Public Shared Function samePoint(one As Rectangle, two As Rectangle) As Boolean
Return ((Controls.Canvas.GetLeft(one) = Controls.Canvas.GetLeft(two)) And (Controls.Canvas.GetTop(one) = Controls.Canvas.GetTop(two)))
End Function
Public Shared Function samePoint(one As Point, two As Rectangle) As Boolean
Return (one.X = Controls.Canvas.GetLeft(two)) And (one.Y = Controls.Canvas.GetTop(two))
End Function
End Class
To able to delete, I have deleting that represents the status, if deleting is true and currentState = MouseState.Pointer. the code will add handler to all the points (rectangles).
Private Sub chge_pointer_Click(sender As Object, e As RoutedEventArgs) Handles chge_pointer.Click
currentState = MouseState.Pointer
deleting = True
chooseHandler()
End Sub
Private Sub chooseHandler()
If deleting Then
For Each r As Rectangle In points.rects
AddHandler r.MouseRightButtonDown, AddressOf points.point_rightClick
Next
Else
For Each r As Rectangle In points.rects
RemoveHandler r.MouseRightButtonDown, AddressOf points.point_rightClick
Next
End If
End Sub
Before I modified the points to be red, I have to have a loop to check if the position is same, if the position same so edit the points
Dim z As CyrusBeck = New CyrusBeck(clippingWindow)
z.Clip(points.items)
'CyrusBeck has a properties 'points'
'CyrusBeck.points saves the all the point that inside the clipping window
For i As Integer = 0 To points.rects.Count - 1
For Each p As Point In z.points
If CGAProject.Points.samePoint(p, points.rects.Item(i)) Then
Dim temp_r As Rectangle = New Rectangle()
temp_r = points.rects.Item(i)
temp_r.Stroke = Brushes.Red
temp_r.Fill = Brushes.Red
points.rects.Add(temp_r)
points.rects.RemoveAt(i)
End If
Next
Next
when the program reaches this, currentState would Never to be MouseState.Pointer. so if user want to delete a point, user have to be press button chge_pointer so my chge_pointer_Click is called and all my handler would be re-setted again.
Why Rectangle.MouseRightButtonDown is not call when the rectangle has updated?
the rectangles that haven't update call the Rectangle.MouseRightButtonDown event, so I have re-set the handler.
What's worng?
Is there any alternative way so user can delete rectangle inside and outside the window?
Note :
I have resetted the handler just after I assigned back my Rectangle to the list, but it still didn't work.
I also create AddHandler temp_r.MouseRightButtonDown, AddressOf points.point_rightClick just after I assigned back my Rectangle to the list, but it didn't work either.
At the end of your events for clicking, like:
Sub point_rightClick(sender As Object, e As MouseButtonEventArgs)
I think you should have a "handles".
E.g.
Sub point_rightClick(sender As Object, e As MouseButtonEventArgs) Handles point.MouseClick
Without this, the sub will never be called (as it seems is happening).
This method also has no "handles"
Public Overrides Sub Canvas1_MouseDown(sender As Object, e As MouseButtonEventArgs)
and it could be:
Public Overrides Sub Canvas1_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Canvas1.MouseDown

(VB.net) Having a picturebox as a property of a class

I am currently making a space invaders game in vb (for a school project otherwise I would steer clear of this for making a game...)
I have a class called Invader, where the information on each enemy will be stored. Part of this is having a picturebox to display the image of the invader, which I have added as a property of the class.
Public Class Invader
' PROPERTIES '
Property X As Integer 'The X coordinate'
Property Y As Integer 'The Y coordinate'
Property PicBox As PictureBox 'The picturebox that holds the invader picture'
Property Type As String 'The enemy type that the invader is'
Property Health As Integer 'The health of the invader'
Property Speed As Integer 'The number of pixels that the invader moves when Move() is called'
Property Alive As Boolean 'Whether the invader is alive or not'
Property Direction As Integer 'The direction that the invader is 'facing'. 1 will be right and 0 will be left'
The array is then declared as
Public Enemy(0 To 3, 0 To 10) As Invader
The instances of the class are created from CreateEnemies()
Public Sub CreateEnemies()
For r = 0 To 3
For c = 0 To 10
Enemy(r, c) = New Invader
Next
Next
End Sub
Now, I have a sub called PositionEnemies() which will position each picturebox on the game form (called frmGame) and then load the picture into it and display it.
Public Sub PositionEnemies()
For r = 0 To 3
For c = 0 To 10
Enemy(r, c).PicBox = New PictureBox
Enemy(r, c).X = 0 + ((c + 1) * 110)
Enemy(r, c).Y = 362 - (((r + 1) * 100) - 100)
Enemy(r, c).Alive = True
Enemy(r, c).UpdateLocation(r, c)
Enemy(r, c).PicBox.ImageLocation = normalinvader
Enemy(r, c).PicBox.Load()
Enemy(r, c).PicBox.Height = 50
Enemy(r, c).PicBox.Width = 50
Enemy(r, c).PicBox.Visible = True
MsgBox(Enemy(r, c).PicBox.Created.ToString())
Next
Next
End Sub
I have added the messagebox at the end to tell me if the picturebox has been created, which at the moment always comes back as "false".
All of this is then called when frmGame loads
Private Sub frmGame_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Me.Show()
CreateEnemies()
PositionEnemies()
End Sub
If you have managed to follow all that, the problem I have is that the load of frmGame completes successfully, but none of the pictureboxes are actually created for some reason (the messagebox returns "false"). I have looked at this code for so long and not been able to figure out why - I hope one of you lovely people could help me out here.
Thanks
Every form wants that you add the controls to be displayed to its Controls collection.
If you don't do it, no display....
Private Sub frmGame_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
CreateEnemies()
PositionEnemies(Me)
Me.Show()
End Sub
Public Sub PositionEnemies(ByVal f as Form)
For r = 0 To 3
For c = 0 To 10
Enemy(r, c).PicBox = New PictureBox
Enemy(r, c).X = 0 + ((c + 1) * 110)
Enemy(r, c).Y = 362 - (((r + 1) * 100) - 100)
Enemy(r, c).Alive = True
Enemy(r, c).UpdateLocation(r, c)
Enemy(r, c).PicBox.ImageLocation = normalinvader
Enemy(r, c).PicBox.Load()
Enemy(r, c).PicBox.Height = 50
Enemy(r, c).PicBox.Width = 50
Enemy(r, c).PicBox.Visible = True
'MsgBox(Enemy(r, c).PicBox.Created.ToString())
f.Controls.Add(Enemy(r, c).PicBox)
Next
Next
End Sub
Also, I would move the call to Show after you have created your Enemies and positioned the PictureBoxes. Of course, if the PositionEnemies is inside the frmGame class then you could use directly the Me reference without passing it.
I think you should add
Me.Controls.Add(Enemy(r, c).PicBox)
in
Public Sub PositionEnemies()
below
Enemy(r, c).PicBox.Visible = True

Memory Game click events and random number generator

So I am building a Memory Game. This is a 2 part question. I have 16 boxes being used and need to have the numbers 1-8 twice. I have set up each box as a structure and have a random number generator randomly picking a number for a box and then randomly placing a number 1 - 8 into it. Problem I am coming across is this. I am getting repeat numbers for my boxes and more than 2 times for a digit that will be placed in that box, sometimes no sequential number being used all together. How can I make sure all 16 boxes are being created with out having to make code for 16 different instances. Also need to make sure each single digit number between 1-8 is being used and only used twice?
Second part of my question is I am having an issue with making a click event when a user chooses a box. Right now I can't figure out how to associate which box the user clicks on. I don't want to write code for 16 different boxes, link an array to each box and then populate each box that array's guess number. Is there a way I can simplify that code down to something short?
I have included all the code so far.
Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
Structure MemoryBox
Public intBox As Integer
Public intGuess As Integer
Public strGuess As String
End Structure
Private gameScore() As Integer
Private memoryGame(15) As MemoryBox
Dim countLoad As Integer = 0
Dim countScore As Integer = 0
Dim intScore As Integer
Private Sub LoadGame()
'this is where I am using the random numbers to make each box and populate it with a guess
Dim randomGen As New Random
Dim intMemBox As Integer
Dim intMemGuess As Integer
intScore = 0
If countLoad <= 15 Then
intMemBox = randomGen.Next(1, 16)
intMemGuess = randomGen.Next(1, 8)
memoryGame(countLoad).intBox = intMemBox
memoryGame(countLoad).intGuess = intMemGuess
memoryGame(countLoad).strGuess = intMemGuess.ToString
countLoad += 1
End If
End Sub
Private Sub GuessClick()
'trying to use this area for click event for each box click
lblMemory1.BackColor = Color.Green
lblMemory1.Text = memoryGame()
intScore += 1
lblScore.Text = intScore.ToString
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Call LoadGame()
End Sub
Private Sub btnNewGame_Click(sender As Object, e As EventArgs) Handles btnNewGame.Click
gameScore(countScore) = intScore
countScore += 1
Dim outFile As IO.StreamWriter
outFile = IO.File.AppendText("score.txt")
outFile.WriteLine(intScore)
outFile.Close()
Call LoadGame()
End Sub
Private Sub btnHighScore_Click(sender As Object, e As EventArgs) Handles btnHighScore.Click
Array.Sort(gameScore)
lblHighScore.Text = gameScore(0).ToString
End Sub
Private Sub btnAllScores_Click(sender As Object, e As EventArgs) Handles btnAllScores.Click
Dim inFile As IO.StreamReader
Dim strInfo As String
If IO.File.Exists("score.txt") Then
inFile = IO.File.OpenText("score.txt")
Do Until inFile.Peek = -1
strInfo = inFile.ReadLine
Loop
inFile.Close()
Else
MessageBox.Show("Can't find the score.txt file", "High Score", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
MessageBox.Show(strInfo, "All Scores", MessageBoxButtons.OK, MessageBoxIcon.Information)
End Sub
End Class
One option is to populate an array with the numbers you want, then randomly shuffle it. Use a loop that runs at least one times the length of the array and use the iterator value as one index and swap it with a randomly chosen index.
Something like this:
Dim memoryGame(15) As MemoryBox
Dim randomarray() As Integer = {1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8}
Dim rnd As New Random(Now.Millisecond)
For I = 0 To 15
Dim randindex As Integer = rnd.Next(0, 16)
Dim temp As Integer = randomarray(I)
randomarray(I) = randomarray(randindex)
randomarray(randindex) = temp
Next
For I = 0 To 15
memoryGame(I).intBox = randomarray(I)
Next
From here simply iterate through the array and assign the values to your boxes
To handle the click events:
Use the same handler for each box. One way is to add a Handles clause for each box. With 16 boxes this could get a little clunky. I would suggest in the load event handler iterate through the boxes and use the AddHandler statement to add the handler to each box. At this point sender will always point to the box that was clicked. It is simply a matter of casting sender as whatever type the box is, to access all the properties of the box.
If the boxes are buttons(Box1, Box2, etc.) it would look something like this:
For Each b As Button In Me.Controls.OfType(Of Button).Where(Function(x) x.Name.StartsWith("Box"))
AddHandler b.Click, AddressOf Button_Click
Next
Private Sub Button_Click(sender As Object, e As EventArgs)
Dim clickedbutton As Button = DirectCast(sender, Button)
'access the properties here
End Sub

Resources