VBA 2012 - Need to return an error when a user enters text instead of a numbers - vba

I am taking a VBA class and am completely stuck on this problem. We CANNOT use the masked text box, which would solve this problem. Instead the professor actually wants me to learn the code, can you imagine?
All kidding aside, the user needs to enter a gas price into a text box, then hit calculate to receive the total cost of the trip. There is much more to the interface but will spare you the details. If a user enters anything else number than a positive number with one decimal place, it should return an error. I have figured out 0 or 0000 as well as a negative number such as -3.45. Now I have to get any text or special characters to give me an error as well as something like 34.56.12.45. You never know, a user may feel the need to type in their IP address. The key to the assignment is that I catch all probable user errors.
Here is what I've written for the calculation as well as catch the errors. I have tried the Try/Catch statements as well. Nothing worked but I got the first two parts of the IF statement to work yet always failing on the last IF part until it gets to the calculation.
Private Sub btnCalc_Click(sender As Object, e As EventArgs) Handles btnCalc.Click
Dim Mileage As Decimal
Dim Miles As Decimal
Dim GasPrice As Decimal
Dim Cost As Decimal
If CDec(txtbxGasPrice.Text) = 0 Then
MessageBox.Show("Please enter a positive dollar amount")
txtbxGasPrice.Text = String.Empty
End If
If CDec(txtbxGasPrice.Text) < 0 Then
MessageBox.Show("Please enter a positive dollar amount")
txtbxGasPrice.Text = String.Empty
End If
If Cost = CDec((Miles / Mileage) * GasPrice) Then
Miles = CDec(lblTMiles.Text)
Mileage = CDec(lblMileage.Text)
GasPrice = CDec(txtbxGasPrice.Text)
lblTotalCost.Text = Cost.ToString("C2")
End If
If CBool(txtbxGasPrice.Text = "") Then
MsgBox("You must enter a dollar amount")
End If
*If Not IsNumeric(txtbxGasPrice.Text) Then
MessageBox.Show("Please enter a positive dollar amount")
txtbxGasPrice.Text = String.Empty*
End If
End Sub
'I have placed this at the top, in the middle, at the bottom but no luck. What am I missing?
Appreciate your thoughts - Lauren

This one seems to meet your criteria and pass David's tests:
Function IsValid(txt As String) As Boolean
If Not IsNumeric(txt) Then
Exit Function
End If
If Len(txt) < 2 Then
Exit Function
End If
If Not Mid(txt, Len(txt) - 1, 1) = "." Then
Exit Function
End If
If Not txt > 0 Then
Exit Function
End If
IsValid = True
End Function

This seems like a perfect application of regular expressions, but could be out of scope for this problem, maybe even better though vb has a Decimal.TryParse(or parse) that will take a string and try to parse it to a decimal.
http://msdn.microsoft.com/en-us/library/system.decimal.tryparse.aspx
on a side not I'm not 100% sure how it acts with xx.xx.xx but I'm betting it will fail and help your problem

I'm going to expand on CSgoose's idea to use RegEx, it seems a lot more reliable. I am very, very green when it comes to using RegEx but I try to work on Q's here at SO, so this may not be the optimal pattern to match, but a function like this seems to do the trick when I test a few value.
0/0.0/0.00 = False
-1.5 = False
1.5 = True
5.45 = False
Steve = False
Steve.6 = False
Steve6.58 = False
6.574.2 = False
A value that evaluates to 0 will return false. Negative values return false. Value must have a decimal component, be comprised of any # of digits (this can be tweaked if you want to limit it, eg., to ##.# format, etc.). Matches full text only, so things like IP addresses won't return true, etc.
NOTE This is VBA, but should be easily adaptable for your purposes)
Sub YourSub()
If Not IsMatch(CStr(txtbxGasPrice.Text)) Then
MsgBox "Please ensure that the value you enter is a positive dollar amount, to 1 decimal place!", vbCritical, "Invalid Gas Price Value!"
End IF
End Sub
This function requires enabling reference to Microsoft VBScript Regular Expressions 5.5, or you could use late-binding.
Function IsMatch(str As String) As Boolean
'Tests for a positive numeric value, formatted 0.0 with a mandatory decimal component
' exact match only
Dim re As RegExp
Dim allMatches As MatchCollection
Dim retVal As Boolean
retVal = False 'by default
If Not IsNumeric(str) Then GoTo EarlyExit 'ignore any non-numeric value
Set re = New RegExp
re.Pattern = "\d*\.[0-9]"
Set allMatches = re.Execute(str)
If allMatches.Count = 1 Then
'If there are multiple matches, then I think safe to say it's not a match,
' make sure it's a full string match
If str > 0 Then
retVal = (allMatches(0) = str)
End If
End If
EarlyExit:
Set re = Nothing
IsMatch = retVal
End Function
Update to force, for example, ##.# format, you could do
re.Pattern = "[1-9]?\d\.\d"

