How to use properties of dynamically created picturebox in vb.net - vb.net

I was trying to remove this "brickn" when ball intersect with this brick
but i am facing problem that "brickn" is not declared any helps?
there is code
Dim brickWidth as Integer = 0
Public Function CreateBrick() As PictureBox
Dim Brickn As New PictureBox
Me.Controls.Add(Brickn)
Brickn.Size = Brick.Size
Brickn.Left = BrickWidth
Brickn.Top = 0
Brickn.Image = Brick.Image
Brickn.SizeMode = PictureBoxSizeMode.StretchImage
Brickn.BackColor = Color.Black
Return Brickn
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i= -75 To Me.Width
CreateBrick()
BrickWidth += 170 ' increasing brick.left on every new brick is created
i += 170 ' increasing looop count according to brick needed
Next
Private Sub Boll_control_Tick(sender As Object, e As EventArgs) Handles Boll_control.Tick
If Ball.Bounds.IntersectsWith(brickn.Bounds) Then
Me.Controls.Remove(brickn)
End If
End Sub
why this "brickn" is not saying not declared in "boll control tick " timer

You are instantiating brickn withing CreateBrick. You are returning it as the result of that function, but not assigning it to anything. So it's scope is limited to the CreateBrick fuction only, which is why it's not accessible from Boll_control_Tick.
Also you are then trying to create multiple instances of it with using a single object.
This code will allow you to create one or more. You will then need to rework your Boll_control_Tick to work out whether it intersects with any. You may want to create a list or array of PictureBox objects as Brickn instead of one.
Dim brickWidth as Integer = 0
Dim Brickn As PictureBox ' This may be better as a list or an array
Public Function CreateBrick() As PictureBox
Dim myBrickn As New PictureBox
'Note - no idea what Brick is here or where it comes from
Brickn.Size = Brick.Size
Brickn.Left = BrickWidth
Brickn.Top = 0
Brickn.Image = Brick.Image
Brickn.SizeMode = PictureBoxSizeMode.StretchImage
Brickn.BackColor = Color.Black
Return myBrickn
End Function
and then in your Form_Load method:
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i= -75 To Me.Width
Brickn = CreateBrick() ' or add to your List/Array here
Me.Controls.Add(Brickn)
BrickWidth += 170 ' increasing brick.left on every new brick is created
i += 170 ' increasing looop count according to brick needed
Next
That will add multiple picture boxes to your controls and, if you want, create a list or array of them for easy access. You will need to loop through those in Boll_control_Tick to see if ball bounds intersects with any and then remove that specific one only

Related

How to create an array of PictureBoxes and use it?

I thought "brickn()" will creat an array and "NoOfBrick" will be the array length and all array will store in it
Dim brickWidth as Integer = 0
Dim Brickn() As PictureBox
dim NoOfBrick as Integer ' array length
Public Function CreateBrick() As PictureBox
Dim myBrickn As New PictureBox
With myBrickn
.Size = Brick.Size
.Left = BrickWidth
.Top = 0
.Image = Brick.Image
.SizeMode = PictureBoxSizeMode.StretchImage
.BackColor = Color.Black
End With
Return myBrickn
End Function
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
For i = -75 To Me.Width
Brickn(NoOfBrick) = CreateBrick() 'and also how to add array/list here
Me.Controls.Add(Brickn(NoOfBrick))
BrickWidth += 170 'increasing brick.left on every new brick is created
i += 170 ' increasing looop count according to brick needed
NoOfBrick +=1
Next
End Sub
But this code is throwing error on "Me.Controls.Add(Brickn(NoOfBrick))"
this error
System.NullReferenceException: 'Object reference not set to an instance of an object.'
I thought if I will get array of PictureBoxes then I can access control on them for this
Private Sub Boll_control_Tick(sender As Object, e As EventArgs) Handles Boll_control.Tick
If Ball.Bounds.IntersectsWith(brickn(NoOfBrick).Bounds) Then
Me.Controls.Remove(brickn(NoOfBrick))
End If
End Sub
Change:
Dim Brickn() As PictureBox
To:
Dim Brickn As New List(Of PictureBox)
Then, when you want to Add something to "Brickn", you'd do:
Brickn.Add(CreateBrick())
You can still access "Brickn" with array syntax, such as:
Brickn(NoOfBrick).Bounds
The difference is that a List will automatically grow or shrink in size as you add/remove things to it, while an Array has a fixed size (you never actually created the array in your code and gave it a size).
You can do hit testing with something like:
Dim hit = Brickn.Where(Function(brick) Ball.Bounds.IntersectsWith(brick.Bounds))
For Each brick As PictureBox In hit
Me.Controls.Remove(brick)
Brickn.Remove(brick)
Next

