Visual Basic Click Event Adding Scores together - arrays

Not 100% sure how to do this, mainly because I am new to programming here!
I have created a table which is populated with random numbers from an array, when the user clicks on one of the buttons the number needs to be added onto their score. eg, when a user clicks 10 and 15, their score will be 25. Once the user has clicked on the button, the button needs to change colour To AliceBlue (just a random colour). Any advice / examples?
This code below makes the table which is used within the game,
Let me know what you think!
Dim RandomNumbers = Enumerable.Range(0, 100).ToList()
Dim RandomNumber As New Random()
For Me.TableColunm = 0 To 4 Step 1
For Me.TableRow = 0 To 4 Step 1
Dim TemporaryNumber = RandomNumbers(RandomNumber.Next(0, RandomNumbers.Count))
RandomNumbers.Remove(CInt(TemporaryNumber))
TableButtons = New Button()
With TableButtons
.Name = "TextBox" & TableColunm.ToString & TableRow.ToString
.Text = TemporaryNumber.ToString
.Width = CInt(Me.Width / 4)
.Left = CInt(TableColunm * (Me.Width / 4))
.Top = TableRow * .Height
.Tag = TemporaryNumber
AddHandler TableButtons.Click, AddressOf TableClickEvent
End With
GameScreen.Controls.Add(TableButtons)
Next TableRow
Next TableColunm
Catch ex As Exception
MsgBox(ex.StackTrace & vbCrLf & "index1= " & TableColunm & vbCrLf & "index2= " & TableRow)
End Try
and
Public Sub TableClickEvent(sender As Object, e As EventArgs)
CType(sender, Button).BackColor = Color.BlueViolet
OverAllScoreInteger += CInt(CType(sender, Button).Tag)
End Sub
I also have to parse the score into a text box called 'UserScoreBox' the form is on 'GameScreen'

You add an eventhandler to a control by using the AddHandler statement and providing the sub that handles the event.
Private Sub Clickhandler(sender As Object, e As EventArgs)
CType(sender, Button).BackColor = Color.AliceBlue
End Sub
Sender is basically the source that initiated the event. In this case the button you clicked.
To make the button raise the event, add this to the code where you create the Buttons:
Addhandler TableButtons.Click, AddressOf Clickhandler
To add the scores you can for example place the index of the table row the button represents to the .Tag property of the button. That way you can, in the event handler, retrieve the row of the sender and add the values.
Edit: Adding the number:
On button creation, save the number in the tag (You could also just use the .Text, but doesn't really matter, it's one conversion less this way):
With TableButtons
.Tag = Temporarynumber
And in the handler unpack the object again:
Overallscore += CInt(CType(sender, button).Tag)

Related

Datagridviewcell Tooltip doesn't display after modifying image of any cell

