Checking for numeric value entered in text box in Visual Basic - vb.net

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

Related

User enters letter then button computes position from a string using VB

I am using indexOf but I cannot figure out where I made a mistake as the output gives a -1.
I realise I can copy the whole statement paragraph into the last line of the output but I was hoping it could pull it straight from the label.
Public Class Form1
Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click
Dim statement As String
Dim letter As String
statement = CStr(lblStatement.Text)
letter = CStr(txtLetter.Text)
txtOutput.Text = CStr(lblStatement.Text).IndexOf("letter")
'txtOutput.Text = letter.ToUpper & " first occurs in position " & statement.IndexOf(statement) & "."
End Sub
End Class
Here is a picture of the form:
Update: Thanks to #ADyson and #Slugsie for taking the time to respond to my call for help. As #Slugsie noted it was indeed down to the lower case in my screenshot. I am now researching how to make it work without being case-sensitive.
Final code
Public Class Form1
Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click
txtOutput.Text = lblStatement.Text.IndexOf((txtLetter.Text).ToUpper)
End Sub
End Class
.IndexOf("letter")
is looking for the literal text letter within the data the user enters in the text. in VB.NET (and most other programming languages), anything enclosed within quote marks is treated as a fixed string of text, to be interpreted as-is rather than processed or treated as program code.
To make it look for the contents of the letter variable instead (which looks like what you were intending) simply remove the quote marks:
.IndexOf(letter)
As an aside, your whole code could be much reduced - primarily the use of CStr is unnecessary, because the Text properties of the textbox and label already return a string - meaning you don't need to use CStr convert it - and also because you're not making use of all the variables you declared either.
You could re-write your whole sample much more succinctly as:
Public Class Form1
Private Sub btnCompute_Click(sender As Object, e As EventArgs) Handles btnCompute.Click
txtOutput.Text = lblStatement.Text.IndexOf(txtLetter.Text)
End Sub
End Class

Sum of Numbers with LOOPING

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.

How to fix System.FormatException: 'Input string was not in a correct format'

I am trying to change Font Family in VB.NET for a RichTextBox
I have tried searching through google and even specific sites for just code problems. Nothing works.
These are the codes for FontFamily changing (it is a tool strip combo button)
Private Sub TscFontFamily_TextChanged(sender As Object, e As EventArgs) Handles tscFontFamily.TextChanged
rtbContent.SelectionFont = New Font(Convert.ToString(tscFontFamily.Text), Convert.ToInt32(tscFontSize.Text))
End Sub
And the FontSize (also a tool strip combo button)
Private Sub tscFontSize_TextChanged(sender As Object, e As EventArgs) Handles tscFontSize.TextChanged
Dim newSize As Single = Convert.ToSingle(tscFontSize.Text)
rtbContent.SelectionFont = New Font(rtbContent.SelectionFont.FontFamily, newSize)
End Sub
I expect this to work since it makes sense, right? But it says "input string was not in correct format" and if i remove the Convert.ToString and other convert code, it says something like "Conversion from string "" to type 'Single' is not valid.".
Also to mentiion, is the fact that i have actually tried Convert.ToString and Convert.ToDouble and basically everything for BOTH.
There is no need to call ToString on tscFontFamily.Text because the Text property of a TextBox returns a String; you're essentially saying return a String value from this String value.
Convert.ToInt32 is a quick and dirty was of converting String values to Int32 (aka integer) values. If you're relying on input from a user then you should almost always use Int32.TryParse instead. This method returns a Boolean value based on if the conversion of the input is successful and then the second parameter passed is a reference variable so if the result of the method is True then the second parameter contains the converted value. However, it looks like you're wanting a Single value in which case you'd actually use Single.TryParse.
Here would be an example applying the changes to your code:
Private Sub tscFontSize_TextChanged(sender As Object, e As EventArgs) Handles tscFontSize.TextChanged
Dim newSize As Single
If Single.TryParse(tscFontSize.Text, newSize) Then
rtbContent.SelectionFont = New Font(rtbContent.SelectionFont.FontFamily, newSize)
End If
End Sub

How do I get the textbox to enable after a certain amount of text is inputted?

