Displaying winner's name in picture box - vb.net

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

Related

How to use properties of dynamically created picturebox in 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

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 do I fix this multidimensional array?

So I need to make a program that displays the monthly sales and totals of three different areas of a company when I click a button. I've added this code, but can't seem to get it right. Can someone advise me on how to fix it. Also, my headings "province, Percentage, Contribution etc" does not display in the list box when the form is loaded.
So basically the values in my .txt files are as follows:
1,Kwazulu Natal,44,120000
1,Gauteng,33,900000
1,Western Cape,23,65000
2,Kwazulu Natal,56,190000
2,Gauteng,25,85000
2,Western Cape,19,64000
3,Kwazulu Natal,54,175000
3,Gauteng,25,80000
3,Western Cape,21,71000
4,Kwazulu Natal,55,188000
4,Gauteng,25,83000
4,Western Cape,20,67000
5,Kwazulu Natal,46,125000
5,Gauteng,31,87000
5,Western Cape,23,65000
6,Kwazulu Natal,53,163000
6,Gauteng,26,80000
6,Western Cape,21,64000
Now they are supposed to show underneath their headings per month (1 - 6). When I run my code, they do not show headings, just the names of the places. It does not give errors
Imports System.IO
Public Class FormMain
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
resultsBox.Items.Clear()
resultsBox.Columns.Add("Province", 100, HorizontalAlignment.Center)
resultsBox.Columns.Add("Percentage", 100, HorizontalAlignment.Center)
resultsBox.Columns.Add("Contribution", 100, HorizontalAlignment.Center)
resultsBox.Columns.Add("Total Cost", 100, HorizontalAlignment.Center)
End Sub
Private Sub ExitBtn_Click(sender As Object, e As EventArgs) Handles ExitBtn.Click
Me.Close()
End Sub
Private Sub ShowResultsBtn_Click(sender As Object, e As EventArgs) Handles ShowResultsBtn.Click
Dim salesReport As String = MonthlyCBox.Text
Dim filereader As New StreamReader("C:\Users\HP Notebook 15\Desktop\main.txt")
Dim details As Array
Dim provinceFound As String = " "
Dim percentageContribute As Integer = 0
Dim monthlySales As Integer = 0
Dim totalvalue As Integer = 0
While filereader.EndOfStream = False
details = filereader.ReadLine().Split(",")
Dim province As String = details(1)
Dim percentage As Decimal = details(2)
Dim monthlyammount As String = details(3)
Dim totalamm As String = details(3)
If details(0) = salesReport Then
resultsBox.Items.Add(New ListViewItem({province, percentage, FormatCurrency(monthlyammount), FormatCurrency(totalamm)}))
End If
End While
End Sub
End Class
I guess you are using ListView, Not List Box. If so, please add
resultsBox.View = View.Details, in load event. That should visible the header text.

Alternative Process

I have 2 buttons and a DataGridView with 2 Columns (0 & 1).
The 1st button transfers a randomized cell from the Column(1) to a TextBox. Then, it stores that Cell in variable (a), plus the cell that opposites it in variable (b).
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim rnd As New Random
Dim x As Integer = rnd.Next(0, Form1.DataGridView1.Rows.Count)
Dim y As Integer = 1
Dim a As String = Form1.DataGridView1.Rows(x).Cells(y).Value
Dim b As String = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
The 2nd button, however, is supposed to compare if another TextBox's text has the same string variable (b) has as Strings. Now, if so, then it has to display a certain message and so on...
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If TextBox4.Text = b Then '<<< ISSUE HERE!
MsgBox("Correct! ^_^")
ElseIf TextBox4.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub
The problem is that the variable (b) is surely not shared across the two "private" subs. And so, there is NOTHING to compare to in the 2nd button's sub! I presume that the solution here is to split the "randomization process" into a separate function, then execute it directly when the 1st button gets activated. Furthermore, that function's variables have to be SHARED somehow, and I certainly don't know how!
Thanks for Mr. Olivier, the code has been improved significantly! Yet, I still encounter a "wrong" comparison issue, somehow!
Dim RND As New Random
Dim x As Integer
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
Private Sub btnRoll_Click(sender As Object, e As EventArgs) Handles btnRoll.Click
x = RND.Next(0, Form1.DataGridView1.Rows.Count)
tbxRoll.Text = GetCell(x, 1)
End Sub
Private Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
If tbxSubmit.Text = GetCell(x, 0) Then
MsgBox("Correct! ^_^")
ElseIf tbxSubmit.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub</code>
Well, unbelievably, I read a guide about "comparison operations" in VB.net and tried out the first yet the most primal method to compare equality - which was to use .Equals() command - and worked like a charm! Thank God, everything works just fine now. ^_^
If tbxSubmit.Text.Equals(GetCell(x, 0)) Then
Alright now... This is going to sound weird! But, following Mr. Olivier's advise to investigate "debug" the code, I rapped the string I'm trying to compare with brackets and realized that it's been outputted after a break-line space! So, I used the following function to remove the "white-space" from both of the comparison strings! And it bloody worked! This time for sure, though. ^_^
Function RemoveWhitespace(fullString As String) As String
Return New String(fullString.Where(Function(x) Not Char.IsWhiteSpace(x)).ToArray())
End Function
If RemoveWhitespace(tbxSubmit.Text) = RemoveWhitespace(GetCell(x, 0)) Then
Turn the local variables into class fields.
Dim rnd As New Random
Dim x As Integer
Dim y As Integer
Dim a As String
Dim b As String
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
x = rnd.Next(0, Form1.DataGridView1.Rows.Count)
y = 1
a = Form1.DataGridView1.Rows(x).Cells(y).Value
b = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
These fields can now be accessed from every Sub, Function and Property.
Of course Button3_Click must be called before Button2_Click because the fields are initialized in the first method. If this is not the case then you should consider another approach.
Create a function for the Cell access
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) _
As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
And then compare
If TextBox4.Text = GetCell(x, y - 1) Then
...
And don't store the values in a and b anymore. If y is always 1 then use the numbers directly.
If TextBox4.Text = GetCell(x, 0) Then
...
One more thing: give speaking names to your buttons in the properties grid before creating the Click event handlers (like e.g. btnRandomize). Then you will get speaking names for those routines as well (e.g. btnRandomize_Click).
See:
- VB.NET Class Examples
- Visual Basic .NET/Classes: Fields