In my winforms application, I loop through the cells of a datagridview and add a tooltip for specific cells based on values in other columns. I do this in the cellformatting event handler, and it worked perfectly. Here is the code:
Private Sub dgvResults_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles dgvResults.CellFormatting
Select Case dgvResults.Columns(e.ColumnIndex).Name
Case "TradeInValue"
DirectCast(dgvResults.Rows(e.RowIndex).Cells("TradeInValue"), DataGridViewTextBoxCell).ToolTipText = "Min = " & CDec(dgvResults.Item("BB_Min", e.RowIndex).FormattedValue).ToString("$#####.##") & ", Max = " & CDec(dgvResults.Item("BB_Max", e.RowIndex).FormattedValue).ToString("$#####.##")
If Not IsNothing(dgvResults.Item("SelectedTrimIndex", e.RowIndex).FormattedValue) AndAlso dgvResults.Item("SelectedTrimIndex", e.RowIndex).FormattedValue.ToString.Trim.Length > 0 AndAlso CInt(dgvResults.Item("SelectedTrimIndex", e.RowIndex).FormattedValue.ToString) <> -1 Then
If dgvResults.Item("ValueList", e.RowIndex).FormattedValue.ToString.Length > 0 Then
Dim ValueParts() As String = dgvResults.Item("ValueList", e.RowIndex).FormattedValue.ToString.Split("|")
'Dim selectedTrim As String = ValueParts(dgvResults.Item("SelectedTrimIndex", e.RowIndex).FormattedValue)
End If
End If
End Select
End Sub
Then, I added code in the cellpainting event handler to hide specific images, again based on values in the datagridview. Here is that code.
Private Sub dgvResults_CellPainting(sender As Object, e As DataGridViewCellPaintingEventArgs) Handles dgvResults.CellPainting
If e.ColumnIndex >= 0 AndAlso e.RowIndex >= 0 Then
Select Case dgvResults.Columns(e.ColumnIndex).Name
Case "VIN_Pic"
If dgvResults.Rows(e.RowIndex).Cells("VIN_Value").FormattedValue = "" Then
DirectCast(dgvResults.Item(e.ColumnIndex, e.RowIndex), DataGridViewImageCell).Value = New Bitmap(1, 1)
End If
Case "EmailDisplayImage"
If dgvResults.Rows(e.RowIndex).Cells("ListingContactEmail").FormattedValue = "" Then
DirectCast(dgvResults.Item(e.ColumnIndex, e.RowIndex), DataGridViewImageCell).Value = New Bitmap(1, 1)
End If
End Select
End If
End Sub
When this code as added, the tooltips no longer display. The CellToolTipTextNeeded event fires, and it shows the correct text in the argument, but it never displays. Comment out the lines that assign a new image to the datagridviewimagecells, and the tooltips start displaying again.
I hope this explanation was sufficient. Any ideas?
With the below code, you will run into memory and GDI object leaks very easily as a new Bitmap instance is created every time the cell is painted. Also this is causing your ToolTip to be not displayed.
DirectCast(dgvResults.Item(e.ColumnIndex, e.RowIndex), DataGridViewImageCell).Value = New Bitmap(1, 1)
Define the empty bitmap in class level or add as embedded resource and use it.
Dim emptyBitmap As New Bitmap(1, 1);
DirectCast(dgvResults.Item(e.ColumnIndex, e.RowIndex), DataGridViewImageCell).Value = emptyBitmap

create array of existing buttons vb 2013

I used to program in VB6 and am trying to write the same program in VB 2013. In this program I use an array of 49 buttons that all do the same thing when you click on them. I have figured out have to do the click function to a point:
Private Sub Button_Click(sender As Object, e As EventArgs) Handles Button9.Click, Button10.Click, Button11.Click, Button12.Click, Button13.Click, Button16.Click, Button17.Click, Button18.Click, Button19.Click, Button20.Click
...
End Sub
What I am trying to do is simplify the code down to using an array so I can just pass on the index. One other person asked the same question in 2010 and the best answer was:
Button[] array = { firstButton, secondButton };
That would work but I want something with less typing. I also tried the following with failure:
One
Button[] buttons = this.Controls.OfType<Button>().ToArray();
Two
For i = 1 To 100
Dim btns() As Button = Controls.Find("Button" & i, True)
Dim btn As Button
If btns IsNot Nothing Then
btn = btns(0)
'If buttons Is Nothing Then
' ReDim buttons(0)
'Else
' ReDim Preserve buttons(buttons.Length)
'End If
'buttons(UBound(buttons)) = btn
btn.Text = i - 1 'here you can change whatever you want
End If
Next
Three
Dim buttons() As Button
buttons = Nothing
For Each b As Button In Me.Controls
If buttons Is Nothing Then
ReDim buttons(0)
Else
ReDim Preserve buttons(buttons.Length)
End If
buttons(UBound(buttons)) = b
Next
I just can't get it to accept the existing buttons into an array. I hope someone can help.
If your Buttons are nested inside container controls (e.g. a GroupBox) then you will need to perform a recursive search for all buttons. Maybe something like this (totally unoptimized)...
Private Function FindAllButtons(root As Control) As List(Of Button)
Dim result As List(Of Button) = New List(Of Button)()
For Each c As Control In root.Controls
If TypeOf c Is Button Then
result.Add(DirectCast(c, Button))
ElseIf c.HasChildren Then
result.AddRange(FindAllButtons(c))
End If
Next
Return result
End Function
Then just call that in your Form:
Dim allButtons as List(Of Button) = FindAllButtons(Me)
' Add common Click handler
For Each b As Button In allButtons
AddHandler b.Click, AddressOf Button_Click
Next
Update Just for fun, here's a generic version to find other types of control.
Private Function FindAllControls(Of T As Control)(root As Control) As List(Of T)
Dim result As List(Of T) = New List(Of T)()
For Each c As Control In root.Controls
If TypeOf c Is T Then
result.Add(DirectCast(c, T))
ElseIf c.HasChildren Then
result.AddRange(FindAllControls(Of T)(c))
End If
Next
Return result
End Function
You can use that like:
Dim allButtons As List(Of Button) = FindAllControls(Of Button)(Me)
Dim allTextBoxes As List(Of TextBox) = FindAllControls(Of TextBox)(Me)
Option two will work, you just need to add the button found into a list. I suggest you add your buttons into a List(Of ) instead of an array. You can always convert the list into an array if you really need to.
Dim buttonList As New List(Of Button)
For i As Integer = 1 To 100
Dim btns() As Control = Controls.Find("Button" & i, True)
If btns IsNot Nothing AndAlso btns.Length > 0 Then
buttonList.Add(CType(btns(0), Button))
End If
Next

