-
Dec 6th, 2022, 10:10 PM
#1
Thread Starter
Hyperactive Member
[RESOLVED] How to make a TextBox accept only numbers, decimal separator and minus sign?
Hello!
I'm trying to make a textBox with the following acceptance requirements:
- positive numbers.
- negative numbers.
- decimal separator (occurring only once)
- minus sign (occurring only once)
- Don't allow the minus sign after a number eg. 7.5-2
Right now, I almost got it with following code under the KeyPress event of the textBox, but the minus sign still can be entered more than once, and it can also be entered after a number.
VB.NET Code:
Dim DecimalSeparator As String = Application.CurrentCulture.NumberFormat.NumberDecimalSeparator
If Not IsNumeric(e.KeyChar) AndAlso Convert.ToByte(e.KeyChar) <> 8 AndAlso Convert.ToByte(e.KeyChar) <> 45 Then
e.Handled = Not (e.KeyChar = DecimalSeparator And DirectCast(sender, TextBox).Text.IndexOf(DecimalSeparator) = -1)
End If
I need some help here, please.
-
Dec 6th, 2022, 10:21 PM
#2
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
The first option would be to use a NumericUpDown instead of a TextBox, although that may not be appropriate in all circumstances. Beyond that, you can't really do this properly with a standard TextBox and handling events. If nothing else, you can't really prevent invalid data being pasted in unless you also prevent valid data being pasted in.
The solution is to use a custom control. That allows you to build in functionality like you're now putting in the form but it also allows code that you can't easily put in the form. Many people have created such custom TextBoxes. Here's mine:
https://www.vbforums.com/showthread....meric-Text-Box
If you look through that code, you'll see some of the reasons that a rigorous implementation is hard to impossible using a standard control.
-
Dec 7th, 2022, 02:51 AM
#3
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Originally Posted by jmcilhinney
…If nothing else, you can't really prevent invalid data being pasted in unless you also prevent valid data being pasted in.
??? Does tend to be so
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Dec 7th, 2022, 02:55 AM
#4
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Originally Posted by .paul.
??? Does tend to be so
I've reread that a couple of times and it looks OK to me. Did you misread it? Note that I say "invalid data" the first time and "valid data" the second time. Basically, it's either let all data be pasted or none.
-
Dec 7th, 2022, 02:57 AM
#5
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Try this… (it handles pasting only valid numbers)
Code:
Public Class numericTextbox
Inherits TextBox
Const WM_PASTE As Integer = &H302
Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
Dim strText As String = Me.Text
strText = strText.Remove(Me.SelectionStart, Me.SelectionLength)
strText = strText.Insert(Me.SelectionStart, e.KeyChar)
e.Handled = CBool(strText.LastIndexOf("-") > 0) Or Not (Char.IsControl(e.KeyChar) OrElse Char.IsDigit(e.KeyChar) OrElse (e.KeyChar = "."c And Not Me.Text.Contains(".") Or e.KeyChar = "."c And Me.SelectedText.Contains(".")) OrElse (e.KeyChar = "-"c And Me.SelectionStart = 0))
MyBase.OnKeyPress(e)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg = WM_PASTE Then
Dim strText As String = Me.Text
strText = strText.Remove(Me.SelectionStart, Me.SelectionLength)
strText = strText.Insert(Me.SelectionStart, Clipboard.GetText)
Dim result As Decimal = 0
If Not Decimal.TryParse(strText, result) Then
Return
End If
End If
MyBase.WndProc(m)
End Sub
End Class
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Dec 7th, 2022, 02:59 AM
#6
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Originally Posted by jmcilhinney
I've reread that a couple of times and it looks OK to me. Did you misread it? Note that I say "invalid data" the first time and "valid data" the second time. Basically, it's either let all data be pasted or none.
Yeah I just re-read it. You’re right, I didn’t catch you with a horrendous blooper, but it is possible to restrict pasting…
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Dec 7th, 2022, 03:46 AM
#7
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Originally Posted by .paul.
it is possible to restrict pasting…
With a standard TextBox? I know that it can be done with a custom control but that was my point: it's better to use a custom control because there's no easy way to use a standard TextBox and do a proper job.
-
Dec 7th, 2022, 03:50 AM
#8
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
For the record, here's my SimpleNumberBox class from the CodeBank:
vb.net Code:
Imports System.Globalization
Public Class SimpleNumberBox
Inherits System.Windows.Forms.TextBox
Private Const WM_PASTE As Integer = &H302
Protected Overrides Sub OnKeyPress(ByVal e As System.Windows.Forms.KeyPressEventArgs)
Dim keyChar = e.KeyChar
Dim formatInfo = NumberFormatInfo.CurrentInfo
If Char.IsControl(keyChar) OrElse _
Char.IsDigit(keyChar) OrElse _
((keyChar = formatInfo.NegativeSign OrElse _
keyChar = formatInfo.NumberDecimalSeparator) AndAlso _
Me.ValidateText(keyChar)) Then
MyBase.OnKeyPress(e)
Else
e.Handled = True
End If
End Sub
Protected Overrides Sub OnValidated(ByVal e As System.EventArgs)
If Not Decimal.TryParse(Me.Text, New Decimal) Then
Me.Clear()
End If
MyBase.OnValidated(e)
End Sub
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If m.Msg <> WM_PASTE OrElse _
Not Clipboard.ContainsText() OrElse _
Me.ValidateText(Clipboard.GetText()) Then
MyBase.WndProc(m)
End If
End Sub
Private Function ValidateText(ByVal newText As String) As Boolean
Dim isValid = True
Dim currentText = Me.Text
Dim selectionStart = Me.SelectionStart
Dim proposedText = currentText.Substring(0, selectionStart) & _
newText & _
currentText.Substring(selectionStart + Me.SelectionLength)
If Not Decimal.TryParse(proposedText, _
NumberStyles.AllowLeadingSign Or NumberStyles.AllowDecimalPoint, _
Nothing, _
New Decimal) Then
Dim formatInfo = NumberFormatInfo.CurrentInfo
Dim negativeSign = formatInfo.NegativeSign
Dim decimalSeparator = formatInfo.NumberDecimalSeparator
isValid = (proposedText = negativeSign) OrElse _
(proposedText = decimalSeparator) OrElse _
(proposedText = negativeSign & decimalSeparator)
End If
Return isValid
End Function
End Class
Fairly rigorous but not as fancy as the more fully-featured NumberBox class.
-
Dec 7th, 2022, 06:15 AM
#9
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Originally Posted by jmcilhinney
With a standard TextBox? I know that it can be done with a custom control but that was my point: it's better to use a custom control because there's no easy way to use a standard TextBox and do a proper job.
to restrict paste I use ShortcutsEnabled ..
Code:
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Me.TextBox1.ShortcutsEnabled = False
End Sub
Private Sub TextBox1_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
If e.KeyChar = "."c Then
'only one allowed
e.Handled = (CType(sender, TextBox).Text.IndexOf("."c) <> -1)
ElseIf e.KeyChar = "-"c Then
'only one allowed
e.Handled = (CType(sender, TextBox).Text.IndexOf("-"c) <> -1)
'Backspace
ElseIf e.KeyChar <> ControlChars.Back Then
e.Handled = ("0123456789".IndexOf(e.KeyChar) = -1) '<--allowed
End If
End Sub
to hunt a species to extinction is not logical !
since 2010 the number of Tigers are rising again in 2016 - 3900 were counted. with Baby Callas it's 3901, my wife and I had 2-3 months the privilege of raising a Baby Tiger.
-
Dec 7th, 2022, 06:30 AM
#10
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Originally Posted by ChrisE
to restrict paste I use ShortcutsEnabled ..
Code:
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
Me.TextBox1.ShortcutsEnabled = False
End Sub
Private Sub TextBox1_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
If e.KeyChar = "."c Then
'only one allowed
e.Handled = (CType(sender, TextBox).Text.IndexOf("."c) <> -1)
ElseIf e.KeyChar = "-"c Then
'only one allowed
e.Handled = (CType(sender, TextBox).Text.IndexOf("-"c) <> -1)
'Backspace
ElseIf e.KeyChar <> ControlChars.Back Then
e.Handled = ("0123456789".IndexOf(e.KeyChar) = -1) '<--allowed
End If
End Sub
The point is, with a custom control, you can allow valid pasting instead of disallowing all pasting…
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
-
Dec 7th, 2022, 01:55 PM
#11
Thread Starter
Hyperactive Member
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
In my case disallowing all pasting is perfectly fine, since I don't want the user to paste anything into the TextBox. this redices many problems.
-
Dec 7th, 2022, 06:30 PM
#12
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Originally Posted by Spybot
In my case disallowing all pasting is perfectly fine, since I don't want the user to paste anything into the TextBox. this redices many problems.
It's your app but, I have to say, it really annoys me if I can't paste valid data into a text field.
-
Dec 8th, 2022, 06:27 PM
#13
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Originally Posted by jmcilhinney
It's your app but, I have to say, it really annoys me if I can't paste valid data into a text field.
Well, then it's good thing it isn't a text field but a numeric field. :P
Honestly IO've gotten to the point where I no longer care about what a user types or pastes in, and only do checks either on exit of the field, or when submit button is clicked. There are more important things in life where I don't need (or care) to try to come up with all the different ways a user might type or paste something in.
-tg
-
Dec 9th, 2022, 11:54 AM
#14
Thread Starter
Hyperactive Member
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
As for the negative sign between numbers. I used this code:
VB.NET Code:
If TextBox8.Text.IndexOf("-") <> -1 Then
Dim TxtBoxLength As Integer = TextBox1.Text.Length
Dim dIndex As Integer = TextBox1.Text.IndexOf("-")
If dIndex <> 0 And TxtBoxLength >= 2 Then
'Error sound
Console.Beep(2500, 120)
Console.Beep(2000, 120)
Else
'Proceed...
End If
End If
I appreciate the time you spend to answer my question.
I got many ideas to solve this problem from you.
Thank you all!
-
Dec 9th, 2022, 01:08 PM
#15
Re: [RESOLVED] How to make a TextBox accept only numbers, decimal separator and minus
You could have written that far more compactly such that it would run more efficiently. It also seems to have a significant bug in it. You check TextBox8 in the first If statement, then work with TextBox1 for everything else. If there's a reason for that, such that TextBox8 SHOULD be checked before checking TextBox1, then some of the other points I'd make are irrelevant, but that seems like a bug.
1) Using the default names for the controls is a path to madness. Madness is not a destination most people are seeking.
2) You end up checking that IndexOf twice, assuming the name of the textbox is a bug. That's a costly waste, but since computers are so fast, you'll never see that cost. Calling Contains might be faster, but even if it isn't, you should...maybe...retain the result of the first IndexOf so that you can use it later. After all, it's a short line of code, but what has to happen is that each character is examined to see if it is the one you are looking for, so that short line of code hides a loop.
3) You should be aware of, and making use of, AndAlso rather than And. AndAlso shortcircuits evaluation, so you could do this:
Code:
If TextBox1.Text.Length>=2 AndAlso TextBox1.Text.IndexOf("-") > 0 Then
The second part won't even happen if the Length is shorter than 2. If the length is shorter than 2, then the overall condition MUST evaluate to False, so checking the second half (which is the costly IndexOf) will be skipped entirely.
4) That code seems like it will fail for a string like: -123-4, and will also fail for --1234. IndexOf will return 0, because it returns the first instance of the sought character. So, if the first character is -, it returns 0, which will pass your test. The fact that there are other dashes in the string will be ignored, and yet they are there, so the string is invalid.
5) All the numeric types (and several others) have a TryParse method which will do the job for you, do it correctly, and do it more safely. In this case, you'd want something like Decimal.TryParse or Double.TryParse. The code would look like this:
Code:
Dim d As Double 'You probably don't have a use for this, but it has to be there for the function.
If Double.TryParse(TextBox1.Text,d) Then
'It IS a double, and that double is found in d.
Else
'It is NOT double, so this is where you can beep at the user.
End If
That's all that's needed. No need for IndexOf at all. No need to check the length of the string, either, because this will work for an empty string, for strings with a minus sign in the right place, and strings with dashes in incorrect places. This will also work for multiple decimal points, as well.
My usual boring signature: Nothing
-
Dec 10th, 2022, 12:16 PM
#16
Thread Starter
Hyperactive Member
Re: [RESOLVED] How to make a TextBox accept only numbers, decimal separator and minus
You are completely right.
I didn't see those coming, but this -123-4, and this --1234, will not happen because of the code on post# 9.
Anyway... the tryParse method seems to be cleaner than mine, thank you for your suggestion.
-
Dec 10th, 2022, 01:56 PM
#17
Re: How to make a TextBox accept only numbers, decimal separator and minus sign?
Originally Posted by jmcilhinney
With a standard TextBox? I know that it can be done with a custom control but that was my point: it's better to use a custom control because there's no easy way to use a standard TextBox and do a proper job.
You could hook the clipboard and allow/disallow pasting depending on the clipboard contents…
- Coding Examples:
- Features:
- Online Games:
- Compiled Games:
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|