Moving picturebox according to the score of the dice

I am new to visual basic and am needing some help. I am creating a board game where you have to roll a dice and depending on the side it lands on, the picture box moves accordingly. I have labels put together in a square shape making up a look alike grid that is 5 rows and 10 columns. So far, I have the part for when the player clicks the button "Rouler" they get a randomized side of the dice. I would like for each time the dice is rolled it moves along the grid accordingly to the number the dice has picked.
Public Class frm1
Dim Rand As New Random
Dim Dé(5) As Image
Private Sub btnRouler_Click(sender As Object, e As EventArgs) Handles btnRouler.Click
Dim n As Integer
n = Rand.Next(4)
PictureBoxDé.Image = Dé(n)
End Sub
Private Sub frm1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dé(0) = My.Resources._11
Dé(1) = My.Resources._2
Dé(2) = My.Resources._3
Dé(3) = My.Resources._4
Dé(4) = My.Resources._5
Dé(5) = My.Resources._6
I think you are saying you have 50 labels arranged in 10 columns and 5 rows. The De array contains the dice images.
This is one approach. Make a small class called Player. When you add a second player you will see the value of this.
You will need an array of the labels, indexes 0-49.
When you roll the die, you choose the appropriate image form the De array. Next, you clear the Player1.Token from the CurrentPosition Label. You also increase the players current position by n + 1. If he rolls a 1 (De(0)) you add one to n to move 1 space. Finally, you add a the Player1.Token to the label at the new position.
Public Class Player
Public Property Token As Image
Public Property CurrentPosition As Integer
Public Sub New(Pic As Image)
Token = Pic
CurrentPosition = 0
End Sub
End Class
Private Player1 As Player
Private Dé(5) As Image
Private LabelArray(49) As Label
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
LabelArray = {Label1, Label2, Label3, Label4} 'etc.
Player1 = New Player(Image.FromFile("Dog.png"))
Dé(0) = My.Resources._11
Dé(1) = My.Resources._2
Dé(2) = My.Resources._3
Dé(3) = My.Resources._4
Dé(4) = My.Resources._5
Dé(5) = My.Resources._6
End Sub
Private Sub btnRouler_Click(sender As Object, e As EventArgs) Handles btnRouler.Click
Dim n As Integer
n = Rand.Next(6) 'Non negative integer, one less than the parameter - in this case 0 to 5
PictureBoxDé.Image = Dé(n)
Player1.CurrentPosition += n + 1
LabelArray(Player1.CurrentPosition).Image = Player1.Token
End Sub

How to add infinite components when a button is clicked

I have a social media WinForm. I have a function that basically makes a new picture box when a button is clicked
Public Sub NewPost()
picture as new picturebox
picture.Width = 208
picture.Height = 264
picture.Image = Form2.PictureBox1.Image
picture.Location = New Point(258, 60)
End Sub
The thing is it only generates 1 new picture box because I have to make a new variable each time I want to add a picturebox, and eachtime I have to have a new name. I know my question Is a bit confusing but help would be nice thanks
If you want to trap events for your dynamic PictureBoxes, then you'll have to abandon the WithEvents model and move to using AddHandler.
Here's a quick example where the name of the PictureBox is displayed when it is clicked. Note that I am not setting a Location since they are being added to a FlowLayoutPanel which takes care of the placement for you:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
NewPost()
End Sub
Public Sub NewPost()
Dim picture As New PictureBox
picture.Width = 208
picture.Height = 264
picture.BorderStyle = BorderStyle.FixedSingle
' ...etc...
Dim index As Integer = FlowLayoutPanel1.Controls.Count + 1
picture.Name = "pb" & index
AddHandler picture.Click, AddressOf picture_Click
FlowLayoutPanel1.Controls.Add(picture)
End Sub
Private Sub picture_Click(sender As Object, e As EventArgs)
Dim pb As PictureBox = DirectCast(sender, PictureBox)
Debug.Print(pb.Name)
End Sub
End Class
because I have to make a new variable each time
Not necessarily. You just want to keep a reference to the object. That reference doesn't need to be its own variable, it can just as easily be an element in a list. For example, suppose on your form you have a list of PictureBox objects as a class-level member:
Dim pictureBoxes As New List(Of PictureBox)()
Then in your method you can just add to that list:
Public Sub NewPost()
Dim pictureBox As New PictureBox
pictureBox.Width = 208
pictureBox.Height = 264
pictureBox.Image = Form2.PictureBox1.Image
pictureBox.Location = New Point(258, 60)
Me.pictureBoxes.Add(pictureBox)
End Sub
In this case the pictureBox variable is local to the NewPost method and gets re-created each time. But pictureBoxes is a class-level member and keeps track of the growing list of PictureBox objects that you're creating.
You can use a for while loop to create n number of objects
You can use the existing ControlCollection
Public Function NewPost() As String
Dim picture As New PictureBox
'your code
picture.Name = "Pb" & Form2.Controls.OfType(Of PictureBox).Count
Form2.Controls.Add(picture)
Return picture.Name
End Function
then you can retrive it
DirectCast(Form2.Controls(NewPost), PictureBox).Image = Form2.PictureBox1.Image
'OR
DirectCast(Form2.Controls("Pb12"), PictureBox).Image = Form2.PictureBox1.Image