So my next question(i know i know ive had a lot of questions already but im learning and my teachers suck)
but I am trying to get the textbox to go to readonly after a certain amount of text has been entered. I know how to make it a read only textbox but only after Ive had one set of data entered. i need it to be readonly after 7 days of data has been entered
I've tried inputtextbox.enabled = false
'Validating if user input is a number or not
Dim output As Integer
If Not Integer.TryParse(InputTextbox.Text, output) Then
MessageBox.Show("ERROR! Data must be a number")
InputTextbox.Text = String.Empty
Else
UnitsTextbox.AppendText(Environment.NewLine & InputTextbox.Text)
InputTextbox.Text = String.Empty
End If
InputTextbox.Enabled = False
I'm expecting it to disable after the user has entered 7 days worth of data but it only disables after one day of data is entered
Since the entries to UnitsTextbox are all done in code, this TextBox can be set to read only at design time.
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim output As Integer
If Not Integer.TryParse(InputTextbox.Text, output) Then
MessageBox.Show("ERROR! Data must be a number")
Else
UnitsTextbox.AppendText(Environment.NewLine & InputTextbox.Text)
End If
'Moved this line outside of the If because it happens either way
InputTextbox.Text = String.Empty
If UnitsTextbox.Lines.Length >= 7 Then
Button2.Enabled = False
End If
End Sub
Here's some simple psuedocode
Private Sub InvalidateTextbox(sender As TextBox, e As KeyEventArgs) Handles TextBox1.KeyUp, TextBox2.KeyUp
'FOR ANY TEXTBOX YOU WANT TO CONTROL WITH THIS SUB, ADD AN ADDITIONAL HANDLE.
If Strings.Len(sender.Text) > 7 Then
'^SIMPLE CONDITIONAL, CHECKING IF THE LENGTH IS MORE THAN SEVEN CHARACTERS, MODIFY THIS TO SUIT YOUR NEEDS.
sender.Enabled = False
'^IF THE CONDITIONAL IS TRUE, DEACTIVATE THE CONTROL, IF THAT IS WHAT YOU ARE LOOKING FOR.
sender.ReadOnly = true
'^IF YOU WANT READONLY,NOT ENABLED/DISABLED.
End If
End Sub
This code will execute every time a key is pressed while the text boxes are active. What is after "Handles" defines what events will trigger the sub.
sender becomes the textbox object that triggered the sub. e holds all the event arguments for the keyboard, so you can evaluate things like which key was pressed and other neat things.
There was some confusion on if you wanted enabled/disabled or readonly, both options included.

Passing arguments to methods in VB

I'm hoping you guys can help with a problem that should be simple to solve, I've just had issues finding a solution. In the program that I'm writing some of the textbox's have to be numeric between 1 and 10, and others just have to be numeric. Instead of coding each textbox to verify these parameters I decided to write methods for each of them. I'm having problems passing the arguments and getting it to function correctly. Included is some of my code that shows what I'm trying to accomplish.
Public Shared Sub checkforonetoten(ByVal onetoten As Double)
If (onetoten > 1 & onetoten < 10) Then
Else
MessageBox.Show("Please enter a Number between 1-10", "Error")
End If
End Sub
Public Shared Sub checkfornumber(numCheck As Double)
Dim numericCheck As Boolean
numericCheck = IsNumeric(numCheck)
If (numericCheck = False) Then
MessageBox.Show("Please enter a number", "Error")
End If
End Sub
Private Sub textboxS_TextChanged(sender As Object, e As EventArgs) Handles textboxS.TextChanged
Dim S As Double
S = textboxS.Text
checkfornumber(S)
checkforonetoten(S)
End Sub
One of your main problems is you're converting your text without validating it. You're also programming without the Options On to warn you of bad conversion techniques like you're using in the event handler.
The TryParse method would come in handy here:
Private Sub textboxS_TextChanged(sender As Object, e As EventArgs) Handles textboxS.TextChanged
Dim S As Double
If Double.TryParse(textboxS.Text, S) Then
checkforonetoten(S)
End If
End Sub
Since the TryParse method validates your text and sets the value to 'S', you only need to check the range.
Of course using NumericUpDown controls would make all this moot, since the values will always only be numbers and you can set the range on each one.
one way to structure it is to have one event procedure process the similar TB types:
Private Sub textboxS_TextChanged(sender As Object, e As EventArgs) _
Handles textbox1.TextChanged, textbox12.TextChanged, _
Handles textbox16.TextChanged
Dim S As Double
If Double.TryParse(Ctype(sender, TextBox).Text, S) Then
' or place the Check code here for all the TextBoxes listed above
checkforonetoten(S)
End If
End Sub
The plain numeric kind:
Private Sub textboxQ_TextChanged(sender As Object, e As EventArgs) _
Handles textbox2.TextChanged, textbox6.TextChanged
Dim S As Double
If Double.TryParse(Ctype(sender, TextBox).Text, S) = False Then
MessageBox.Show("Please enter a number", "Error")
End If
End Sub
Rather than calling a function and passing the current TextBox from events (which is fine), have 2 or 3 events process them all. The point is adding/moving the Handles clause to a common event procedure (be sure to delete the old ones).
If you do decide to call a common function, dont do anything in the events (you still have one per TB) and do it all in the common proc:
Private Sub textboxS_TextChanged(sender As Object, e As EventArgs) _
Handles textboxS.TextChanged
checkforonetoten(Sender)
End Sub
private Sub checkforonetoten(tb As Textbox)
Dim S As Double
If Double.TryParse(tb.Text, S) Then
' your check for 1 - 10 on var S
else
' error: not a valid number
End If
end sub
Also:
If (onetoten > 1 & onetoten < 10) Then
should be:
If (onetoten > 1) AndAlso (onetoten < 10) Then