Minesweeper VB.NET issue - vb.net

So basically, i have 2 int variables, x and y i am using to create a grid of pictureboxes.
This is all fluid and built on runtime.
I am trying to specifically change the picturebox on click if mine = 2.
I cannot specifically change one, when i click any, it changes all of them.
HELP PLEASE!!
Heres my code:
Public Class Form1
Inherits System.Windows.Forms.Form
Dim images(8) As Image 'declares image array
Dim zonesY As Integer = 50
Dim zonesX As Integer = 50
Dim Guy As Object
Dim pbxNewZone As PictureBox = DirectCast(Guy, PictureBox) 'declares pbxNewZone as a picturebox variable
Dim generator As New Random
Public Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
images(0) = Image.FromFile("blank.png")
images(1) = Image.FromFile("1.png")
images(2) = Image.FromFile("2.png")
images(3) = Image.FromFile("3.png")
images(4) = Image.FromFile("4.png")
images(5) = Image.FromFile("5.png")
images(6) = Image.FromFile("clear.png")
images(7) = Image.FromFile("hit.png")
images(8) = Image.FromFile("mine.png")
Dim x As Integer 'declares x as an integer variable
Dim y As Integer 'declares y as an integer variable
Me.SuspendLayout() 'suspends creation of layout
For y = 1 To zonesY 'starts a For loop (1 to zonesY number of loops)
For x = 1 To zonesX 'starts a For loop (1 to zonesX number of loops)
Dim zonesize1 As Integer
Dim zonesize2 As Integer
Dim mine As Integer
pbxNewZone = New PictureBox
Dim blockStatus As Integer
Dim allZones As Integer
allZones = zonesX * zonesY
blockStatus = generator.Next(0, allZones)
pbxNewZone.Name = (zonesX * (y - 1)) + x
If blockStatus < (allZones / 10) Then
mine = 1
If mine = 1 Then
pbxNewZone.Image = images(8)
End If
Else
mine = 2
If mine = 2 Then
pbxNewZone.Image = images(0)
End If
End If
pbxNewZone.Height = 16
pbxNewZone.Width = 16
pbxNewZone.Tag = 0
zonesize1 = pbxNewZone.Height 'sets out all of the boxes on the form.
zonesize2 = pbxNewZone.Width
pbxNewZone.Left = ((x - 1) * zonesize1 + 15)
pbxNewZone.Top = ((y - 1) * zonesize2 + 15)
Me.Controls.Add(pbxNewZone)
' Wire this control up to an appropriate event handler
AddHandler pbxNewZone.Click, AddressOf pbxNewZoneClicked
Next
Next
Me.Height = (pbxNewZone.Height * zonesY + 63) 'sets the height of fmmGame
Me.Width = (pbxNewZone.Width * zonesX + 40) 'sets the width of frmGame
checkBlank()
End Sub
Public Sub checkBlank()
End Sub
Private Sub pbxNewZoneClicked(ByVal sender As System.Object, ByVal e As System.EventArgs)
ReDim x
Do While y = 1 'starts a For loop (1 to zonesY number of loops)
Do While x = 1 'starts a For loop (1 to zonesX number of loops)
MsgBox("you have clicked " & x & ", " & y)
Loop
Loop
End Sub
End Class

You're adding the same handler to all the PictureBoxes but not doing anything to the specific PictureBox that was clicked (the Sender parameter). You can use the Name or Tag properties to work out what to do with the click. You might want to extend the standard PictureBox to include extra parameters that will make this easier - x and y properties for example.
As an aside you might want to consider re-factoring form_load so that it calls a number of more discrete methods.

In a Click event, sender will be the clicked object so...
Dim pbx as PictureBox = DirectCast(sender,PictureBox)
...will give you a reference (as pbx) to the clicked PictureBox - then you can do what you need to do with it.
For ease, you may want to check the state of a given PictureBox by checking pbx.Image - as you do not have any custom attributes of the PictureBox.

Related

Random picturebox arrangement