Related

Invalid Cast Expectation Was Unhanded (when checking the contents of a text box)

This code is from a subroutine that checks if a text box entry fits the criteria specified (an integer between 1 and 100).
The first IF statement should check if it is not a numerical entry. If it is not numerical then the contents of the text box should be set blank so that a number can be entered.
The second IF statement should check if the number is larger than 100. If it is then the contents of the text box should be set blank so that an appropriate number can be entered.
The Third IF statement should check if the number is smaller than 1. If it is then the contents of the text box should be set blank so that an appropriate number can be entered.
Finally the contents of the box should be set as the variable.
I initially programmed the first IF statement on its own and it worked. But upon adding the others my program would crash when I typed anything into the text box and the error was as stated in my title. I have looked at multiple solutions and have found nothing for almost 2 days that fixed the problem.
Any suggestions would be appreciated.
Public Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles NumQTextBoxInput.TextChanged
'Check if input is numeric
If Not IsNumeric(NumQTextBoxInput.Text) Then NumQTextBoxInput.Text = ""
If (NumQTextBoxInput.Text > 100) Then
NumQTextBoxInput.Text = ""
End If
If (NumQTextBoxInput.Text < 1) Then
NumQTextBoxInput.Text = ""
End If
ArchwayComputingExamCreator.GlobalVariables.NumOfQuestions = NumQTextBoxInput.Text
'Setting the variable to the contense
End Sub
You should always use the appropriate parse function when accepting text for numbers.
Public Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles NumQTextBoxInput.TextChanged
Dim Value as integer
If Not Integer.TryParse(NumQTextBoxInput.text, Value) OrElse Value < 1 OrElse Value > 100 Then NumQTextBoxInput.Text = ""
... no idea if the archway bit is really what you wanted so left that out ....
End Sub
In this operation:
If Not IsNumeric(NumQTextBoxInput.Text) Then NumQTextBoxInput.Text = ""
Any time the input is not numeric, you set it to a value which is still not numeric. So any numeric comparison will fail:
If (NumQTextBoxInput.Text > 100)
Maybe you meant to set the value to some numeric default?:
If Not IsNumeric(NumQTextBoxInput.Text) Then NumQTextBoxInput.Text = "0"
Or just exit the method entirely when it's not numeric?:
If Not IsNumeric(NumQTextBoxInput.Text) Then
NumQTextBoxInput.Text = ""
Return
End If
Or perhaps something else? However you modify your logic, the point is that you can't perform numeric comparisons on non-numeric strings.

VBA - How to check if a String is a valid hex color code?