Visual Basic Avg. Temp Calculator

Ok, so I am super new to visual basic and was not planning on taking it as a class either until they made it a requirement for me to get my technicians certificate at my community college. Literally understand the chapters I have read so far to a T, and then first homework assignment comes up and for the past few days I have been scratching my head as to why on earth it is not working. Here is what the Prof is asking.
Write a program that calculates average daily temperatures and summary statistics. The user will be prompted to enter a Fahrenheit temperature as a value with one decimal place and to select the name of the technician entering the temperature. The user will have the option to see the Celsius equivalent of the entered Fahrenheit temperature. The program will display the average temperature of all entered temperatures. The results are displayed when the user hits ENTER, uses the access key or clicks the Calculate button. The user will be given the opportunity to enter another temperature when the user hits ESC (Clear is the Cancel Button), uses the access key or clicks the Clear button. The user will exit the program by clicking the Exit button or using its access key. The Exit button will also display the summary statistics: 1) the number of temperatures entered by each technician and 2) the average temperature of all entered temperatures. Calculations should only be done if a numeric value between 32.0 and 80.0 (inclusive) degrees for temperature is entered and a technician has been selected.
The graphical side is a breeze with dragging and dropping, then naming the labels, radio buttons, etc... But now that I have assembled my code. Nothing is working. I'm frustrated, confused, and let down. I had no idea this class would be this hard. Here is what I came up with so far code wise. No error messages at all, just not getting any output pretty much.
Option Strict On
Option Strict On
Public Class Form1
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
'Clear App
txtTemp.Clear()
lblAverageTemp.Text = String.Empty
lblCelsius.Text = String.Empty
radDave.Checked = False
radJoe.Checked = False
chkCelsiusTemp.Checked = False
'New Temp Focus
txtTemp.Focus()
End Sub
Private Sub btnClose_Click(sender As Object, e As EventArgs) Handles btnClose.Click
'End app with display
MessageBox.Show("Dave entered intEntriesDave entries." & ControlChars.CrLf & "Joe entered intEntriesJoe entries." & _
ControlChars.CrLf & "The average temperature is _.", "Status")
Me.Close()
End Sub
Public Sub chkCelsiusTemp_CheckedChanged(sender As Object, e As EventArgs) Handles chkCelsiusTemp.CheckedChanged
'Convert entered Fahrenheit temp to Celsius
Dim dblCelsius As Double
dblCelsius = (CDbl(txtTemp.Text) - 32) * 5 / 9
lblCelsius.Text = CStr(dblCelsius)
End Sub
Private Sub btnCalculate_Click(sender As Object, e As EventArgs) Handles btnCalculate.Click
Dim intEntriesDave As Integer = 0
Dim intEntriesJoe As Integer = 0
If radDave.Checked = True Then
intEntriesDave = +1
End If
If radJoe.Checked = True Then
intEntriesJoe = +1
End If
Dim dblAvg As Double
dblAvg = CDbl(txtTemp.Text) / intEntriesDave + intEntriesJoe
lblAverageTemp.Text = CStr(dblAvg)
End Sub
End Class
Hope I figure this out or I can get some help with it. I procrastinated of course, like the idiot I am, and it is due in 11 hours :\
Thanks in advance!
I would use a dictionary to store names along with temperatures.
Place a numericupdown control on your form for the temperature input (numTemp) and a textbox for names tbName and a label lblCelsius for output:
Public Class Form1
Dim temps As New Dictionary(Of String, List(Of Double))
Private Sub btnEnter_Click(sender As Object, e As EventArgs) Handles btnEnter.Click
If numTemp.Value < 32 OrElse numTemp.Value > 80 OrElse tbName.Text = "" Then Exit Sub 'Invalid input
If temps.ContainsKey(tbName.Text) = False Then 'Name is new, create a new list entry
temps.Add(tbName.Text, New List(Of Double))
End If
temps(tbName.Text).Add(numTemp.Value) 'Append the entered temperature
lblCelsius.Text = "In celsius: " & CStr(numTemp.Value - 32) * 5 / 9 'Output the Celsius value
End Sub
Private Sub btnStats_Click(sender As Object, e As EventArgs) Handles btnStats.Click
Dim sb As New System.Text.StringBuilder 'Create the output
For Each k As String In temps.Keys
sb.AppendLine(k & ": " & temps(k).Average)
Next
lblCelsius.Text = sb.ToString
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
temps.Clear() 'Clear the database
End Sub
End Class
Basically everytime you click btnEnter you check your dictionary if the name already entered a value. If not a new entry is created with a new list and the new temperature is just added to the list.
Creating the output is then straightforward with the .Average method of the list.