If I click the calculate button the program crashes? - vb.net

Just for context;
I need to calculate the average of 5 numbers located in 5 textboxes.
Nummer means number
Gemiddelde means average
and
Bereken means calculate
What is causing it to crash?
Private Sub butBereken_Click(sender As Object, e As EventArgs) Handles butBereken.Click
'Variabelen'
Dim nummer1 As Decimal = txtNummer1.Text
Dim nummer2 As Decimal = txtNummer2.Text
Dim nummer3 As Decimal = txtNummer3.Text
Dim nummer4 As Decimal = txtNummer4.Text
Dim nummer5 As Decimal = txtNummer5.Text
Dim somNummers As Decimal = nummer1 + nummer2 + nummer3 + nummer4 + nummer5
Dim Gemiddelde As String = (somNummers) / 5
lblGemiddelde.Text = Gemiddelde
If Gemiddelde < 5.5 Then
lblGemiddelde.Text = Gemiddelde + " Dit is onvoldoende"
End If
If nummer1 = "" Or nummer2 = "" Or nummer3 = "" Or
nummer4 = "" Or nummer5 = "" Then
butBereken.Enabled = False
MessageBox.Show("your mom")
Else
butBereken.Enabled = True
End If
End Sub

I don't see what would crash the program but check to that the TextBoxes have values before assigning them to numeric variables. A Decimal value will never = "".
Private Sub butBereken_Click(sender As Object, e As EventArgs) Handles butBereken.Click 'Variabelen'
If Not IsNumeric(txtNummer1.Text) Or _
Not IsNumeric(txtNummer2.Text) Or _
Not IsNumeric(txtNummer3.Text) Or _
Not IsNumeric(txtNummer4.Text) Or _
Not IsNumeric(txtNummer5.Text) Then
MessageBox.Show ("your mom wants you to fill in all the number boxes")
Exit Sub
End If
Dim nummer1 As Decimal = CDec(txtNummer1.Text)
Dim nummer2 As Decimal = CDec(txtNummer2.Text)
Dim nummer3 As Decimal = CDec(txtNummer3.Text)
Dim nummer4 As Decimal = CDec(txtNummer4.Text)
Dim nummer5 As Decimal = CDec(txtNummer5.Text)
Dim somNummers As Decimal = nummer1 + nummer2 + nummer3 + nummer4 + nummer5
Dim Gemiddelde As String = (somNummers) / 5
lblGemiddelde.Text = Gemiddelde
If Gemiddelde < 5.5 Then
lblGemiddelde.Text = Gemiddelde + "Dit is onvoldoende"
End If
If nummer1 = 0 Or nummer2 = 0 Or nummer3 = 0 Or nummer4 = 0 Or nummer5 = 0 Then
butBereken.Enabled = False
MessageBox.Show ("your mom")
Else
butBereken.Enabled = True
End If
End Sub
If this doesn't work I would consider setting breakpoints in the could to determine what line is causing the crash.
If that doesn't work consider adding this line to the form's initialization:
butBereken.Caption = "Warning: Do not Click!"

Assuming the user populated all the textboxes with numeric only data, (and you have checked this) try replacing these lines in your code with this code
Dim nummer1 As Decimal = txtNummer1.Text
Dim nummer2 As Decimal = txtNummer2.Text
Dim nummer3 As Decimal = txtNummer3.Text
Dim nummer4 As Decimal = txtNummer4.Text
Dim nummer5 As Decimal = txtNummer5.Text
Dim somNummers As Decimal = nummer1 + nummer2 + nummer3 + nummer4 + nummer5
Dim Gemiddelde As Decimal = somNummers / 5
lblGemiddelde.Text = Gemiddelde.ToString("##0.0")