I am new to visual basics and was wondering how to do the following program: I have 9 picture boxes and a button "arrange". For my program, I would like that all picture boxes come together like a puzzle randomly to make a square that has a width and height of three picture boxes. The square made would have all nine picture boxes in one and every time you click the button "arrange" the picture boxes would change to a random location within the square. So far, I have written so that all the picture boxes become the same size but i don't know how to make them come together in a square. Thanks in advance.
Public Class frm1
Dim Placement As Integer
Private Sub btnArrange_Click(sender As Object, e As EventArgs) Handles btnArrange.Click
picDeux.Size = picgris.Size
picTrois.Size = picgris.Size
picQuatre.Size = picgris.Size
picCinq.Size = picgris.Size
picSix.Size = picgris.Size
picSept.Size = picgris.Size
picHuit.Size = picgris.Size
picNeuf.Size = picgris.Size
lstNum.Items.Clear()
For i = 1 To 3
For j = 1 To 3
Dim L As New Point(picgris.Width * j + 100, picgris.Height * i)
lstNum.Items.Add(L)
Next
Next
For i = 1 To 3
For j = 1 To 3
Placement = Int(Rnd() * (lstNum.Items.Count))
Next
Next
End Sub
End Class
I created nine pictures boxes at design time. You would assign a different image to each picture box. They are all square and the same size. Mine are 100 x 100 to make the arithmetic easy.
I made an array of points as a form level variable. These point will form a 300 x 300 square with the picture boxes. I also declared an array of PictureBox. In the Form.Load I added the pictures boxes to the array.
To reposition the picture boxes assigned the array to a list. Items in this list will be removed because we don't want to assign the same location to more the one picture box. This will not effect the original array.
Looping through the picture boxes we assign a random position to the box then remove that point from the list.
Public Class PictureSort
Private Rand As New Random()
Private PointArray As Point() = {New Point(100, 100), New Point(200, 100), New Point(300, 100), New Point(100, 200), New Point(200, 200), New Point(300, 200), New Point(100, 300), New Point(200, 300), New Point(300, 300)}
Private PictureBoxArray(8) As PictureBox
Private Sub PictureSort_Load(sender As Object, e As EventArgs) Handles MyBase.Load
PictureBoxArray = {PictureBox1, PictureBox2, PictureBox3, PictureBox4, PictureBox5, PictureBox6, PictureBox7, PictureBox8, PictureBox9}
End Sub
Private Sub RepositionPictureBoxes()
Dim lst = PointArray.ToList
For Each pb In PictureBoxArray
Dim index = Rand.Next(0, lst.Count)
pb.Location = lst(index)
lst.RemoveAt(index)
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
RepositionPictureBoxes()
End Sub
End Class
My advice is to use a control array - you have an example here that should help: VB.NET Control Array- Declaration and Application.
You just need to initiate that array of controls once, this can be done at form load.
The next step is to sort that array in a random manner. Finally, loop on the array and every time your current loop index modulo 3 = 0, then you increase the Y coordinates and reset the X position.
Here is an example. You can see that each time you click on the button, the picture boxes are rearranged on the form in random order using an ad hoc function. For each picture box, a bitmap is generated on the fly to show the index of the control.. this is for demonstration purposes.
Public Class frmPics
Private pics As New List(Of PictureBox)
Private Const picture_width As Integer = 100, picture_height As Integer = 50
Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
' instantiate controls
Dim font As New Font("Arial", 20, FontStyle.Regular, GraphicsUnit.Pixel)
For i As Integer = 1 To 9
Dim pic As New PictureBox
pic.Visible = False
pic.Name = "pic" & i
pic.Text = i.ToString
Console.WriteLine("Create control: name: " & pic.Name)
' generate an ad-hoc bitmap image showing the index of the control
Dim bitmap As New Bitmap(picture_width, picture_height)
Using g As Graphics = Graphics.FromImage(bitmap)
Dim width As Integer = CInt(g.MeasureString(Text, font).Width)
Dim height As Integer = CInt(g.MeasureString(Text, font).Height)
End Using
Using g As Graphics = Graphics.FromImage(bitmap)
g.Clear(Color.Blue)
g.DrawString(i.ToString, font, New SolidBrush(Color.White), 0, 0)
End Using
pic.Image = bitmap
pics.Add(pic)
Me.Controls.Add(pic)
Next
End Sub
Private Sub btnShuffle_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnShuffle.Click
Dim x As Integer = 10, y As Integer = picture_height
Dim counter As Integer = 1
Dim rnd As New Random()
' show controls on form
Console.WriteLine("Show controls on form")
Me.SuspendLayout()
For Each item In pics.OrderBy(Function() rnd.Next)
item.Width = picture_width
item.Height = picture_height
item.Location = New Point(x, y)
item.BorderStyle = BorderStyle.FixedSingle
item.Visible = True
Console.WriteLine("counter: " & counter & " - control name" & item.Name & " - position: " & item.Location.X & "/" & item.Location.Y & " text: " & item.Text)
' reset X position every 3 iterations
If counter Mod 3 = 0 Then
x = 10
y += item.Height
Else
x += item.Width
End If
counter += 1
Next
Me.ResumeLayout()
End Sub
End Class