How to respond to events for objects in an array

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.

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

FindControl not finding dynamcily added user control in wizard control

I have a wizard control in wich I am adding a user control containing a simple table with
some input fields based on users entry of how many children they have. ex: how many kids do you have so I add the user control ascx based on that loop
that goes into step 5 of my wizard wich is also in a masterpage.
I then use findcontrol to atttempt the get to those input boxes so i can save the data into my db, findcontrol allway comes up null, even though the user control in visable and recreated on page load after post back.
any help greatly appreciated.
find control button:
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim numbchildren As Integer = CInt(Howmanychildren.Text)
For i As Integer = 1 To numbchildren - 1
Dim textbox As TextBox = TryCast(Me.Wizard1.FindControl("WizardStep5").FindControl("Minor_1_Child_Name"), TextBox)
'Dim textbox2 As TextBox = TryCast(Me.Wizard1.FindControl("WizardStep5").FindControl("Howmanychildren"), TextBox)
If textbox IsNot Nothing Then
Response.Write("Found TextBox1 <br>")
Dim val As String = textbox.Text
Response.Write(val & "<br>")
Else
Response.Write("not found" & "<br>")
End If
' Insert into DB
'SaveValueToDatabase(val)
Next
End Sub
user control added function on dropdown :
Protected Sub Doyouhavechildren_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles Doyouhavechildren.SelectedIndexChanged
Dim numbchildren As Integer = CInt(Howmanychildren.Text)
Dim cnt As Integer = 1
'Panel1.Controls.Clear()
Select Case Doyouhavechildren.SelectedIndex
Case 0
ViewState.Add("Doyouhavechildren", numbchildren)
Do While cnt <= numbchildren
Dim uc As Web.UI.UserControl = DirectCast(Page.LoadControl("MinorChild.ascx"), Web.UI.UserControl)
uc.ID = "Minor_" + cnt.ToString()
Wizard1.ActiveStep.Controls.Add(uc)
cnt = cnt + 1
Loop
Exit Select
Case 1
Exit Select
End Select
End Sub
user control:
<%# Control Language="VB" AutoEventWireup="false" CodeFile="MinorChild.ascx.vb" Inherits="MinorChild" %>
Name
Age
SS#
DOB
the find control works in the howmanychildren field that is static
I figured it out myself
basicly, you have to referance the container, thats what everyone everywhere else where saying but I kept ignoring the answer
the correct code is
Dim textbox As TextBox = TryCast(Me.Wizard1.FindControl("WizardStep5").FindControl("Minor_1").FindControl("Child_Name"), TextBox)
you have to referance the user control name first then search within it , even though the client source is disceptive.

Resources