I'd do something more like:
Private Sub butBereken_Click(sender As Object, e As EventArgs) Handles butBereken.Click
Dim TBs() As TextBox = {txtNummer1, txtNummer2, txtNummer3, txtNummer4, txtNummer5}
Dim inputs() As String = TBs.Select(Function(x) x.Text).ToArray()
Dim values() As Decimal
Try
values = Array.ConvertAll(inputs, Function(s) Decimal.Parse(s))
Dim Gemiddelde As String = values.Average()
lblGemiddelde.Text = Gemiddelde & If(Gemiddelde < 5.5, " Dit is onvoldoende", "")
Catch ex As Exception
MessageBox.Show("your mom")
End Try
End Sub
I prefer this approach as it doesn't require repetitive lines of code, manually converting each TextBox to a Decimal. Since the TextBoxes are in an Array, we could also add another TextBox to the form and then add that name to the end of the Array. The rest of the code would not need to change at all; it would still just work as is.
From the Array of TextBox, we use a LINQ statement to extract the Text from each TextBox and add it to an Array of String called "inputs". From there, we convert every single String to a Decimal using Array.ConvertAll(), again avoiding repetitive code. If any of the input values is not a valid Decimal then an Exception will be thrown and we'll jump the the Catch block where the not so well written error message is displayed.
If there are no exceptions, then all String inputs were successfully converted to Decimals and stored in the "values" Array. Next we simply use the LINQ function Average() to get the average of all the values.
Lastly we display the computed average in the Label, adding the "Dit is onvoldoende" message if approapriate. The If() function used in this line is simply a shorthand version of a longer If...Else...End If statement.
In your original attempt, it looks like you wanted to disable the button if any of the values are blank (or maybe if they are invalid decimals?):
If nummer1 = "" Or nummer2 = "" Or nummer3 = "" Or nummer4 = "" Or nummer5 = "" Then
butBereken.Enabled = False
MessageBox.Show("your mom")
Else
butBereken.Enabled = True
End If
This makes no sense as if you disable the button, how would it get turned back on so that user could click it again?
A different approach would be to handle the TextChanged() event of all the TextBoxes and simply update your Label with the average in real-time whenever one of the TextBoxes is changed:
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
UpdateAverage()
End Sub
Private Sub txtAll_TextChanged(sender As Object, e As EventArgs) Handles txtNummer5.TextChanged, txtNummer4.TextChanged, txtNummer3.TextChanged, txtNummer2.TextChanged, txtNummer1.TextChanged
UpdateAverage()
End Sub
Private Sub UpdateAverage()
Dim TBs() As TextBox = {txtNummer1, txtNummer2, txtNummer3, txtNummer4, txtNummer5}
Dim inputs() As String = TBs.Select(Function(x) x.Text).ToArray()
Try
Dim values() As Decimal = Array.ConvertAll(inputs, Function(s) Decimal.Parse(s))
Dim average As Decimal = values.Average
lblGemiddelde.Text = average & If(average < 5.5, " Dit is onvoldoende", "")
Catch ex As Exception
lblGemiddelde.Text = "{ Invalid Input }"
End Try
End Sub
End Class
Sample run:

Related

How to create a Loop to push Values to different TextBox with Similar Labels names and Change their text?