To prevent errors, I need to check if a String retrieved from a custom input box is not a valid hex color code. So far I found various solutions for other languages, but none for VBA.
Working on the following code, giving a not hex value input will cause a run time error. That's critical to my project, since I am working on a protected sheet.
Public Function HexWindow(MyCell As String, Description As String, Caption As String)
Dim myValue As Variant
Dim priorValue As Variant
priorValue = Range(MyCell).Value
myValue = InputBox(Description, Caption, Range(MyCell).Value)
Range(MyCell).Value = myValue
If myValue = Empty Then
Range(MyCell).Value = priorValue
End If
tHex = Mid(Range(MyCell).Text, 6, 2) & Mid(Range(MyCell).Text, 4, 2) & Mid(Range(MyCell).Text, 2, 2)
Range(MyCell).Interior.Color = WorksheetFunction.Hex2Dec(tHex)
End Function
How can I set a condition that recognizes a value not being in the format of "#" & 6 characters from 0-9 and A-F in any case?
Couple ways to do this. The easiest way is with a regular expression:
'Requires reference to Microsoft VBScript Regular Expressions x.x
Private Function IsHex(inValue As String) As Boolean
With New RegExp
.Pattern = "^#[0-9A-F]{1,6}$"
.IgnoreCase = True 'Optional depending on your requirement
IsHex = .Test(inValue)
End With
End Function
If for some reason that doesn't appeal to you, you could also take advantage of VBA's permissive casting of hex strings to numbers:
Private Function IsHex(ByVal inValue As String) As Boolean
If Left$(inValue, 1) <> "#" Then Exit Function
inValue = Replace$(inValue, "#", "&H")
On Error Resume Next
Dim hexValue As Long
hexValue = CLng(inValue) 'Type mismatch if not a number.
If Err.Number = 0 And hexValue < 16 ^ 6 Then
IsHex = True
End If
End Function
I would use regular expressions for this. First you must go to Tools-->Referencesin the VBA editor (alt-f11) and make sure this library is checked
Microsoft VBScript Regular Expressions 5.5
Then you could modify this sample code to meet your needs
Sub RegEx_Tester()
Set objRegExp_1 = CreateObject("vbscript.regexp")
objRegExp_1.Global = True
objRegExp_1.IgnoreCase = True
objRegExp_1.Pattern = "#[a-z0-9]{6}"
strToSearch = "#AAFFDD"
Set regExp_Matches = objRegExp_1.Execute(strToSearch)
If regExp_Matches.Count = 1 Then
MsgBox ("This string is a valid hex code.")
End If
End Sub
The main feature of this code is this
objRegExp_1.Pattern = "#[a-z,A-Z,0-9]{6}"
It says that you will accept a string that has a # followed by any 6 characters that are a combination of upper case or lower case strings or numbers 0-9. strToSearch is just the string you are testing to see if it is a valid color hex string. I believe this should help you.
I should credit this site. You may want to check it out if you want a crash course on regular expressions. They're great once you learn how to use them.

Why isn't my VB if statement working?