Restrain form to the working area of the screen without flickering

I have working code but when moving the form to the screen bounds I sometimes get form flickering. It doesn't look good.
Is there a better solution for this?
Private Sub Form1_Move(sender As Object, e As EventArgs) Handles Me.Move
Dim p As Point
p = Me.Location
Dim screenWidth As Integer = Screen.PrimaryScreen.Bounds.Width
Dim screenHeight As Integer = Screen.PrimaryScreen.Bounds.Height
Dim TaskBarH As Integer = screenHeight - Screen.PrimaryScreen.WorkingArea.Height
If p.X < 0 Then
Me.Location = New System.Drawing.Point(0, p.Y)
ElseIf p.X > screenWidth - Me.Size.Width Then
Me.Location = New System.Drawing.Point(screenWidth - Me.Size.Width, p.Y)
End If
If p.Y < 0 Then
Me.Location = New System.Drawing.Point(p.X, 0)
ElseIf p.Y > screenHeight - Me.Size.Height - TaskBarH Then
Me.Location = New System.Drawing.Point(p.X, screenHeight - Me.Size.Height - TaskBarH)
End If
End Sub
The reason your form is flickering when you are moving it around, is because every time the form is redrawn in a different location, the Move event is fired. To see just how much, try this:
Option Strict On
Option Explicit On
Public Class Form1
Dim counter As Int64
Private Sub Form1_Move(sender As Object, e As EventArgs) Handles Me.Move
counter += 1
Console.WriteLine(counter)
End Sub
End Class
You'll notice that anytime the form is moved even just one pixel, the event is getting fired. You move the form 100 pixels to the left, that event is going to fire 100 times. That's a lot of work to be checking the location on every redraw of the form and then computing if each individual point is within the bounds that you want. All that constant computing of the points and rectangles and such is causing a huge overhead and the result is not enough resource time to redraw all of the controls in the form, hence the flickering of the form.
The better option would be to do all of that math only once when the form is done moving and correct the form if it is outside of the screen bounds. There is a Form.ResizeEnd event that is fired anytime the user has finished re-sizing or moving a form. By utilizing this event, the code will only get called once after the user has finished their action and the form has redrawn itself on the screen. Then if the form is outside of the bounds that you want, you can move the form to a location that is.
Rather than hard-coding the use of Screen.PrimaryScreen, I am dynamically getting the screen in which the form resides. This allows the user to move the form to a different screen in a multi-monitor environment.
Option Strict On
Option Explicit On
Public Class Form1
Private Sub Form1_resizeEnd(sender As Object, e As EventArgs) Handles Me.ResizeEnd
Dim screenArea As Rectangle = Screen.GetWorkingArea(Me.Location)
Dim formArea As Rectangle = Me.DesktopBounds
If Me.WindowState = FormWindowState.Normal AndAlso Not screenArea.Contains(formArea) Then
If formArea.Top < screenArea.Top Then Me.Top = 0
If formArea.Left < screenArea.Left Then Me.Left = 0
If formArea.Right > screenArea.Right Then Me.Left = Me.Left - (formArea.Right - screenArea.Right)
If formArea.Bottom > screenArea.Bottom Then Me.Top = Me.Top - (formArea.Bottom - screenArea.Bottom)
End If
End Sub
End Class
You can try restricting where the mouse can drag the form like this.
Option Strict On
Option Explicit On
Option Infer Off
Imports System.Runtime.InteropServices
Public Class Form1
Public Declare Function SetCursorPos Lib "user32.dll" (X As Integer, Y As Integer) As Boolean
Public Function AbsoluteFormMousePosition() As Point
Dim mousePos As Point = PointToClient(MousePosition)
Dim hBorderWidth As Integer = (Me.Width - Me.ClientRectangle.Width) \ 2
Dim vBorderWidth As Integer = hBorderWidth
Dim TitleHeight As Integer = (Me.Height - Me.ClientRectangle.Height) - vBorderWidth
Dim newPos As New Point(mousePos.X + hBorderWidth, mousePos.Y + TitleHeight)
Return newPos
End Function
Function TryOffest(range As Range, find As Integer, ByRef newValue As Integer) As Boolean
If Not range.Contains(find) Then
Dim diff As Integer
diff = If(find > range.Upper, find - range.Upper, range.Lower - find)
newValue += If(find > range.Upper, -(diff), diff)
Return True
End If
Return False
End Function
Private Sub Form1_Move(sender As Object, e As EventArgs) Handles Me.Move
Dim mousePos As Point = MousePosition
Dim newX As Integer = mousePos.X
Dim newY As Integer = mousePos.Y
Dim vChanged, hChanged As Boolean
Dim hBorder As Integer = Me.Width - Me.ClientRectangle.Width
Dim vBorder As Integer = Me.Height - Me.ClientRectangle.Height
Dim adjX As Integer = Me.PointToClient(mousePos).X
Dim adjY As Integer = Me.PointToClient(mousePos).Y
Dim titleMousePosition As Integer = hBorder - Me.PointToClient(mousePos).Y
Dim verticalBounds As New Range(AbsoluteFormMousePosition.Y + 2, Screen.PrimaryScreen.WorkingArea.Height - (Me.Height - vBorder - adjY + 2))
Dim horizontalBounds As New Range(adjX + 2, Screen.PrimaryScreen.WorkingArea.Width - (Me.Width - hBorder - adjX + 2))
vChanged = TryOffest(verticalBounds, mousePos.Y, newY)
hChanged = TryOffest(horizontalBounds, mousePos.X, newX)
If vChanged OrElse hChanged Then SetCursorPos(newX, newY)
End Sub
End Class
Public Class Range
Public Lower, Upper As Integer
Sub New(lower As Integer, upper As Integer)
Me.Lower = lower : Me.Upper = upper
End Sub
Public Function Contains(number As Integer) As Boolean
If number >= Lower AndAlso number <= Upper Then Return True Else Return False
End Function
End Class