Is there a way to use timer ticks for multiple procedures?

I am currently coding a small animation. The animation starts off with a small circle moving across the screen, then the user click buttons and other small images move across the screen (I feel like describing the contents of the images, the purpose of the program, etc. would be tangential and irrelevant).
The way I am currently coding the animation is like this:
Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles Timer.Tick
Circle1.Left -= 10
If Counter = 16 Then
Timer.Enabled = False
Counter = 0
End If
Counter += 1
End Sub
However, the problem is that I need to use the timer to help animate the movement of multiple images. Other than creating multiple timers, is there a way of using the ticking of the timer in multiple subroutines?
You can use a list to hold all the controls you want to animate. Iterate the list in the timer event and modify the position of the controls. Here's an example how to do it.
Public Class Form1
' this list holds all controls to animate
Private controlsToAnimate As New List(Of Control)
Private random As New Random
Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
' this list holds all controls to remove
Dim controlsToRemove As New List(Of Control)
For i = 0 To controlsToAnimate.Count - 1
Dim control = controlsToAnimate(i)
If control.Left < 0 Then
' this control has reached the left edge, so put it in the list to remove
controlsToRemove.Add(control)
Else
' move the control to left
control.Left -= 10
End If
Next
' remove all controls that have reached the left edge
For Each control In controlsToRemove
controlsToAnimate.Remove(control)
control.Dispose()
Next
' for debug only, display the number of controls to animate
Me.Text = controlsToAnimate.Count()
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' create a new picturebox
Dim newControl As New PictureBox
With newControl
' load an image for the picturebox
.Image = Image.FromFile("D:\Pictures\abc.jpg")
' size of the picturebox
.Size = New Size(100, 100)
' picturebox appears at the right edge of the form,
' the vertical position is randomize
.Location = New Point(Me.Width - newControl.Width, random.Next(Me.Height - newControl.Height))
' stretch the image to fit the picturebox
.SizeMode = PictureBoxSizeMode.StretchImage
End With
' add the newly created control to list of controls to animate
controlsToAnimate.Add(newControl)
' add the newly created control to the form
Me.Controls.Add(newControl)
End Sub
End Class

Displaying winner's name in picture box