I'm working on my first project for my visual basic programming class.
I am trying to have this condition statement say if the discount rate is .1 or (10%), then add to the count of customers who got the discount (msngFrequentFlyers) and add to the accumulator that keeps track of total discounts given (msngTotalDiscounts).
I'm very new to all this- please help! Project is due tonight.
Here's my code:
Public Class frmTaxiConsole
'Modular Variable Declaration Section
'Declares msngDiscountRate and sets inital value to -1 for testing user input
Dim msngDiscountRate As Single = -1
'Declares all counter variables
Dim msngNumberOfRides As Single
Dim msngNumberOfFrequentFlyers As Single
'Declares all accumulator variables
Dim msngRevenue As Single
Dim msngTotalDiscounts As Single
Dim msngBillableMiles As Single
If the radio button for the discount is checked:
Private Sub radFrequentFlyer_CheckedChanged(sender As Object, e As EventArgs) Handles radFrequentFlyer.CheckedChanged
msngDiscountRate = 0.1 'Sets discount rate to 10% upon selection of radio button
End Sub
This is the if statement that's not working, in the "Process Transaction" click event:
If msngDiscountRate = "0.1" Then 'Checks to see if this transaction had any discount
msngNumberOfFrequentFlyers += 1 'If so, adds 1 to the number of discounts given
msngTotalDiscounts = msngTotalDiscounts + (sngSubTotal * msngDiscountRate) 'Also adds the discount amount to the total discounts accumulator (without making it negative)
End If
Here's the entire code for the "Process Transaction" click event:
Private Sub btnProcessTx_Click(sender As Object, e As EventArgs) Handles btnProcessTx.Click
'Local Variable Declaration Section
Dim sngMilesDriven As Single
Dim dblOdometerStart As Double
Dim dblOdometerEnd As Double
Dim sngInitialFee As Single
Dim sngPerMileFee As Single
Dim sngMileageCharge As Single
Dim sngSubTotal As Single
Dim sngDiscount As Single
Dim sngTotalDue As Single
'Data Input + Testing Section
'Changes all text box backcolors white, in case they had been turned red due to an error
txtOdometerStart.BackColor = Color.White
txtOdometerEnd.BackColor = Color.White
txtInitialFee.BackColor = Color.White
txtPerMileFee.BackColor = Color.White
'Try/Catch validates user input for Inital Fee
Try
'Attempts to convert user input to Single and store as a local variable
sngInitialFee = CSng(txtInitialFee.Text)
Catch ex As Exception
'If error occurs, displays a messagebox, changes background color of relavent text box, and exits sub.
MessageBox.Show("Please enter a valid initial fee.", "Invalid Initial Fee", MessageBoxButtons.OK)
txtInitialFee.BackColor = Color.Red
txtInitialFee.Focus() 'Focuses in text box where error occured so user can fix
Exit Sub
End Try
'Try/Catch validates user input for Per-Mile Fee
Try
'Attempts to convert user input to Single and store as a local variable
sngPerMileFee = CSng(txtPerMileFee.Text)
Catch ex As Exception
'If error occurs, displays a messagebox, changes background color of relavent text box, and exits sub.
MessageBox.Show("Please enter a valid per-mile fee.", "Invalid Per-Mile Fee", MessageBoxButtons.OK)
txtPerMileFee.BackColor = Color.Red
txtPerMileFee.Focus() 'Focuses in text box where error occured so user can fix
Exit Sub
End Try
'Try/Catch validates user input for starting milage
Try
'Attempts to convert user input to Double and store as a local variable
dblOdometerStart = CDbl(txtOdometerStart.Text)
Catch ex As Exception
'If error occurs, displays a messagebox, changes background color of relavent text box, and exits sub.
MessageBox.Show("Please enter a valid starting milage.", "Invalid Odometer Reading", MessageBoxButtons.OK)
txtOdometerStart.BackColor = Color.Red
txtOdometerStart.Focus() 'Focuses in text box where error occured so user can fix
Exit Sub
End Try
'Try/Catch validates user input for ending milage
Try
'Attempts to convert user input to Double and store as a local variable
dblOdometerEnd = CDbl(txtOdometerEnd.Text)
Catch ex As Exception
'If error occurs, displays a messagebox, changes background color of relavent text box, and exits sub.
MessageBox.Show("Please enter a valid ending milage.", "Invalid Odometer Reading", MessageBoxButtons.OK)
txtOdometerEnd.BackColor = Color.Red
txtOdometerEnd.Focus() 'Focuses in text box where error occured so user can fix
Exit Sub
End Try
'If statement ensures Inital Fee is a positive number
If sngInitialFee < 0 Then
'If error occurs, displays a messagebox, changes background color of relavent text box, and exits sub.
MessageBox.Show("Initial Fee cannot be negative.", "Invalid Inital Fee", MessageBoxButtons.OK)
txtInitialFee.BackColor = Color.Red
txtInitialFee.Focus() 'Focuses in text box where error occured so user can fix
Exit Sub
End If
'If statement ensures Per-Mile Fee is a positive number
If sngPerMileFee < 0 Then
'If error occurs, displays a messagebox, changes background color of relavent text box, and exits sub.
MessageBox.Show("Per-Mile Fee cannot be negative.", "Invalid Per-Mile Fee", MessageBoxButtons.OK)
txtPerMileFee.BackColor = Color.Red
txtPerMileFee.Focus() 'Focuses in text box where error occured so user can fix
Exit Sub
End If
'If statement checks to make sure starting milage is smaller number than ending milage
If dblOdometerEnd <= dblOdometerStart Then
'If ending milage is smaller number than starting milage, displays a messagebox and exits sub.
MessageBox.Show("Your ending mileage cannot be less than or equal to your starting mileage. Please check your odometer readings.", "Invalid Odometer Reading", MessageBoxButtons.OK)
txtOdometerStart.Focus() 'Focuses in starting odometer reading text box so user can fix
Exit Sub
End If
'If statement checks to make sure both odometer readings are positive numbers.
If dblOdometerEnd < 0 Or dblOdometerStart < 0 Then
'If either odometer reading is negative, displays a messagebox and exits sub.
MessageBox.Show("Both your odometer readings must be positive numbers. Please check your odometer readings.", "Invalid Odometer Reading", MessageBoxButtons.OK)
txtOdometerStart.Focus() 'Focuses in starting odometer reading text so user can fix
Exit Sub
End If
'If statement checks to ensure user has seleted one of the two radio buttons
If msngDiscountRate = -1 Then
'If msngDiscountRate is the same as the initial value, neither option has been chosen, an error message is shown, and sub exited.
MessageBox.Show("Please choose a frequent flyer status.", "Frequent Flyer?", MessageBoxButtons.OK)
Exit Sub
End If
'Calculations Section
sngMilesDriven = CSng(dblOdometerEnd - dblOdometerStart) 'Subtracts starting mileage from ending mileage, converts to single, stores as var sngMilesDriven
sngMileageCharge = sngMilesDriven * sngPerMileFee 'Multiplies the miles driven by the per-mile fee and stores as var sngMileageCharge
sngSubTotal = sngMileageCharge + sngInitialFee 'Adds the milage charge to the initial fee, stores as var sngSubTotal
sngDiscount = sngSubTotal * msngDiscountRate * -1 'Multiplies subtotal by discount rate, makes negative, stores as var sngDiscount
sngTotalDue = sngSubTotal + sngDiscount 'Subtracts discounts from subtotal, stores as var sngTotalDue
'Counter and Accumulator Operations
msngNumberOfRides += 1 'Adds 1 to the number of rides given
If msngDiscountRate = "0.1" Then 'Checks to see if this transaction had any discount
MsgBox(msngDiscountRate)
msngNumberOfFrequentFlyers += 1 'If so, adds 1 to the number of discounts given
msngTotalDiscounts = msngTotalDiscounts + (sngSubTotal * msngDiscountRate) 'Also adds the discount amount to the total discounts accumulator (without making it negative)
End If
msngRevenue = msngRevenue + sngTotalDue 'Adds the total due for current transaction to revenue accumulator
msngBillableMiles = msngBillableMiles + sngMilesDriven 'Adds miles from this transaction to running total
'Output Section
'Displays above calculations in respective labels and formats as currency if neccecary.
lblMilesDrivenOutput.Text = sngMilesDriven
lblSumInitialFeeOutput.Text = FormatCurrency(sngInitialFee) 'Formats sngInitialFee as currency and displays in lblSumInitialFeeOutput
lblSumMilageChargeOutput.Text = FormatCurrency(sngMileageCharge)
lblSumSubTotalOutput.Text = FormatCurrency(sngSubTotal)
lblSumDiscountOutput.Text = FormatCurrency(sngDiscount)
lblSumTotalDueOutput.Text = FormatCurrency(sngTotalDue)
'Displays all counter and accumulator variables after they are updated
lblTotalRidesOutput.Text = msngNumberOfRides
lblFrequentFlyersOutput.Text = msngNumberOfFrequentFlyers
lblRevenueOutput.Text = FormatCurrency(msngRevenue)
lblTotalDiscountsOutput.Text = FormatCurrency(msngTotalDiscounts)
lblBillableMilesOutput.Text = msngBillableMiles
End Sub
Firstly as mentioned above you'll need to remove the quotes around the 0.1 in your if statement, this won't work as it's comparing a number to a string.
I'm no expert on floating-point arithmetic, but as Plutonix alludes to, I think the problem when you tried it without quotes is that the 0.1 you're comparing your msngDiscountRate in the if statement defaults to a Double, whereas you've declared your variable as a Single, so the if statement evaluates to false.
You could either declare your msngDiscountRate variable as Double instead, or cast the 0.1 to a Single to get around it. These simple examples might help -
'Variable declared as a Single, compared to 0.1 (a Double) - If statement evaluates to false
Dim msngDiscountRateExample1 As Single = -1
msngDiscountRateExample1 = 0.1
If msngDiscountRateExample1 = 0.1 Then
Debug.Print(msngDiscountRateExample1.ToString)
End If
'Variable declared as a Double, compared to 0.1 (another Double) - If statement evaluates to true
Dim msngDiscountRateExample2 As Double = -1
msngDiscountRateExample2 = 0.1
If msngDiscountRateExample2 = 0.1 Then
Debug.Print(msngDiscountRateExample2.ToString)
End If
'Variable declared as a Single, compared to 0.1 (a Double) which is *cast* as a Single - If statement evaluates to true
Dim msngDiscountRateExample3 As Single = -1
msngDiscountRateExample3 = 0.1
If msngDiscountRateExample3 = CSng(0.1) Then
Debug.Print(msngDiscountRateExample3.ToString)
End If