I am new to this VB. I'm building an application where I need to fill some 48 text boxes with 4 sets of similar names like
L1onHHxx
L1onMMxx
L1offHHxx
L1offMMxx
Where xx is a number from 1 to 24 for each label.
What I'm trying to do is calculate some values based on the user input and fill the text boxes with results.
Private Async Sub Line1Calc_Click(sender As Object, e As EventArgs) Handles Line1Calc.Click
Dim Cycle_Time As Integer
Dim Cycle_Count As Integer
Dim srtHH As Integer
Dim srtMM As Integer
Dim stpHH As Integer
Dim stpMM As Integer
Dim inDelay As Integer
Dim i As Integer
Dim lineONHH As New Label
Dim lineONMM As New Label
Dim lineOFFHH As New Label
Dim lineOFFMM As New Label
'Dim controls = GetAllTextBoxes(Me)
'Line1Tab
Cycle_Time = CInt(L1Time.Text)
Cycle_Count = CInt(L1Count.Text)
srtHH = CInt(L1ONHH.Text)
srtMM = CInt(L1ONMM.Text)
stpHH = CInt(L1OFFHH.Text)
stpMM = CInt(L1OFFMM.Text)
inDelay = (24 / CInt(Cycle_Count))
L1onhh1.Text = srtHH
L1onhh1.Text = srtHH
L1offhh1.Text = stpHH
L1offmm1.Text = stpMM
For i = 2 To (Cycle_Count)
srtHH += inDelay
stpHH += inDelay
lineONHH.Name = "L1onhh" & i.ToString()
lineONMM.Name = "L1onmm" & i.ToString()
lineOFFHH.Name = "L1offhh" & i.ToString()
lineOFFMM.Name = "L1offmm" & i.ToString()
lineONHH.Text = srtHH
lineONMM.Text = srtMM
lineOFFHH.Text = stpHH
lineOFFMM.Text = stpMM
' To Check if the labels name are correct
Box1.Text = lineONHH.Name
Box2.Text = lineONMM.Name
Box3.Text = lineOFFHH.Name
Box4.Text = lineOFFMM.Name
Await Task.Delay(1000)
Next
End Sub
Here when I pass the value of the New label to Box 1,2,3 & 4 for test purposes they are correct but the values don't appear on the respective text boxes.
Please can anyone point me in the right direction of what I'm doing wrong?
This should get you close, with a few assumptions made.
It assumes you have constant textbox naming pattern.
Assumes you want hour and minute in string.
Switch that structure to a DateTime if you want it in that format.
'class to hold all your time value entries
Private Class TimeValue
Public Property HourValue As String
Public Property MinValue As String
End Class
'class for each control time slow and its associated timevalues
Private Class ControlTime
Public Property TimeSlot As String
Public Property OnValue As TimeValue
Public Property OffValue As TimeValue
End Class
'method to set control values
Private Function SetControlValus(controlTimeItem As ControlTime) As Boolean
'find the control
Dim OnHourTextBox As TextBox = DirectCast(Me.Controls.Find(String.Concat("L1onHH", controlTimeItem.TimeSlot), False)(0), TextBox)
OnHourTextBox.Text = controlTimeItem.OnValue.HourValue
Dim OnMinTextBox As TextBox = DirectCast(Me.Controls.Find(String.Concat("L1onMM", controlTimeItem.TimeSlot), False)(0), TextBox)
OnMinTextBox.Text = controlTimeItem.OnValue.MinValue
Dim OffHourTextBox As TextBox = DirectCast(Me.Controls.Find(String.Concat("L1offHH", controlTimeItem.TimeSlot), False)(0), TextBox)
OffHourTextBox.Text = controlTimeItem.OffValue.HourValue
Dim OffMinTextBox As TextBox = DirectCast(Me.Controls.Find(String.Concat("L1offMM", controlTimeItem.TimeSlot), False)(0), TextBox)
OffMinTextBox.Text = controlTimeItem.OffValue.MinValue
Return True
End Function
Private Sub Test()
'set up some results
Dim results As List(Of ControlTime) = New List(Of ControlTime)
results.Add(New ControlTime() With {.TimeSlot = "01",
.OnValue = New TimeValue() With {.HourValue = "08", .MinValue = "56"},
.OffValue = New TimeValue() With {.HourValue = "08", .MinValue = "58"}})
results.Add(New ControlTime() With {.TimeSlot = "02",
.OnValue = New TimeValue() With {.HourValue = "09", .MinValue = "14"},
.OffValue = New TimeValue() With {.HourValue = "09", .MinValue = "29"}})
For Each controlTimeItem In results
SetControlValus(controlTimeItem)
Next
End Sub
Private Sub TestControlTimeButton_Click(sender As Object, e As EventArgs) Handles TestControlTimeButton.Click
Try
Test()
Catch ex As Exception
MessageBox.Show(String.Concat("An error occurred: ", ex.Message))
End Try
End Sub

How to debug a cast execption in vb.net?