VB.NET Getting Value On Dynamic Control

I am new to VB and run into some problems.
I have created sub routine that will automatically add a control to a panelcontrol each time i click on the button, so it can create as many as i want.
Here is the code for the subroutine.
Private Sub CreateControl()
'CREATE TEXTBOX ITEMNO
Dim i_Itemno As Integer = TextEditItemno.Length
ReDim Preserve TextEditItemno(i_Itemno)
TextEditItemno(i_Itemno) = New TextEdit
With TextEditItemno(i_Itemno)
.Name = "Txtitemno" & i_Itemno.ToString()
If TextEditItemno.Length < 2 Then
.SetBounds(0, 0, 32, 20)
Else
.Left = TextEditItemno(i_Itemno - 1).Left
.Top = TextEditItemno(i_Itemno - 1).Top + TextEditItemno(i_Itemno - 1).Height + 4
.Size = TextEditItemno(i_Itemno - 1).Size
End If
.Tag = i_Itemno
End With
AddHandler TextEditItemno(i_Itemno).TextChanged, AddressOf TextEditItemno_TextChanged
PanelControl5.Controls.Add(TextEditItemno(i_Itemno))
'CREATE TEXTBOX PRICE
Dim i_Price As Integer = TextEditPrice.Length
ReDim Preserve TextEditPrice((i_Price))
Dim PriceX As Int16 = LblHarga.Location.X
TextEditPrice(i_Price) = New TextEdit
With TextEditPrice(i_Price)
.Name = "Txtprice" & i_Price.ToString()
If TextEditSatuan.Length < 2 Then
.SetBounds(PriceX, 0, 70, 20)
Else
.Left = TextEditPrice(i_Price - 1).Left
.Top = TextEditPrice(i_Price - 1).Top + TextEditPrice(i_Price - 1).Height + 4
.Size = TextEditPrice(i_Price - 1).Size
End If
.Tag = i_Price
End With
AddHandler TextEditPrice(i_Price).TextChanged, AddressOf TextEditPrice_TextChanged
PanelControl5.Controls.Add(TextEditPrice(i_Price))
End Sub
And i call it in a button click.
Private Sub btnNew_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnNew.Click
CreateControl()
End Sub
Now what i am looking for is how to loop and get the value of those textboxes no matter how many textboxex i have create.
For i As Integer = 0 To TextEditItemno.Length - 1
' code to get the value of each textbox
Next
Thank you
This code goes in to your loop and gets the value of each textbox based on i.
Dim Text as String = TextEditItemno(i).Text
You may also be better served by using a List(of Textbox) rather than an array of textboxes. You don't need to worry about redimming the array, you can just do MyListOfTextboxes.Add(TheNewTextBox). You can still retrieve the value of each textbox the same way as the array.