String.compare returns true when strings aren't equal?

I've seen plenty of questions here about strings that are equal returning as unequal, but trust me to not get that problem.
I have this function.
Protected Sub ChkValidStockCode()
If Not (Voucher.ValidStockCode = "") Then
Dim validcount As Int32 = 0
Dim validproduct As String = Product.GetProductNameByCode(Voucher.ValidStockCode)
For Each rpi As RepeaterItem In rptCart.Items
Dim ProductID As HyperLink = CType(rpi.FindControl("hlProductID"), HyperLink)
Dim ProductName As HyperLink = CType(rpi.FindControl("hlProductName"), HyperLink)
If (String.Compare(Voucher.ValidStockCode.ToString(), ProductID.ToString())) Then
validcount = validcount + 1
End If
Next
If validcount = 0 Then
txtVoucher.Text = "Sorry, this voucher is only valid when purchasing a " & validproduct
failed = True
Exit Sub
End If
End If
End Sub
It's supposed to compare the two strings and increment a validcount integer if they're equal, and then tell you off if it gets to the end of the repeater without finding any matches.
The variables in this test are LT00004 (Voucher.ValidStockCode) and SP08076 (ProductID.ToString())
I have run the code several times, outputting the different strings as the result and can confirm they are what they should be, but when I try to compare them (and I expect validCount to be 0), they return as a match.
What did I do to screw this up?
You probably want String.Equals() and not String.Compare(). Compare is used to order things and not test for equality. What's happening is String.Compare is returning a non-zero number so the condition is being satisfied. The reason for that is because in VB "0" is False but any non-zero number evaluates to true. There's a whole history behind why that's the case but I digress.