I am getting a cast exception and I have re-written this code a large number of times. I am getting the exception on the following line:
If (CInt(hHurricaneYear) < CInt(_strYears(hAverage))) Then
And I am only getting results in the lblNumberOfHurricans. the other two labels are not showing any results. I thought I was getting it when the cast exception showed up.
Can anyone suggest how to get the results and stop the exception?
Here is what I have so far (well at least the last try).
Option Strict On
Public Class frmHurricaneStatistics
' Class level Private variables.
Public Shared _intSizeOfArray As Integer = 20
Private _strYears(_intSizeOfArray) As String
Private _intNumberOfHurricans(_intSizeOfArray) As Integer
Private Sub frmHurricaneStatistics_Load(sender As Object, e As EventArgs
) Handles MyBase.Load
' This load event reads the inventory text file and fills
' the ComboBox object with the Hurricane Statistics.
' Initialize an instace of the streamreader object and declare variables.
Dim objReader As IO.StreamReader
Dim strHurricaneStatistics As String = "Hurricanes.txt"
Dim intCount As Integer = 0
Dim intFill As Integer
Dim strFileError As String = "The file is not available. Please restart the
application when the file is available."
' Verify the Hurricane.txt file exists.
If IO.File.Exists(strHurricaneStatistics) Then
objReader = IO.File.OpenText(strHurricaneStatistics)
' Read the file line by line until the file is completed.
Do While objReader.Peek <> -1
_strYears(intCount) = objReader.ReadLine()
_intNumberOfHurricans(intCount) = Convert.ToInt32(objReader.ReadLine())
intCount += 1
Loop
objReader.Close()
' The ComboBox objext is filled with the Years for Hurricanes.
For intFill = 0 To (_strYears.Length - 1)
cmbYears.Items.Add(_strYears(intFill))
Next
Else
MsgBox(strFileError, , "Error")
Close()
' If ComboBox is filled then enable the Display Statistics button.
'btnDisplayStatistics.Enabled = True
End If
End Sub
Private Sub btnDisplayStatistics_Click(sender As Object, e As EventArgs
) Handles btnDisplayStatistics.Click
' This click event calls the sub procedures for the selected years and
' the number of hurricans in that year.
Dim intSelectedYear As Integer
Dim strMissingSelection As String = "Missing Selection"
Dim strSelectAYearError As String = "Please Select a Year"
' If the ComboBox object has a selection, Display Statistics.
If cmbYears.SelectedIndex >= 0 Then
intSelectedYear = cmbYears.SelectedIndex
Else
MsgBox(strSelectAYearError, , strMissingSelection)
End If
Private Sub btnDisplayStatistics_Click(sender As Object, e As EventArgs
) Handles btnDisplayStatistics.Click
' This click event calls the sub procedures for the selected years and
' the number of hurricans in that year.
Dim intSelectedYear As Integer
Dim strMissingSelection As String = "Missing Selection"
Dim strSelectAYearError As String = "Please Select a Year"
' If the ComboBox object has a selection, call the Display Statistics procedure.
If cmbYears.SelectedIndex >= 0 Then
intSelectedYear = cmbYears.SelectedIndex
Else
MsgBox(strSelectAYearError, , strMissingSelection)
End If
' This procedure MakeLabelsVisible Is called to display the labels
' And the results.
MakeLabelsVisible()
Dim hHurricaneAverage As Integer
Dim hHurricaneYear As Integer = 0
For hAverage As Integer = 0 To _strYears.Length - 1
If (CInt(hHurricaneYear) < CInt(_strYears(hAverage))) Then
hHurricaneYear = CInt(CType(CInt(_strYears(hAverage)), String))
End If
hHurricaneAverage = hHurricaneAverage + CInt((_strYears.ToString))
hHurricaneAverage = CInt(hHurricaneAverage / _strYears.Length)
Next
' Display the statistics for the Storm Average in the selected Year
' and the most active year within the range of year.
lblNumberOfHurricanes.Text = "The Number of Hurricanes in the Year " &
_strYears(intSelectedYear) & " is " & _intNumberOfHurricans(intSelectedYear).ToString() & "."
lblAvergeNumberHurricanes.Text = "The Average Number of Storms was " &
hHurricaneAverage & " Hurricanes."
Dim intSizeOfArray As Integer = Nothing
lblMostStorms.Text = "The Year "(CInt(_strYears(CInt(hHurricaneYear.ToString())) & "
Had The Most Storms Between " & (_strYears(0) & _strYears(20).ToString)))
End Sub
Option strict on
Your error lies in that you are trying to convert an entire string array into an integer:
hHurricaneAverage = hHurricaneAverage + CInt((_strYears.ToString))
You will need to call the index of _strYears:
hHurricaneAverage = hHurricaneAverage + CInt((_strYears(hAverage).ToString))
This will also explain why the other labels do not update, because hHurricanAverage never gets calculated.

Displaying Input into textbox

I am trying to display a calculation into a TextBox, but having trouble with getting it to show. I want it to show once all input fields are true.
Public Class VehicleAudit
Private Sub Calculate()
Dim validMiles As Boolean = False
Dim validPercent As Boolean = False
Dim validAvg As Boolean = False
Dim inputtedMiles As Double
Dim inputtedPercent As Double
Dim inputtedAvgCost As Double
Dim servTruck As Integer
Try
inputtedMiles = Double.Parse(txtMilesDriven.Text)
inputtedPercent = Double.Parse(txtPercent.Text)
inputtedAvgCost = Double.Parse(txtAvgCost.Text)
Catch ex As FormatException
MessageBox.Show("Please enter all values and try again")
Return
End Try
Dim cal As String = FormatCurrency(Convert.ToString(inputtedAvgCost * inputtedMiles * (1.0 + inputtedPercent))) + " dollars."
ValidateBoxes(inputtedMiles, 0, 10000, "Miles must range from 0-10000.", validMiles)
ValidateBoxes(inputtedPercent, 0.1, 0.5, "Please enter percent from .10 to .50", validPercent)
ValidateBoxes(inputtedAvgCost, 0.25, 0.75, " Please enter Average cost from .25 to .75", validAvg)
If (validAvg And validMiles And validPercent) Then
Dim totalCost As Double
If boxVehicleSelect.SelectedIndex = 9 Then
servTruck = inputtedMiles / 100 'this way we lose precision using the integer, so values below 100s are dropped.
totalCost = servTruck * 15.46
Else
totalCost = inputtedAvgCost * inputtedMiles * (1.0 + inputtedPercent)
End If
End If
End Sub
Private Sub txtTotalCost_TextChanged(ByVal Calculate As String, e As EventArgs) Handles txtTotalCost.TextChanged
End Sub
You appear to already have a block that runs when all three values are "valid". Simply output that value at the bottom of it:
If (validAvg And validMiles And validPercent) Then
Dim totalCost As Double
If boxVehicleSelect.SelectedIndex = 9 Then
servTruck = inputtedMiles / 100 'this way we lose precision using the integer, so values below 100s are dropped.
totalCost = servTruck * 15.46
Else
totalCost = inputtedAvgCost * inputtedMiles * (1.0 + inputtedPercent)
End If
' Output the computed "totalCost" some where.
' Here I'm using a Textbox called "txtTotalCost":
txtTotalCost.Text = totalCost.ToString()
End If
Edit...
Also call your Calculate() method whenever one of your textboxes changes:
Private Sub TextChanged(sender As Object, e As EventArgs) Handles txtMilesDriven.TextChanged, txtAvgCost.TextChanged, txtPercent.TextChanged
Calculate()
End Sub
Note how all three textboxes are listed after the handles keyword.

Visual Basic Confusion

I have been required to create a program that asks me to find the maximum value of one particular array. I am using multiple forms in this project and have used a user-defined data type and created multiple array under it. There is a first form that is related to this, which defines my defined data type is gStudentRecord and the arrays that define it are last name, Id, and GPA. This second form is where I write all of the code to display what I want. My question is how to get the Max GPA out of that array. I'm sorry if this isn't in very good format, this is the first time I've used Stackoverflow
Public Class frmSecond
Private Sub frmSecond_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim Ctr As Integer
Dim Line As String
lstDisplay.Items.Clear()
lstDisplay.Items.Add("Name".PadRight(25) & "ID".PadRight(16) & "GPA".PadRight(20) & "Out of state".PadRight(10))
For Ctr = 0 To gIndex Step 1
Line = gCourseRoster(Ctr).LastName.PadRight(20) & gCourseRoster(Ctr).ID.PadRight(15) & gCourseRoster(Ctr).GPA.ToString.PadRight(15) & gCourseRoster(Ctr).OutOfState.ToString().PadLeft(5)
lstDisplay.Items.Add(Line)
Next
End Sub
Private Sub btnStats_Click(sender As Object, e As EventArgs) Handles btnStats.Click
Dim Ctr As Integer = 0
Dim Average As Double
Dim Sum As Double
Dim Found As Boolean = False
Dim Pass As Integer
Dim Index As Integer
lstDisplay.Items.Clear()
**For Ctr = 0 To gIndex Step 1
If gCourseRoster(Ctr).GPA > gCourseRoster(Ctr).GPA Then
lstDisplay.Items.Add(gCourseRoster(Ctr).GPA)
End If
Next**
Average = gComputeAverage(Sum)
lstDisplay.Items.Add("Number of Students: " & gNumberOfStudents)
lstDisplay.Items.Add("Average: " & Average)
End Sub
Private Function gComputeAverage(Sum As Double) As Double
Dim Ctr As Integer
Dim Average As Double
For Ctr = 0 To gIndex Step 1
Sum = Sum + gCourseRoster(Ctr).GPA
Next
Average = Sum / gNumberOfStudents
Return Average
End Function
End Class
You can use a Lambda expression to tease it out. The Cast part is converting from the gCourseRoster to a collection of Double by supplying the GPA to the Select statement.
Dim gList As New List(Of gCourseRoster)
gList.Add(New gCourseRoster With {.id = 1, .name = "Bob", .GPA = 3.9})
gList.Add(New gCourseRoster With {.id = 2, .name = "Sarah", .GPA = 3.2})
gList.Add(New gCourseRoster With {.id = 3, .name = "Frank", .GPA = 3.1})
Dim maxGPA = gList.Cast(Of gCourseRoster).Select(Function(c) c.GPA).ToList.Max
MessageBox.Show(maxGPA.ToString)
Output: 3.9

GPA Calculation

I'm having trouble finding out what the proper code would be to calculate the GPA. Everything I try ends up in the wrong GPA. Any help would be greatly appreciated I'm still a beginner at visual basic but this is the best I could do.
Option Explicit On
Option Strict On
Option Infer Off
Public Class mainForm
Private Sub exitButton_Click(sender As Object, e As EventArgs) Handles exitButton.Click
Me.Close()
End Sub
Private Sub dataButton_Click(sender As Object, e As EventArgs) Handles dataButton.Click
Const Prompt As String = "Enter number of Credit Hours:"
Const Title As String = "Credit Hours"
Const Prompt2 As String = "Enter grade:"
Const Title2 As String = "Grades"
Dim inputCredit As String
Dim inputGrades As String
Dim creditHours As Integer
Dim grades As Char
Dim gradesCounter As Integer
Dim point As Integer
Dim gpaTotal As Double
Dim creditHoursAccumulator As Integer
Dim pointAccumulator As Integer
inputCredit = InputBox(Prompt, Title)
inputGrades = InputBox(Prompt2, Title2)
Do While inputCredit <> String.Empty
Integer.TryParse(inputCredit, creditHours)
Char.TryParse(inputGrades, grades)
Select Case grades
Case CChar("A")
point = 4
Case CChar("B")
point = 3
Case CChar("C")
point = 2
Case CChar("D")
point = 1
Case CChar("F")
point = 0
End Select
pointAccumulator += 1
gradesCounter += 1
creditHoursAccumulator += creditHours
inputCredit = InputBox(Prompt, Title)
inputGrades = InputBox(Prompt2, Title2)
Loop
gpaTotal = pointAccumulator / creditHoursAccumulator
totalCreditsLabel.Text = "Total credit hours:" & creditHoursAccumulator
gpaLabel.Text = "GPA:" & gpaTotal
totalGradesLabel.Text = "Number of grades entered:" & gradesCounter
End Sub
End Class
Shouldn't line:
pointAccumulator += 1
be:
pointAccumulator += point