Below is code for a simple voting system I am coding.
Public Class Form1
Dim winner As String
Dim maxVotes As Integer
Dim votes() As String
Dim index As String
Dim candidates As String
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
If Not isValidInput(txtNewCandidate.Text) Then
Exit Sub
End If
lstCandidates.Items.Add(txtNewCandidate.Text)
txtNewCandidate.Clear()
txtNewCandidate.Focus()
ReDim Preserve votes(index)
index += 1
End Sub
Private Function isValidInput(ByRef firstName As String) As Boolean
If IsNumeric(txtNewCandidate.Text) Or txtNewCandidate.Text = "" Then
MsgBox("Please input a valid candidate name.")
txtNewCandidate.Focus()
Return False
Else
Return True
End If
End Function
Private Sub btnTally_Click(sender As Object, e As EventArgs) Handles btnTally.Click
lstTallies.Visible = True
lblTally.Visible = True
For i = 0 To lstCandidates.Items.Count - 1
lstTallies.Items.Add(lstCandidates.Items(i).ToString & " - " & votes(i))
Next
End Sub
Private Sub lstCandidates_DoubleClick(sender As Object, e As EventArgs) Handles lstCandidates.DoubleClick
If lstCandidates.SelectedIndex = -1 Then
MsgBox("Select a candidate by double-clicking")
End If
votes(lstCandidates.SelectedIndex) += 1
MsgBox("Vote Tallied")
End Sub
Private Sub pbxWinner_Click(sender As Object, e As EventArgs) Handles pbxWinner.Click
End Sub
End Class
The voter must double click on their choice of candidate in the first list box. The user then tallies the votes by clicking on a button and a second list box will appear with the votes per candidate.
Now I need to display the winner (or winners, if there is a tie) in a picture box, pbxWinner. I am not sure how to accomplish this. Any clues?
Here is what i am trying to do, though the code below doesn't work.
Private Function candidateWinner(ByRef winner As String) As Boolean
For i As Integer = 0 To lstCandidates.SelectedIndex - 1
If votes(i) > maxVotes Then
maxVotes += 1
End If
Next
g = pbxWinner.CreateGraphics
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(winner, New Font("Arial", 7, FontStyle.Regular), Brushes.DarkBlue, New PointF(0, 0))
Return True
End Function
Your code is actually working fine for an initial paint, but when the picture box image doesn't have its own bitmap set, a number of events can repaint its graphics behind the scenes(even as simple as minimizing/mazimizing the form, and a whole bunch of other ones), so in effect your text seems to never appear at all or disappear almost instantly when in reality it's probable getting repainted. To fix this, use a bitmap for the graphics object's reference, paint the bitmap's graphics, and then assign the bitmap to the picturebox's image property. This will make the image persistent...give this code a try in your candidateWinner function after the for loop:
Dim bmp As New Bitmap(pbxWinner.Width, pbxWinner.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(winner, New Font("arial", 7, FontStyle.Regular), Brushes.DarkBlue, 0, 0)
pbxWinner.Image = bmp
...If you still aren't seeing text, make sure the winner string has the correct value set, I tested this code and it showed my test string correctly
Edit for Comment:
That's because of the logic you're using to calculate the winner...you are just checking to see if the currently selected candidate's vote count is higher than maxVotes and then incrementing the max by 1. If you wanted to stick with that sort of logic for picking the winner, you would want to iterate through ALL of the candidates(not just those from index 0 to the currently selected one), and if their vote count is higher than the max, then set the max EQUAL to their vote count. Then the next candidate in the loop will have their count checked against the previous max. However, tracking the winner could be done a lot easier if you just use a dictionary since you are allowing candidates to be added, and you must change your "winner" logic to actually check who has the most votes out of everyone entered. A bare bones example of that would look like this:
Dim dctTally As Dictionary(Of String, Integer)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
dctTally = New Dictionary(Of String, Integer)
End Sub
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
dctTally.Add(txtNewCandidate.Text, 0)
lstCandidates.Items.Add(txtNewCandidate.Text)
End Sub
Private Sub lstCandidates_DoubleClick(sender As Object, e As EventArgs) Handles lstCandidates.DoubleClick
dctTally(lstCandidates.text) += 1
End Sub
Private Sub pbxWinner_Click(sender As Object, e As EventArgs) Handles pbxWinner.Click
Dim winner = dctTally.Aggregate(Function(l, r) If(l.Value > r.Value, l, r)).Key
Dim bmp As New Bitmap(pbxWinner.Width, pbxWinner.Height)
Dim g As Graphics = Graphics.FromImage(bmp)
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(winner, New Font("arial", 7, FontStyle.Regular), Brushes.DarkBlue, 0, 0)
pbxWinner.Image = bmp
End Sub
This way, the program allows as many names as you want to be added to the candidates list, and will add a vote count to their name each time their name is double-clicked on. Then, when your winner pixturebox is clicked, it will find the dictionary with the highest vote count and display their name in the winner-box.
You can try this to draw the winners:
Private Sub candidateWinner()
Dim y As Single = 0
maxVotes = votes.Select(Function(x) Convert.ToInt32(x)).Max()
For i = 0 To UBound(votes)
If votes(i) = maxVotes.ToString() Then
g = pbxWinner.CreateGraphics
g.TranslateTransform(10.0F, 0.0F)
g.DrawString(lstCandidates.Items(i).ToString(), New Font("Arial", 7, FontStyle.Regular), Brushes.DarkBlue, New PointF(0, y))
y += 10
g.Dispose()
End If
Next
End Sub