So for my class I am trying to do write a code that sums up numbers from 1-10. For example if a user puts in 3, the that program will add 1+2+3 and the final answer would be 6.......I am trying to do this using looping and also with a display mesage that gives the answer.
this is the code I have so far........
Option Strict On
Public Class frmSumOfNumbers
Private Sub btnEnterNumbers_Click(sender As Object, e As EventArgs) Handles btnEnterNumbers.Click
'For loop from 0 to counter -1
InputBox("Enter A Positive integer value", "Input needed", "10")
End Sub
Function Validation(ByVal PositiveNumber As Double, ByRef Result As Double) As Boolean
If PositiveNumber > -1 Then
Result = CDbl(PositiveNumber)
Else
'pop message box and return false if not positive
MessageBox.Show("Please enter positive numbers only")
Return False
End If
End Function
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
' Closes the program
Close()
End Sub
End Class
Your first problem is providing a place to collect the input values from the user. Take a look at the InputBox Function https://learn.microsoft.com/en-us/dotnet/api/microsoft.visualbasic.interaction.inputbox?view=netframework-4.8
Notice that is returns a string. We can get the input from the user by providing a String variable.
Dim UserInput As String
UserInput = InputBox("Enter A Positive integer value", "Input needed", "10")
But this value will disappear as soon as we reach End Sub! If we use a form level variable to collect the values the variable will be around as long as the form is open. Another advantage of a form level (class level) variable is that it can be seem by any method in the from.
We can use a collection variable like an array or a list. Since we are not sure how many numbers the user will enter let's use a list. With an array we would have to use ReDim Preserve every time we got a new number to resize the array. That isn't necessary with a list. See https://learn.microsoft.com/en-us/dotnet/api/system.collections.generic.list-1?view=netcore-3.1
At the Form level...
Private IntegerList as New List(Of Integer)
But the we have a String variable from the user. This is where your validation code comes in. We need to pass the what the user entered in the input box (remember InputBox returns a String) so the datatype of the argument in String. We want to get back an Integer so the datatype of the Function is Integer. Any return statement in the function must be followed by an Integer value.
I used Integer.TryParse to test if the input was a number and then I tested to see if the number is positive. See the docs https://learn.microsoft.com/en-us/dotnet/api/system.int32.tryparse?view=netcore-3.1
If the user input passes the validation then the number is added to the list, otherwise the message is displayed.
To add up the list you can the .Net framework do the loop behind the scenes with the .Sum method of a list or you can use a For Each loop to do it yourself. Same result.
Private IntegerList As New List(Of Integer)
Private Sub AddANumber_Click(sender As Object, e As EventArgs) Handles AddANumber.Click
Dim UserInput = InputBox("Enter A Positive integer value", "Input needed", "10")
Dim RetVal = Validation(UserInput)
If RetVal > -1 Then
IntegerList.Add(RetVal)
Else
MessageBox.Show("Please enter positive numbers only")
End If
End Sub
Function Validation(ByVal UserInput As String) As Integer
Dim ReturnInteger As Integer
If Integer.TryParse(UserInput, ReturnInteger) AndAlso ReturnInteger > -1 Then
Return ReturnInteger
Else
Return -1
End If
End Function
Private Sub DisplayTotal_Click(sender As Object, e As EventArgs) Handles DisplayTotal.Click
Dim Total = IntegerList.Sum
MessageBox.Show($"The Total is {Total}")
Dim LoopTotal As Integer
For Each i In IntegerList
LoopTotal += i
Next
MessageBox.Show($"The LoopTotal is {LoopTotal}")
End Sub
Note: The strings preceded by a $ are called interpolated strings. You can search for that term to learn how they work.
Related
I am trying to make a program that includes all the presidents and lets you search any letter or name to show the results of presidents associated with that letter or name. However, I am having trouble with actually adding them to the list. This is a class project, so the code is designed to meet requirements for that. Specifically, the part where it says
'Show the match
addPresidentsToList(presidents(idxReturned), idxReturned)
This is saying it isn't declared, but I'm not sure how to go about it.
Any tips or advice would be appreciated, thanks!
Public Class frmLab32
Const IDX_START As Integer = 0
Const IDX_END As Integer = 1
Const IDX_NAME As Integer = 2
Dim presidents() As String
Dim headerRowNeeded As Boolean
Private Sub frmLab32_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'Populate array from file
presidents = IO.File.ReadAllLines("USPresWithDates.txt")
End Sub
Private Sub btnSearch_Click(sender As Object, e As EventArgs) Handles btnSearch.Click
Dim idxReturned As Integer = -1
Dim idxStart As Integer = 0
'remove names
lstResults.Items.Clear()
'Header row?
headerRowNeeded = True
'Search for matches
Do
idxReturned = Array.FindIndex(presidents,
idxStart,
Function(el) el.Split(","c)(IDX_NAME).ToLower.Contains(txtSearch.Text.ToLower))
'Match Found?
If idxReturned > -1 Then
'Show the match
addPresidentsToList(presidents(idxReturned), idxReturned)
'Prepare for next search
idxStart = idxReturned + 1
End If
Loop Until idxReturned = -1
'Any names found?
If lstResults.Items.Count = 0 Then
'Update counter
lblCount.Text = "0"
'Tell User
MessageBox.Show(text:="No match found",
caption:="Search Results",
buttons:=MessageBoxButtons.OK,
icon:=MessageBoxIcon.Information)
End If
End Sub
End Class
My text file looks like this.
Washington, George
Adams, John
Jefferson, Thomas
Madison, James
Monroe, James
etc.
I use default names for controls in my text program but it is much better to use descriptive name like you did.
In the Form.Load I set the MaxLength property of the TextBox to 1. This will only allow a single character to be typed in the TextBox. You could set this property in the form designer and skip this line of code. Next fill the presidents array exactly as you did.
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
TextBox5.MaxLength = 1
presidents = IO.File.ReadAllLines("C:\Users\maryo\Desktop\Presidents.txt")
End Sub
Now for the search button. We need to validate the user input. A user could enter a number or punctuation character. Char https://learn.microsoft.com/en-us/dotnet/api/system.char?view=netcore-3.1#:~:text=Remarks-,.,bit%20numeric%20(ordinal)%20value. is a .net structure representing a character. It provides some interesting methods that can be helpful from time to time. Char.IsLetter() tells us (true or false) if a character is a letter. Just what we want to know. The only problem is a String is not a Char and .Text property of a TextBox is a String. Since we limited the entry to a single character we can convert this String to a Char with CChar(). If it is a letter we make the assignment to SelectedLetter otherwise we correct the user and exit the method.
Instead of all the index stuff we can use a For Each loop. It checks each element in presidents. String has a method called StartsWith. We can check each string in presidents to see if it .StartsWith the SelectedLetter. If it does, add it to the ListBox.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
ListBox1.Items.Clear()
'Validate user input
Dim SelectedLetter As String = ""
If Char.IsLetter(CChar(TextBox5.Text)) Then
SelectedLetter = TextBox5.Text.ToUpper
Else
MessageBox.Show("Please enter a letter A - Z.", "Enter Letter")
Exit Sub
End If
For Each pres In presidents
If pres.StartsWith(SelectedLetter) Then
ListBox1.Items.Add(pres)
End If
Next
If ListBox1.Items.Count = 0 Then
'Tell User
MessageBox.Show("No match found", "Search Results")
End If
End Sub
Just started doing Visual Basic, and am trying to make a time converter. I'm aware my code may be very inefficient or impractical, but I'm trying to make a part of the program where you type in your number of minutes into the text box as opposed to using the scrollbar. However, when the text box is empty the program crashes and throws the 'Conversion from string "" to type 'Double is not valid.' error. Code is below. The line where the error is shown is highlighted in red.
Public Class timeConverter
Private Sub scrollBar_Scroll(sender As Object, e As ScrollEventArgs) Handles scrollBar.Scroll
Dim minuteBoxInt As Integer 'Declaring variables'
Dim hourBoxInt As Integer
Dim minuteBox2Int As Integer = scrollBar.Value Mod 60
minuteBox.Text = scrollBar.Value() 'The scrollbar value will change with the minute box text'
minuteBoxInt = minuteBox.Text() 'Make the minuteBox associated with the minuteBoxInt variable'
hourBoxInt = Math.Floor(minuteBoxInt / 60) 'Rounds the decimal when the minuteBoxInt reaches 60'
hourBox.Text = hourBoxInt 'Makes the hourBox associated with the hourBoxInt variable'
minuteBox2.Text() = minuteBox2Int 'Makes the minuteBox2 associated with the minuteBox2Int variable'
End Sub
Private Sub minuteBox_TextChanged(sender As Object, e As EventArgs) Handles minuteBox.TextChanged
hourBox.Text = minuteBox.Text() / 60
End Sub
End Class```
To check user input (or lack of input) use .TryParse. Pass it a string and a variable of the type you are looking for. The .Text property of a TextBox is a string and here we have declare a variable, minutes, which will be filled with the parsed value of the string if the parse is successful. .TryParse returns a Boolean so it can be used in an If statement.
Private Sub minuteBox_TextChanged(sender As Object, e As EventArgs) Handles minuteBox.TextChanged
Dim minutes As Integer
If Integer.TryParse(minuteBox.Text, minutes) Then
hourBox.Text = (minutes / 60).ToString
Else
MessageBox.Show("Please make a valid entry in the minutes box.")
End If
End Sub
I have this so far but it just outputs 0
Option Explicit On
Option Strict On
Option Infer Off
Public Class frmMain
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
Me.Close()
End Sub
Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
Dim inFile As IO.StreamReader
Dim intBill As Integer
Dim avg As Integer
Dim trueAvg As Integer
If IO.File.Exists("monthlyBills.txt") Then
inFile = IO.File.OpenText("monthlyBills.txt")
Do Until inFile.Peek = -1
Integer.TryParse(inFile.ReadLine, intBill)
avg += intBill
Loop
inFile.Close()
trueAvg = CInt(avg / 12D)
lblAvg.Text = trueAvg.ToString()
Else
MessageBox.Show("Cannot find the file.", "monthlyBills",
MessageBoxButtons.OK, MessageBoxIcon.Information)
lblAvg.Text = "N/A"
End If
End Sub
End Class
Here is the "monthlyBills.txt" text file:
141.71
156.75
179.25
141.71
130.19
115.05
95.65
86.78
85.45
79.99
98.45
126.78
The problem is that none of the values in your text file is an integer and yet, you're trying to parse them as integers. You should use a Decimal type instead.
One more thing, whenever you use a .TryParse() method, you probably want to check its return value to make sure whether or not the parsing was successful. An If statement would help in this case.
This should work fine:
Dim inFile As IO.StreamReader
Dim intBill As Decimal
Dim avg As Decimal
Dim trueAvg As Integer
If IO.File.Exists(filePath) Then
inFile = IO.File.OpenText(filePath)
Do Until inFile.Peek = -1
If Decimal.TryParse(inFile.ReadLine, intBill) Then
avg += intBill
Else
' TODO: decide what you should do if a line isn't a decimal value.
End If
Loop
inFile.Close()
trueAvg = CInt(avg / 12D)
lblAvg.Text = trueAvg.ToString()
Else
MessageBox.Show("Cannot find the file.", "monthlyBills",
MessageBoxButtons.OK, MessageBoxIcon.Information)
lblAvg.Text = "N/A"
End If
Notes:
I changed the type of both inBill and avg to Decimal but kept trueAvg as in integer just in case you need that end value to be rounded. If you don't have a specific reason for that, you should use a Decimal instead and get rid of the CInt.
Floating numbers in .NET can be represented in two different categories of types; a binary representation (like Single or Double types), and a decimal representation (the Decimal type). For your particular situation, I suggested using Decimal because you seem to be dealing with prices and Decimal would be more suitable. You may read more about the difference in this post.
To use a method that doesn't have a .TryParse you must be very sure that each line in the text file is a number.
.ReadAllLines returns an array where each element is a line in the text file.
Next we use a bit of Linq to change each line (which is a string) to a Decimal value. The .Trim removes any white space that may be there. Don't worry about the IEnumerable. That is what this Linq returns. It just means you can loop through it with a For Each loop.
Then we can just call the .Average method on the IEnumerable and we are done.
Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
Dim lines As String() = File.ReadAllLines("monthlyBills.txt")
Dim decs As IEnumerable(Of Decimal) = From line In lines
Select CDec(line.Trim)
Dim avg As Decimal = decs.Average
lblAvg.Text = avg.ToString("N2")
End Sub
Here is another example that does not use the Linq query and does use .TryParse. If you use a List instead of an array you don't have to know how many items are going to be added in advance. Also you don't need to keep track of the index. You still use the .Average method on the list.
Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
Dim lines As String() = File.ReadAllLines("monthlyBills.txt")
Dim decs As New List(Of Decimal)
Dim dec As Decimal
For Each line As String In lines
If Decimal.TryParse(line, dec) Then
decs.Add(dec)
Else
MessageBox.Show(line & " is not a number and is being excluded from calculations.")
End If
Next
Dim avg As Decimal = decs.Average
lblAvg.Text = avg.ToString("N2")
End Sub
I'l trying to generate a unique random number generator with the snippet of code from below, but it's not working. The IF section is suppose to test if it's the first random number generated, if it is, it's suppose to add the first random number to the ArrayList, if it's not the first random number, it's supposed to check if the random number is already in the ArrayList and if it's in the ArrayList it's suppose to MsgBox and generate a new unique random number that is not already in the ArrayList and add it to the ArrayList, but it's not doing any of those. Any help would be greatly appreciated.
Public Class Form1
Dim r As New Random
Dim dLowestVal As Integer = 1
Dim dHighestVal As Integer = 26
Dim dItemAmount As Integer = 1
Dim RollCheck As New HashSet(Of Integer)
Private Sub btnExit_Click(sender As Object, e As EventArgs) Handles btnExit.Click
End
End Sub
Private Sub btnRollDice_Click(sender As Object, e As EventArgs) Handles btnRollDice.Click
lblRandomNo.Text = r.Next(dLowestVal, dHighestVal)
lblItemAmount.Text = dItemAmount
If dItemAmount = 1 Then
RollCheck.Add(Val(lblRandomNo.Text))
ElseIf (RollCheck.Contains(Val(lblRandomNo.Text))) Then
MsgBox("Already Exists")
lblRandomNo.Text = r.Next(dLowestVal, dHighestVal)
RollCheck.Add(Val(lblRandomNo.Text))
End If
dItemAmount = dItemAmount + 1
Thanks in advance.
You could replace your whole method with this simple one
' This is globally declared at the top of your form
Dim values As New List(Of Integer)
' This is called when you construct your form
' It will store consecutive integers from 1 to 25 (25 elements)
values = Enumerable.Range(1, 25).ToList()
This is the method that extract an integer from your values that is not already used
Private Sub Roll()
' Get an index in the values list
Dim v = r.Next(0, values.Count)
' insert the value at that index to your RollCheck HashSet
RollCheck.Add(values(v))
' Remove the found value from the values list, so the next call
' cannot retrieve it again.
values.Remove(values(v))
End Sub
And you can call it from the previous event handler in this way
Private Sub btnRollDice_Click(sender As Object, e As EventArgs) Handles btnRollDice.Click
if values.Count = 0 Then
MessageBox("No more roll available")
else
Roll()
End Sub
End Sub
The point of the HashSet is that since it doesn't allow duplicates you can just check the return value of Add() to determine whether the number was successfully inserted or if it already exists in the list.
If you want to keep trying until it succeeds all you have to do is wrap it in a loop:
If dHighestVal - dLowestVal >= RollCheck.Count Then
'If the above check passes all unique values are MOST LIKELY already in the list. Exit to avoid infinite loop.
MessageBox.Show("List is full!")
Return 'Do not continue.
End If
Dim Num As Integer = r.Next(dLowestVal, dHighestVal)
'Iterate until a unique number was generated.
While Not RollCheck.Add(Num)
MessageBox.Show("Already exists!")
Num = r.Next(dLowestVal, dHighestVal)
End While
lblRandomNo.Text = Num
An alternative way of writing the loop is: While RollCheck.Add(Num) = False.
I am working on a program for my Visual Basic class and have a quick question. One of the things we were encouraged to do was to check to make sure the quantity entered in a text box is actually a number. Our professor suggested using IsNumeric to perform this check, but I'm running into some trouble. I already had a good bit of the code written before he added this to the instructions, so not sure how to integrate this into the code I already have.
The main purpose of the program is to allow the user to add ingredients from one list box to the recipe list box, input a quantity for each selected ingredient in a text box, and calculate the total calories for the recipe. The way I have the code written now, IsNumeric is part of a nested if statement at the beginning of where I will start adding the selected ingredients to the recipe list box. I'm not sure if that's the correct place for it though.
Here is the code I have written so far.
Public Class Form1
Private Sub btnAdd_Click(sender As Object, e As EventArgs) Handles btnAdd.Click
Dim i As Integer = lstIngredients.SelectedIndex
Dim Quantity As Double
Dim intCount As Integer = 0
If Trim(txtQuantity.Text = "") Then
Quantity = 1
Else
Quantity = Me.txtQuantity.Text
End If
If txtQuantity.Text Is IsNumeric() Then
If intCount < Quantity Then
lstRecipe.Items.Add(Quantity & " " & lstIngredients.Text)
intCount += 1
End If
Else
MessageBox.Show("The quantity entered is not numeric. Please add a numeric quantity.")
End If
End Sub
Private Sub btnClear_Click(sender As Object, e As EventArgs) Handles btnClear.Click
lstRecipe.Items.Clear()
txtQuantity.Clear()
txtAnswer.Clear()
End Sub
Private Sub btnCalculate_Click(sender As Object, e As EventArgs) Handles btnCalculate.Click
End Sub
End Class
Also, here is the error I receive when I attempt to run this program as it is written.
Error 1 Argument not specified for parameter 'Expression' of 'Public Function IsNumeric(Expression As Object) As Boolean'.
Any suggestions would be greatly appreciated.
A more correct way to do that is to use the TryParse method available in the Int32 or Double class
If Double.TryParse(txtQuantity.Text, Quantity) Then
If intCount < Quantity Then
lstRecipe.Items.Add(Quantity & " " & lstIngredients.Text)
intCount += 1
End If
Else
MessageBox.Show("The quantity entered is not numeric. Please add a numeric quantity.")
End If
And you could also remove the code that test for the empty textbox.
The TryParse method wants two parameters, the first one is the string that could be converted, the second parameter is the variable that receives the result of the conversion if it is possible. If the conversion cannot be executed the function returns false.
There are numerous reasons to prefer Double.TryParse instead of IsNumeric.
The first reason is that with TryParse you also get the result of the conversion while with IsNumeric you would have to do the conversion after the check.
The second reason is that you could give to IsNumeric whatever object you want (also a Button for example) and it accepts it. You would never discover this kind of errors at compile time. Instead, with TryParse, you could only pass a string as its first parameter.
You're just using the function incorrectly - you need to pass the string as a parameter.
If IsNumeric(txtQuantity.Text) Then
Use Regex.IsMatch:
Public Function isNumeric(input As String) As Boolean
Return Regex.IsMatch(input.Trim, "\A-{0,1}[0-9.]*\Z")
End Function
Yes, Double.Tryparse is the best answer to this question, but to save you time on coding and ensure that the value entered is always numeric, use the NumericDropdown control instead of the plain Text Box so that you are sure that inputted value is always numeric and save you time checking the inputted value since that control will not accept anything but numeric values only.
Use IsNumeric(txtQuantity.Text) if you have that method defined. Otherwise use Int32.TryParse() method. It will return true if the text passed in is a number.
Private Sub txbDwellTime_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txbDwellTime.KeyPress
numDecOnly(e)
End Sub
Public Sub numDecOnly(ByVal e As System.Windows.Forms.KeyPressEventArgs)
If (Asc(e.KeyChar) >= 48 And Asc(e.KeyChar) <= 57 Or Asc(e.KeyChar) = 46) Then
'good job do nothing we only allow positive Decimal numbers in this field
'Asc(e.KeyChar) 48 Through 57 i.e. 0 through 9 Or Asc(e.KeyChar) 46 (dot= .)
Else
e.Handled = True
MsgBox("Only Positive Decimal Numbers Allowed this field")
End If
End Sub