How do I detect collision with spawned objects?

Public Class Form1
Dim i As Integer 'integer for spawning
Dim maxball As Integer = 50 'max ball able to be created
Dim RateX(maxball) As Integer 'rate of movement
Dim RateY(maxball) As Integer 'rate of movement
Dim ball(maxball) As PictureBox 'spawned ball is a picture box
Dim rnd As New Random 'random number generator
Dim rndLoc As Integer 'random locatino generator
Dim Loc As Point 'location is a point on the screen
Dim create As Integer 'integer to create new balls
Dim score As Integer = 0 'score is 0 but can increase
'move the ball
Private Sub moveball()
'For Each ball(ec) In ball
For i As Integer = 0 To create - 1
If ball(i).Left <= pbArena.Left Then 'bounce off left side
RateX(i) *= -1
End If
If ball(i).Right >= pbArena.Right Then 'bounce off right side
RateX(i) *= -1
End If
If ball(i).Top <= pbArena.Top Then 'bounce off top
RateY(i) *= -1
End If
If ball(i).Bottom >= pbArena.Bottom Then 'bounce off bottom
RateY(i) *= -1
End If
'====================================================================================================================================================
ball(i).Left += RateX(i) 'moves the ball horizontally
ball(i).Top += RateY(i) 'moves the ball vertically
'====================================================================================================================================================
Next
End Sub
'create the ball
Private Sub createball()
If create <= 50 Then '50 is max amount to
create += 1 'add 1 to create
ball(i) = New PictureBox 'ball is a picture box
ball(i).Size = New Size(45, 45) 'set size
ball(i).BackColor = Color.Red 'set color
'====================================================================================================================================================
ball(i).Top = rnd.Next(pbArena.Height - ball(i).Height) 'sets random y
ball(i).Left = rnd.Next(pbArena.Width - ball(i).Width) 'sets random x
'====================================================================================================================================================
RateX(i) = rnd.Next(-4, 4) 'random X direction/speed
RateY(i) = rnd.Next(-4, 4) 'random Y direction/speed
'====================================================================================================================================================
Me.Controls.Add(ball(i)) 'actually add teh ball
ball(i).BringToFront() 'bring to front so arena isn't in front
i += 1
End If
End Sub
'commands for when you touch black box
Private Sub pbTarget_MouseEnter(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles pbTarget.MouseEnter
pbTarget.Top = rnd.Next(pbArena.Height - pbTarget.Height) 'sets random y
pbTarget.Left = rnd.Next(pbArena.Width - pbTarget.Width) 'sets random x
'====================================================================================================================================================
'scoring system
score = score + 1
lblScore.Text = score
createball() 'creates a new ball
End Sub
'what happens when the timer ticks
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
moveball() 'every timer tick the ball will move IF its created
ball(i) = New PictureBox 'ball is a picture box
End Sub
End Class
This is my code so far. Each time the mouse intersects with the target (which is a picture box) is moves. I am replicating this game. http://www.lewpen.com/game/ I have used an array to spawn red squares on the form. I want to be able to detect when my mouse enters them. I know how to do this with picture boxes, but these are all spawned objects called ball(i). Thanks for the help!
It sounds like you want to know how to add an event handler to a dynamically created control. these are all spawned objects called ball(i) but they are all just pictureboxes. You can add event handlers when you create the balls (pictureboxes)
Private Sub createball(BallIndex As Integer)
Dim ball As New PictureBox 'ball is a picture box
' give it a name so we can find it
' ball index is PASSED to avoid sloppy global vars
ball.Name = "Ball" & BallIndex.ToString
' etc
Me.Controls.Add(ball)
AddHandler ball.MouseEnter, AddressOf BallMouseEnter
Elsewhere, you'd add the code for the event:
Private Sub BallMouseEnter(sender As Object, e As EventArgs)
' your code here
End Sub
Since the balls exist as controls in the Controls collection there is really no reason to keep a reference to them in an array. If you name them "Ball1", "Ball2" you can make them move by referencing them by name:
Me.Controls(ballname)
Where BallName would be "Ball" & index.ToString and index would be the ball/picturebox to move (like the i variable). EDIT More info:
Private Sub moveballS()
Dim ball As PictureBox
' loop thru ballS
For n As Integer = 0 To BallCount
' current ball from name
ball = Me.Controls("Ball" & n.ToString)
' your code here
If ball.Left <= pbArena.Left Then
' etc
End If
' you CAN just reference them in controls(),
' but it is wordy:
If Controls("Ball" & n.ToString).Left <= pbArena.Left Then
' etc
End If
Next n
End Sub
Another way to track them is just a List(Of String) to store the name, but that is equally unneeded if you can get them by name from Controls() as above:
Dim ballList As New List(Of String)
' when you create a ball:
ballList.Add(ball.Name)
to get a control reference:
For n As Integer = 0 To ballList.Count - 1
ball = Me.Controls(ballList(n))
' etc
It can be a bad idea to create a separate reference to dynamically created controls (like an array) since that ref can prevent the object from being disposed of if/when you reset or start over and are deleting balls/pictureboxes.

VB.net nearest control

Is there an easy way to get the nearest control to a control of choice?
I have a picture box and some other moving controls. I want to delete the nearest control to my picture box.
So I have to get the position of all controls and delete that with the Location nearest to the Location of my picture box. I'm not sure about how to do that the best way.
If "closest" in your case indeed means "with the Location nearest to the Location of my picture box", then the easiest would be:
Me.Controls.Remove((From c In Me.Controls.Cast(Of Control)() Order By c.Location.Distance(PictureBox1.Location) Select c).Skip(1).Take(1)(0))
, where Distance is defined in a module like this:
<System.Runtime.CompilerServices.Extension()> _
Public Function Distance(ByVal p1 As Point, ByVal p2 As Point) As Integer
Return (p1.X - p2.X) * (p1.X - p2.X) + (p1.Y - p2.Y) * (p1.Y - p2.Y)
End Function
Here's an entire sample form that calculates "closest" by checking if the supplied control is in 1 of 8 regions relative to the base control. Half of the code is setup trying to mimic the scenario you described. The MainButton_Click and below is the meat of the work.
Option Explicit On
Option Strict On
Public Class Form1
Private MainPB As PictureBox
Private OtherPB As List(Of PictureBox)
Private WithEvents MainButton As Button
Private Rnd As New Random()
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
'Setup the form with sample data
Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
Me.MainButton = New Button()
Me.MainButton.Text = "Update"
Me.MainButton.Left = 1
Me.MainButton.Top = 20
Me.Controls.Add(Me.MainButton)
Me.Width = 1000
Me.Height = 1000
MainPB = New PictureBox()
MainPB.BackColor = Color.Red
MainPB.Width = 100
MainPB.Height = 100
MainPB.Left = (Me.Width \ 2) - (MainPB.Width \ 2)
MainPB.Top = (Me.Height \ 2) - (MainPB.Height \ 2)
Me.Controls.Add(MainPB)
Me.OtherPB = New List(Of PictureBox)
For I = 0 To 50
Me.OtherPB.Add(New PictureBox())
With Me.OtherPB(I)
.BackColor = Color.Transparent
.BorderStyle = BorderStyle.FixedSingle
.Width = 50
.Height = 50
End With
SetRandomPbLocation(Me.OtherPB(I))
Me.Controls.Add(Me.OtherPB(I))
Next
End Sub
Private Sub SetRandomPbLocation(ByVal pb As PictureBox)
'Just sets a random location for the picture boxes and ensures that it doesn't overlap with the center PB
Do While True
pb.Left = Rnd.Next(1, Me.Width - pb.Width)
pb.Top = Rnd.Next(1, Me.Height - pb.Height)
If (pb.Right < Me.MainPB.Left OrElse pb.Left > Me.MainPB.Right) AndAlso (pb.Top > Me.MainPB.Bottom OrElse pb.Bottom < Me.MainPB.Top) Then
Exit Do
End If
Loop
End Sub
Private Sub MainButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles MainButton.Click
'Randomizes the location of the picture boxes
For Each PB In Me.OtherPB
SetRandomPbLocation(PB)
Next
'Will hold the closest control after the loop
Dim ClosestPB As Control = Nothing
Dim ClosestD, TempD As Double
For Each PB In Me.OtherPB
'Reset the control's background color
PB.BackColor = Color.Transparent
'Calculate the distance
TempD = GetDistanceBetweenToControls(PB, Me.MainPB)
If ClosestPB Is Nothing Then 'If this is the first time through the loop then just use this control as the closest
ClosestPB = PB
ClosestD = TempD
ElseIf TempD < ClosestD Then 'Otherwise if this control is closer than the current closest
ClosestPB = PB
ClosestD = TempD
End If
Next
'Set the closest controls background color so that we can see it
ClosestPB.BackColor = Color.Blue
End Sub
Private Shared Function GetDistanceBetweenToControls(ByVal controlToCheck As Control, ByVal baseControl As Control) As Double
If controlToCheck.Bottom < baseControl.Top Then
If controlToCheck.Right < baseControl.Left Then 'Above and to the left
Return DistanceBetweenTwoPoints(New Point(controlToCheck.Right, controlToCheck.Bottom), baseControl.Location)
ElseIf controlToCheck.Left > baseControl.Right Then 'above and to the right
Return DistanceBetweenTwoPoints(New Point(controlToCheck.Left, controlToCheck.Bottom), New Point(baseControl.Right, baseControl.Top))
Else 'Above
Return baseControl.Top - baseControl.Bottom
End If
ElseIf controlToCheck.Top > baseControl.Bottom Then
If controlToCheck.Right < baseControl.Left Then 'Below and to the left
Return DistanceBetweenTwoPoints(New Point(controlToCheck.Right, controlToCheck.Top), New Point(baseControl.Left, baseControl.Bottom))
ElseIf controlToCheck.Left > baseControl.Right Then 'Below and to the right
Return DistanceBetweenTwoPoints(controlToCheck.Location, New Point(baseControl.Right, baseControl.Bottom))
Else 'Below
Return controlToCheck.Top - baseControl.Bottom
End If
Else
If controlToCheck.Right < baseControl.Left Then 'Left
Return baseControl.Left - controlToCheck.Right
ElseIf controlToCheck.Left > baseControl.Right Then 'Right
Return controlToCheck.Left - baseControl.Right
End If
End If
End Function
Private Shared Function DistanceBetweenTwoPoints(ByVal point1 As Point, ByVal point2 As Point) As Double
'Standard distance formula
Return Math.Sqrt((Math.Abs(point2.X - point1.X) ^ 2) + (Math.Abs(point2.Y - point1.Y) ^ 2))
End Function
End Class