vb.net string contains only 4 digit numbers(or a year)

how can i check if a string only contains 4 digit numbers ( or a year )
i tried this
Dim rgx As New Regex("^/d{4}")
Dim number As String = "0000"
Console.WriteLine(rgx.IsMatch(number)) // true
number = "000a"
Console.WriteLine(rgx.IsMatch(number)) // false
number = "000"
Console.WriteLine(rgx.IsMatch(number)) //false
number = "00000"
Console.WriteLine(rgx.IsMatch(number)) // true <<< :(
this returns false when its less than 4 or at characters but not at more than 4
thanks!
I actually wouldn't use a regex for this. The expression is deceptively simple (^\d{4}$), until you realize that you also need to evaluate that numeric value to determine a valid year range... unless you want years like 0013 or 9015. You're most likely going to want the value as an integer in the end, anyway. Given that, the best validation is probably just to actually try to convert it to an integer right off the bat:
Dim numbers() As String = {"0000", "000a", "000", "00000"}
For Each number As String In numbers
Dim n As Integer
If Integer.TryParse(number, n) AndAlso number.Length = 4 Then
'It's a number. Now look at other criteria
End If
Next
Use LINQ to check if All characters IsDigit:
Dim result As Boolean = ((Not number Is Nothing) AndAlso ((number.Length = 4) AndAlso number.All(Function(c) Char.IsDigit(c))))
You should use the .NET string manipulation functions.
Firstly the requirements, the string must:
Contain exactly four characters, no more, no less;
Must consist of a numeric value
However your aim is to validate a Date:
Function isKnownGoodDate(ByVal input As String) As Boolean 'Define the function and its return value.
Try 'Try..Catch statement (error handling). Means an input with a space (for example ` ` won't cause a crash)
If (IsNumeric(input)) Then 'Checks if the input is a number
If (input.Length = 4) Then
Dim MyDate As String = "#01/01/" + input + "#"
If (IsDate(MyDate)) Then
Return True
End If
End If
End If
Catch
Return False
End Try
End Function
You may experience a warning:
Function isKnownGoodDate does not return a value on all code
paths. Are you missing a Return statement?
this can be safely ignored.