Event not Firing on First KeyPress - vb.net

I am trying to call a Sub from within the keyPress event in a textBox, the problem is that the Sub will not get called until the second keyPress, at that time the keyPress processes the first key entered, if a third keyPress is done the sub will process the second keyPress and so on... Here is an image;
And here is my code;
Private nonNumberEntered As Boolean = False
Private Sub txtAmount_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles txtAmount.KeyPress
'Only allowed characters
Dim allowedChars As String = "0123456789."
nonNumberEntered = False
If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
If e.KeyChar <> ControlChars.Back Then
If allowedChars.IndexOf(e.KeyChar) = -1 Then
' Invalid Character, notify clear and return
MsgBox("Numbers only", MsgBoxStyle.Exclamation)
txtAmount.Text = ""
txtAmount.Focus()
nonNumberEntered = True
End If
End If
End If
'If shift key was pressed, it's not a number.
If Control.ModifierKeys = Keys.Shift Then
nonNumberEntered = True
End If
'Call the function to create a text line out of the numbers
'Regex to ensure the string contains numbers
Dim re As New Text.RegularExpressions.Regex("\d")
If re.IsMatch(txtAmount.Text) Then
If nonNumberEntered = False Then
Dim newNum = txtAmount.Text.Trim
'If there are any leading weird . in the string
newNum = newNum.TrimStart(".")
Dim newStr As String
'Build the array
Dim newDec As String() = newNum.Split(New Char() {"."c})
If newNum.Contains(".") Then
newStr = NumberToText(newDec(0))
lblResult.Text = newStr & " Dollars and " & newDec(1) & "/100 "
Else
newStr = NumberToText(newDec(0))
lblResult.Text = newStr & " Dollars and 00/100 "
End If
End If
End If
End Sub
Any ideas?

As #jmcilhinney alluded in the comments, you are trying to do too much in the KeyPress event handler. That handler should only be used to allow valid key presses and suppress invalid key presses. Whenever a valid key press is made, it is allowed to go through and then the TextChanged event handler will be called. Setting e.Handled = True will suppress the key press and the TextChanged event will not be called.
Private Sub txtAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox2.KeyPress
'Only allowed characters
Dim allowedChars As String = "0123456789."
If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
If e.KeyChar <> ControlChars.Back Then
If allowedChars.IndexOf(e.KeyChar) = -1 Then
' Invalid Character, notify clear and return
e.Handled = True 'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
MsgBox("Numbers only", MsgBoxStyle.Exclamation)
txtAmount.Text = ""
txtAmount.Focus()
End If
End If
End If
End Sub
Private Sub txtAmount_TextChanged(sender As Object, e As EventArgs) Handles TextBox2.TextChanged
lblResult.Text = NumberToText(txtAmount.Text)
End Sub
Public Function NumberToText(input As String) As String
'Convert value of amount to words here
End Function
You may also wish to look into using a MaskedTextBox which will handle the validation automatically.

Here is what I am using as my solution, might be a bit of a kluge but it works;
Private nonNumberEntered As Boolean = False
Private Sub txtAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtAmount.KeyPress
'Only allowed characters
Dim allowedChars As String = "0123456789."
If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
If e.KeyChar <> ControlChars.Back Then
If allowedChars.IndexOf(e.KeyChar) = -1 Then
' Invalid Character, notify clear and return
nonNumberEntered = True 'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
MsgBox("Numbers only", MsgBoxStyle.Exclamation)
txtAmount.Text = ""
txtAmount.Focus()
lblResult.Text = ""
End If
End If
End If
'If shift key was pressed, it's not a number.
If Control.ModifierKeys = Keys.Shift Then
nonNumberEntered = True
txtAmount.Text = ""
txtAmount.Focus()
End If
End Sub
Private Sub txtAmount_TextChanged(sender As Object, e As EventArgs) Handles txtAmount.TextChanged
'Call the function to create a text line out of the numbers
'Regex to ensure the string contains numbers
Dim t As TextBox = sender
Dim foo As Decimal
If Decimal.TryParse(txtAmount.Text, foo) Then
'data is good
Dim re As New Text.RegularExpressions.Regex("\d")
If re.IsMatch(txtAmount.Text) Then
If nonNumberEntered = False Then
Dim newNum = txtAmount.Text.Trim
'If there are any leading weird . in the string
newNum = newNum.TrimStart(".")
Dim newStr As String
'Build the array
Dim newDec As String() = newNum.Split(New Char() {"."c})
If newNum.Contains(".") Then
newStr = NumberToText(newDec(0))
lblResult.Text = newStr & " Dollars and " & newDec(1) & "/100 "
Else
newStr = NumberToText(newDec(0))
lblResult.Text = newStr & " Dollars and 00/100 "
End If
End If
End If
Else
'data is bad
nonNumberEntered = False
txtAmount.Text = ""
txtAmount.Focus()
lblResult.Text = ""
End If
End Sub
Note that in the textChanged I am checking to see if the value is actually a number, if ot, clear contents and keep going. In textChanged I also allow a decimal point, but nothing else, and then I clear everything making the user start over. Simple, yet effective......

Ok Chris, you were close. What I needed to do was set e.KeyChar = "" and then trap the and in KeyPress. So here is my final solution that is working as intended.
Private Sub cbCheckAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles cbCheckAmount.KeyPress
'Only allowed characters
Dim allowedChars As String = "0123456789."
If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
If e.KeyChar <> ChrW(Keys.Return) Or e.KeyChar <> ChrW(Keys.Tab) Then
If e.KeyChar <> ControlChars.Back Or e.KeyChar <> ControlChars.Tab Then
If allowedChars.IndexOf(e.KeyChar) = -1 Then
' Invalid Character, notify clear and return
nonNumberEntered = True 'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
MsgBox("Numbers only", MsgBoxStyle.Exclamation)
cbCheckAmount.Text = ""
cbCheckAmount.Focus()
lblTotalText.Text = ""
e.KeyChar = ""
nonNumberEntered = False
End If
End If
End If
End If
'If shift key was pressed, it's not a number.
If Control.ModifierKeys = Keys.Shift Then
nonNumberEntered = True
cbCheckAmount.Text = ""
cbCheckAmount.Focus()
End If
End Sub
Private Sub cbCheckAmount_TextChanged(sender As Object, e As EventArgs) Handles cbCheckAmount.TextChanged
'Call the function to create a text line out of the numbers
'Regex to ensure the string contains numbers
Dim t As ComboBox = sender
Dim foo As Decimal
If nonNumberEntered = False Then
If Decimal.TryParse(cbCheckAmount.Text, foo) Then
'data is good
Dim re As New Text.RegularExpressions.Regex("\d")
If re.IsMatch(cbCheckAmount.Text) Then
If nonNumberEntered = False Then
Dim newNum = cbCheckAmount.Text.Trim
'If there are any leading weird . in the string
newNum = newNum.TrimStart(".")
Dim newStr As String
'Build the array
Dim newDec As String() = newNum.Split(New Char() {"."c})
If newNum.Contains(".") Then
newStr = NumberToText(newDec(0))
lblTotalText.Text = newStr & " Dollars and " & newDec(1) & "/100 "
Else
newStr = NumberToText(newDec(0))
lblTotalText.Text = newStr & " Dollars and 00/100 "
End If
End If
End If
End If
Else
'data is bad
nonNumberEntered = True
cbCheckAmount.Text = ""
'cbCheckAmount.Focus()
'lblTotalText.Text = ""
End If
End Sub

Related

Catching a [Tab] or [Enter] on KeyPress Event

Is it possible to catch the Enter or Tab key in the KeyPress Event?
I am entering a numeric only value on a comboBox, but once this value has been validated I want the user to be able to either Tab or Enter out of the CB once validated, is this possible from within the keyPress? Here's my code;
Private Sub cbCheckAmount_KeyPress(sender As Object, e As KeyPressEventArgs) Handles cbCheckAmount.KeyPress
'Only allowed characters
Dim allowedChars As String = "0123456789."
If Char.IsDigit(e.KeyChar) = False And Char.IsControl(e.KeyChar) = False Then
If e.KeyChar <> ControlChars.Back Then
If allowedChars.IndexOf(e.KeyChar) = -1 Then
' Invalid Character, notify clear and return
nonNumberEntered = True 'Set to True to 'swallow' the keypress and prevent the TextChanged event from firing.
MsgBox("Numbers only", MsgBoxStyle.Exclamation)
cbCheckAmount.Text = ""
cbCheckAmount.Focus()
cbDollarAmount.Text = ""
End If
End If
End If
'If shift key was pressed, it's not a number.
If Control.ModifierKeys = Keys.Shift Then
nonNumberEntered = True
cbCheckAmount.Text = ""
cbCheckAmount.Focus()
End If
End Sub
Private Sub cbCheckAmount_TextChanged(sender As Object, e As EventArgs) Handles cbCheckAmount.TextChanged
'Call the function to create a text line out of the numbers
'Regex to ensure the string contains numbers
Dim t As ComboBox = sender
Dim foo As Decimal
If Decimal.TryParse(cbCheckAmount.Text, foo) Then
'data is good
Dim re As New Text.RegularExpressions.Regex("\d")
If re.IsMatch(cbCheckAmount.Text) Then
If nonNumberEntered = False Then
Dim newNum = cbCheckAmount.Text.Trim
'If there are any leading weird . in the string
newNum = newNum.TrimStart(".")
Dim newStr As String
'Build the array
Dim newDec As String() = newNum.Split(New Char() {"."c})
If newNum.Contains(".") Then
newStr = NumberToText(newDec(0))
cbDollarAmount.Text = newStr & " Dollars and " & newDec(1) & "/100 "
Else
newStr = NumberToText(newDec(0))
cbDollarAmount.Text = newStr & " Dollars and 00/100 "
End If
End If
End If
Else
'data is bad
nonNumberEntered = False
cbCheckAmount.Text = ""
cbCheckAmount.Focus()
cbDollarAmount.Text = ""
End If
End Sub
I'm using VB 2015
Stop and listen. The problem you're trying to solve doesn't exist. Just do it properly in the first place. Handle the Validating event of each control and do your validation there. If validation fails, set e.Cancel to True and the control will retain focus. In the Click event handler of your OK Button or whatever, call the ValidateChildren method and that will raise the Validating event on every control, even if it never received focus. If any controls fail validation, ValidateChildren returns False and you know not to try to use the data. E.g.
Private Sub TextBox1_Validating(sender As Object, e As CancelEventArgs) Handles TextBox1.Validating
Dim value = TextBox1.Text.Trim()
'Data is optional but must be numeric if provided.
If value <> String.Empty AndAlso Not Double.TryParse(value, Nothing) Then
TextBox1.SelectAll()
TextBox1.HideSelection = False
MessageBox.Show("If data is provided, it must be numeric", "Invalid Data", MessageBoxButtons.OK, MessageBoxIcon.Error)
TextBox1.HideSelection = True
e.Cancel = True
End If
End Sub
Private Sub TextBox2_Validating(sender As Object, e As CancelEventArgs) Handles TextBox2.Validating
'Data is required.
If TextBox2.Text.Trim() = String.Empty Then
TextBox2.SelectAll()
TextBox2.HideSelection = False
MessageBox.Show("Data must be provided", "Invalid Data", MessageBoxButtons.OK, MessageBoxIcon.Error)
TextBox2.HideSelection = True
e.Cancel = True
End If
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
If ValidateChildren() Then
'The data has passed validation so it is safe to use it.
End If
End Sub
If i understand correctly isnt what you want just
If e.KeyChar = ChrW(Keys.Return) or e.KeyChar = Keys.Tab Then
''somethign something''
End If

Counter using KeyPress events

First time posting here, although I'm a frequent visitor when I'm looking for answers. I am new to VB and programming.
My problem is this. I had this figured out in VBA, but I want to convert my "program" to a standalone executable with VB (using Visual Studio 2015)
I want to keep track of certain keypresses done on a textbox, and so far I figured out something that works, but it seems messy.
Can anyone think of a better way of doing
Public Class Form1
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs) Handles TextBox1.KeyPress
Select Case UCase(e.KeyChar) 'For capturing keypresses and adding them
Case "W" : Label3.Text = Val(Label3.Text) + 1
Case "R" : Label4.Text = Val(Label4.Text) + 1
End Select
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
TextBox1.Text = "" 'Clears the text box after each keypress
End Sub
Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim WcountA As Integer
Dim RcountA As Integer
Dim WcountB As Integer
Dim RcountB As Integer
Dim Wavg As Single
Dim Ravg As Single
Select Case Button1.Text
Case "Finish A" 'Finishes first count and stores results in labels
WcountA = Convert.ToInt32(Label3.Text)
RcountA = Convert.ToInt32(Label4.Text)
Button1.Text = "Finish B"
Label5.Text = WcountA
Label7.Text = RcountA
TextBox1.Focus()
Label3.Text = ""
Label4.Text = ""
Case "Finish B" 'Finishes second count and stores in labels
WcountB = Convert.ToInt32(Label3.Text)
RcountB = Convert.ToInt32(Label4.Text)
With Button1
.Text = "Finished"
.Enabled = False
End With
Label6.Text = WcountB
Label8.Text = RcountB
Label3.Text = ""
Label4.Text = ""
WcountA = Label5.Text
RcountA = Label7.Text
WcountB = Label6.Text
RcountB = Label8.Text
Wavg = (WcountA + WcountB) / 2
Ravg = (RcountA + RcountB) / 2
MsgBox("W average = " & Wavg & vbNewLine & "R average = " & Ravg)
End Select
End Sub
End Class
On the form I have the textbox that logs the keypress event, labels that increase by 1 with each specific keypess ("W" and "R"), a button that changes its function with each click(finish first count, finish second count) and some labels I had to use to store the first and second count for the final calculation.
Any suggestion will be appreciated.
Thanks in advance!
First of al, you need to take out the counters of the key pres handler like so;
Because they are gone every time the Button1_Click sub ends.
Public Class Form1
Dim WcountA As Integer
Dim RcountA As Integer
Dim WcountB As Integer
Dim RcountB As Integer
Dim Wavg As Single
Dim Ravg As Single
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs) Handles TextBox1.KeyPress
Select Case UCase(e.KeyChar) 'For capturing keypresses and adding them
Case "W" : Label3.Text = Val(Label3.Text) + 1
Case "R" : Label4.Text = Val(Label4.Text) + 1
End Select
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
TextBox1.Text = "" 'Clears the text box after each keypress
End Sub
Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Select Case Button1.Text
Case "Finish A" 'Finishes first count and stores results in labels
WcountA = Convert.ToInt32(Label3.Text)
RcountA = Convert.ToInt32(Label4.Text)
Button1.Text = "Finish B"
Label5.Text = WcountA
Label7.Text = RcountA
TextBox1.Focus()
Label3.Text = ""
Label4.Text = ""
Case "Finish B" 'Finishes second count and stores in labels
WcountB = Convert.ToInt32(Label3.Text)
RcountB = Convert.ToInt32(Label4.Text)
With Button1
.Text = "Finished"
.Enabled = False
End With
Label6.Text = WcountB
Label8.Text = RcountB
Label3.Text = ""
Label4.Text = ""
WcountA = Label5.Text
RcountA = Label7.Text
WcountB = Label6.Text
RcountB = Label8.Text
Wavg = (WcountA + WcountB) / 2
Ravg = (RcountA + RcountB) / 2
MsgBox("W average = " & Wavg & vbNewLine & "R average = " & Ravg)
End Select
End Sub
End Class
This is what I ended up doing, works better and looks cleaner. Thanks Lectere for pointing me to the right path!
Public Class Form1
Dim WcountA As Integer
Dim RcountA As Integer
Dim WcountB As Integer
Dim RcountB As Integer
Dim Wavg As Single
Dim Ravg As Single
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As KeyPressEventArgs) Handles TextBox1.KeyPress
Select Case UCase(e.KeyChar) 'For capturing keypresses and adding them
Case "W" : lblWcount.Text = Val(lblWcount.Text) + 1
Case "R" : lblRcount.Text = Val(lblRcount.Text) + 1
Case Convert.ToChar(13) : Button1_Click(sender, e)
End Select
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
TextBox1.Text = "" 'Clears the text box after each keypress
End Sub
Public Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Select Case Button1.Text
Case "Finish A" 'Finishes first count and stores results in variables
If lblWcount.Text = vbNullString Then 'checks for empty values and treats them as 0
WcountA = 0
Else
WcountA = lblWcount.Text
End If
If lblRcount.Text = vbNullString Then 'checks for empty values and treats them as 0
RcountA = 0
Else
RcountA = lblRcount.Text
End If
Button1.Text = "Finish B"
lbl_1.Text = WcountA
lbl_2.Text = RcountA
TextBox1.Focus()
lblWcount.Text = vbNullString
lblRcount.Text = vbNullString
lblcount.Text = "Count B"
Case "Finish B" 'Finishes second count and stores results in variables
lblcount.Text = vbNullString
If lblWcount.Text = vbNullString Then
WcountB = 0
Else
WcountB = lblWcount.Text
End If
If lblRcount.Text = vbNullString Then
RcountB = 0
Else
RcountB = lblRcount.Text
End If
With Button1
.Text = "Reset"
End With
lbl_3.Text = WcountB
lbl_4.Text = RcountB
lblWcount.Text = vbNullString
lblRcount.Text = vbNullString
Wavg = (WcountA + WcountB) / 2
Ravg = (RcountA + RcountB) / 2
MsgBox("W average = " & Wavg & vbNewLine & "R average = " & Ravg)
Button1.Focus()
Case "Reset" 'Resets values
Dim i As Integer
For i = 1 To 4 'clears labels that start with lbl_ (1 through 4)
Dim myLabel As Label = CType(Controls("lbl_" & i), Label)
myLabel.Text = vbNullString
Next
Initial() ' calls initial form state
End Select
End Sub
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Initial() 'calls initial form state at load up
End Sub
Private Sub Initial() 'initial state sub
lblcount.Text = "Count A"
TextBox1.Focus()
Button1.Text = "Finish A"
End Sub
End Class
I managed to use loops for clearing labels, and also made pressing Enter during the KeyPress event be treated as a button click.
Loving this feeling of accomplishment when I finally figure something out on something new to me! Love pages like this one where one can learn so much!

VB.NET validate the form to check if empty fields or errors exists

So far I have written code to remain Save&Update buttons disabled until user fills all required fields(Textboxes & Comboboxes) in Groupbox, but I also want the Save&Update buttons to remain disabled until user has addressed all errors available in the form e.g Book_Name should not go beyond 50 characters!
I would really appreciate if someone help me in this!
Below is the code that I tried to do so what I have mentioned above but somehow it is not working:
Private Sub ValidateInputs(ByVal Sender As Object, ByVal e As EventArgs)
Dim ctrl As Control
Dim strErrorList As String
strErrorList = ""
For Each ctrl In Me.Controls
If Len(ErrorProvider1.GetError(ctrl)) > 0 Then
strErrorList += ErrorProvider1.GetError(ctrl) & ChrW(10) &
ChrW(13)
End If
Next
If Len(strErrorList) = 0 Then
' Process stuff if no errors
btnsave.Enabled = Not GroupBox1.Controls.OfType(Of TextBox).Any(Function(t) t.Text = String.Empty) And _
Not (cboStaff_id.Text = String.Empty OrElse cboPub_id.Text = String.Empty OrElse cboSub_Code.Text = String.Empty _
OrElse DateTimePicker1.Text = " ")
btnSaveUpdate.Enabled = Not GroupBox1.Controls.OfType(Of ComboBox).Any(Function(cbo) cbo.Text = String.Empty) And _
Not (txtbook_name.Text = String.Empty OrElse txtauthor.Text = String.Empty OrElse txtprice.Text = String.Empty _
OrElse txtrack_no.Text = String.Empty OrElse TxtNo_of_Books.Text = String.Empty OrElse txtvol_no.Text = String.Empty OrElse DateTimePicker1.Text = " ")
btndelete.Enabled = Not (cboISBN.Text = String.Empty)
Else
btnsave.Enabled = False
btnSaveUpdate.Enabled = False
MessageBox.Show(strErrorList, "List Of Errors")
End If
End Sub
Use Error Providers Or Create your own error provider that does the task required for you and for the ISBN textBox say put the MaxLength=13 it will do the task without any error providers or validators, For phone number of email use masked text box, or handle the text change event of the textbox if you want to accept only numbers in that textbox
Since I asked the question 4 days ago and no one provided an answer to solve my problem, I researched & rechecked my code and found solution for my problem!
So I am gonna explain each point to clarify what I have done.
'Below disables numeric entry; only characters and spaces allowed with the help of ASCII values
Private Sub txtbook_name_KeyPress(sender As Object, e As KeyPressEventArgs) Handles txtbook_name.KeyPress
If Not (Asc(e.KeyChar) = 8) Then
If Not ((Asc(e.KeyChar) >= 97 And Asc(e.KeyChar) <= 122) _ Or (Asc(e.KeyChar) >= 65 _
And Asc(e.KeyChar) <= 90) _
Or (Asc(e.KeyChar) = 32)) Then
e.KeyChar = ChrW(0)
e.Handled = True
End If
End If
End Sub
'Bellow function return only true if input matches Regex pattern in other cases false
Private Function ValidBook_name(ByVal book_name As String, ByRef errorMessage As String) As Boolean
Dim regex As New System.Text.RegularExpressions.Regex("^[a-zA-Z ]{1,50}$")
' Confirm there is text in the control.
If txtbook_name.Text.Length = 0 Then
errorMessage = "Book Name is required"
Return False
End If
If txtbook_name.Text.Length > 50 Then
errorMessage = "Book Name can not be more than 50"
Return False
End If
'Confirm that book name is in character not number
If (regex.IsMatch(Trim(txtbook_name.Text))) Then
errorMessage = ""
Return True
End If
errorMessage = "A valid Book Name is required" + ControlChars.Cr
Return False
End Function
'Check whether input entered is valid or not; if not return cursor to control
Private Sub txtbook_name_Validating(ByVal sender As Object, _
ByVal e As System.ComponentModel.CancelEventArgs) Handles txtbook_name.Validating
Dim errorMsg As String
Try
If Not ValidBook_name(txtbook_name.Text, errorMsg) Then
' Cancel the event and select the text to be corrected by the user.
e.Cancel = True
txtbook_name.Select(0, txtbook_name.Text.Length)
' Set the ErrorProvider error with the text to display.
Me.ErrorProvider1.SetError(txtbook_name, errorMsg)
End If
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Private Sub txtbook_name_Validated(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles txtbook_name.Validated
' If all conditions have been met, clear the error provider of errors.
Try
ErrorProvider1.SetError(txtbook_name, "")
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Sub
Hope this helps...

How to check if text box max length has been exceeded?

My problem:
I'm limiting a text box to 8 characters and showing a tooltip when it's exceeded (>8) rather than reached (=8). Using the .Maxlength function prevents the user from ever exceeding 8 characters so my >8 function is never fulfilled.
If I forgo the .Maxlength function and instead use .Substring to limit the input, my >8 function is fulfilled however the behavior differs from .Substring (the last rather than first 8 inputs are kept and I lose the alert sound).
It would a lot cleaner to be able to check for whenever .Maxlength is exceeded without affecting the first 8 inputs.
To reproduce:
In Visual Studio, in design mode, drag a text box and tooltip onto a fresh form.
Use the following as is:
Code:
Public Class Form1
Private Sub Textbox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged
TextBox1.MaxLength = 8
If (Not IsNumeric(TextBox1.Text) And TextBox1.Text.Length > 0) Then
If ToolTip1.GetToolTip(TextBox1) = "" Then
ToolTip1.ToolTipTitle = "Input must be numeric!"
ToolTip1.Active = True
ToolTip1.IsBalloon = True
ToolTip1.ToolTipIcon = ToolTipIcon.Warning
ToolTip1.Show(vbNewLine, TextBox1, 45, -40)
End If
ElseIf TextBox1.Text.Length > 8 Then
'TextBox1.Text = TextBox1.Text.Substring(0, 8)
ToolTip1.IsBalloon = True
ToolTip1.ToolTipTitle = "8 character maximum!"
ToolTip1.Active = True
ToolTip1.ToolTipIcon = ToolTipIcon.Warning
ToolTip1.Show(vbNewLine, TextBox1, 45, -40)
Else
ToolTip1.Active = False
ToolTip1.Hide(TextBox1)
End If
End Sub
End Class
When you replace the text, it resets the caret, so move it back into place at the end:
TextBox1.Text = TextBox1.Text.Substring(0, 8)
TextBox1.Select(TextBox1.TextLength, 0)
It is better to supress the key if it is invalid:
Private Sub TextBox1_KeyPress(sender As System.Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
Dim str As String
str = TextBox1.Text
str = str.Insert(TextBox1.SelectionStart, CStr(e.KeyChar))
If e.KeyChar = ChrW(Keys.Back) Then
HideToolTip()
ElseIf str.Length > 8 Then
ShowToolTip("8 character maximum!")
e.Handled = True
ElseIf Not IsNumeric(str) Then
ShowToolTip("Input must be numeric!")
e.Handled = True
Else
HideToolTip()
End If
End Sub
Private Sub HideToolTip()
If ToolTip1.GetToolTip(TextBox1) <> "" Then
ToolTip1.Active = False
ToolTip1.Hide(TextBox1)
End If
End Sub
Private Sub ShowToolTip(ByVal str As String)
'always check if tooltip is visible, to avoid inversion
If ToolTip1.GetToolTip(TextBox1) = "" Then
ToolTip1.ToolTipTitle = str
ToolTip1.Active = True
ToolTip1.IsBalloon = True
ToolTip1.ToolTipIcon = ToolTipIcon.Warning
ToolTip1.Show(vbNewLine, TextBox1, 45, -40, 1000)
End If
End Sub
EDIT
There is a minor "bug" in IsNumeric() function as it allows numeric with spaces and multiple "."
8..888 'is numeric
.9999 'is numeric
To solve everything:
Private Sub TextBox1_KeyPress(sender As System.Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
Dim str As String = "0123456789."
If e.KeyChar = ChrW(Keys.Back) Then
HideToolTip()
ElseIf TextBox1.Text.Length = 8 Then
ShowToolTip("8 character maximum!")
e.Handled = True
ElseIf e.KeyChar = "." And (TextBox1.Text.Contains(".") Or TextBox1.SelectionStart = 0) Then 'supress a second "." or a first one
ShowToolTip("Input must be numeric!")
e.Handled = True
ElseIf Not str.Contains(CStr(e.KeyChar)) Then
ShowToolTip("Input must be numeric!")
e.Handled = True
Else
HideToolTip()
End If
End Sub
Add this after the substring call
TextBox1.SelectionStart = 8

How to only allow digits and dots in a textbox?

I'm wondering how I can get my textbox to only accept digits and dots, like:
123.45
or 115
or 218.16978
etc.
I already have the following code:
Private Sub TxtHStof_KeyPress(ByVal sender As System.Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TxtHStof.KeyPress
e.Handled = Not Char.IsDigit(e.KeyChar)
End Sub
But that only allows digits without the dots.
How can I change the code so it does allows the dots as well, but nothing else?
e.Handled = Not (Char.IsDigit(e.KeyChar) OR e.KeyChar=".")
The accepted solution doesn't cater for
Multiple entries of decimals for example "12....1234"
OS specific decimal separators
This works for me
Private Sub TextBox1_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox1.KeyPress
Dim DecimalSeparator As String = Application.CurrentCulture.NumberFormat.NumberDecimalSeparator
e.Handled = Not (Char.IsDigit(e.KeyChar) Or
Asc(e.KeyChar) = 8 Or
(e.KeyChar = DecimalSeparator And sender.Text.IndexOf(DecimalSeparator) = -1))
End Sub
You should use a MaskedTextBox - see here on how to set the format string (which allows you to restrict to digits and decimal point only)
http://msdn.microsoft.com/en-us/library/system.windows.forms.maskedtextbox.mask.aspx
With this code you can use ',' (Europe) and '.' (American) decimals.
Private Sub TGewicht_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TGewicht.KeyPress
e.Handled = Not (Char.IsDigit(e.KeyChar) Or Asc(e.KeyChar) = 8 Or ((e.KeyChar = "." Or e.KeyChar = ",") And (sender.Text.IndexOf(".") = -1 And sender.Text.IndexOf(",") = -1)))
End Sub
'****To Allow only Numbers with Decimal and BACKSPACE enabled****
If Not (Char.IsDigit(e.KeyChar) Or e.KeyChar = ".") And Not Char.IsControl(e.KeyChar) Then
e.Handled = True
End If
Coming from C# and not VB, I'm taking a stab at this, but would this work:
e.Handled = Not (Char.IsDigit(e.KeyChar) AndAlso e.KeyChar.Equals('.'))
Insert function in MODULE o FORM
Public Sub OnlyNumber(Ct As TextBox, MaxLength As Integer)
Ct.MaxLength = MaxLength
AddHandler Ct.KeyPress, AddressOf ValidarTeclaNumeros
End Sub
Private Sub ValidarTeclaNumeros(sender As Object, e As KeyPressEventArgs)
Dim Ct As TextBox
Ct = sender
If [Char].IsDigit(e.KeyChar) OrElse [Char].IsControl(e.KeyChar) Then
'ok
'e.Handled = True
ElseIf [Char].IsPunctuation(e.KeyChar) Then
If (Ct.Text.Contains(",") OrElse Ct.Text.Contains(".")) Then
e.Handled = True
End If
Else
e.Handled = True
End If
End Sub
In load form add this code for your control only numerical (and only one comma or doc)
OnlyNumber(txtControl, 10)
I started with mostly the same question, but I did care about being able to paste. While searching on the web for how to do this, I found that I really should handle:
Periods or commas as the decimal indicator, depending on how your OS is set up.
Only allowing keypresses that conform to the pattern, while still allowing cursor control characters like arrows and backspace.
Only allowing pastes into the TextBox that conform to the pattern. I chose to this in a manner that, when pasting, the code treats the pasted text as if the text was being keyed in, so pasting "a1b.c2d,e3f.g4h,i5j" into the TextBox would show up as "1.2345" if periods are your decimal indicator, and "12,345" if commas are your decimal indicator.
I tried the MaskedTextBox and really did not like it, as it enforced the decimal point location where I really just wanted to be able to freely fill in any numeric. I may have gone a little overboard using a RegEx for the pattern matching, but now I should be able to reuse this code pretty much anywhere.
Public Class frmMain
Dim RegexValidator As System.Text.RegularExpressions.Regex
Dim FormLoaded As Boolean = False
Private Sub frmMain_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim RegexDecimalPattern As String = Globalization.CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator
RegexDecimalPattern = IIf(RegexDecimalPattern = ".", "\.", RegexDecimalPattern)
RegexValidator = New System.Text.RegularExpressions.Regex("^\d*" & RegexDecimalPattern & "?\d*$", System.Text.RegularExpressions.RegexOptions.IgnoreCase)
FormLoaded = True
End Sub
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
' Code below is based on
' http://www.vbforums.com/showthread.php?626378-how-to-validate-textbox-allows-only-numeric-and-decimal-in-vb-net
' but was modified to be based on Regex patterns.
'
' Note that:
' KeyPress event validation covers data entry as it is being typed.
' TextChanged event validation covers data entry by cut/pasting.
If Char.IsControl(e.KeyChar) Then
'Allow all control characters.
Else
Dim Text = Me.TextBox1.Text
Dim SelectionStart = Me.TextBox1.SelectionStart
Dim SelectionLength = Me.TextBox1.SelectionLength
Text = Text.Substring(0, SelectionStart) & e.KeyChar & Text.Substring(SelectionStart + SelectionLength)
If Not RegexValidator.IsMatch(Text) Then e.Handled = True
End If
End Sub
Private Sub TextBox1_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged
' If default text is used in a textbox, a TextChanged event occurs before
' RegexValidator is initialized during the Form Load, so we need to check.
If FormLoaded Then
' Note that:
' KeyPress event validation covers data entry as it is being typed.
' TextChanged event validation covers data entry by cut/pasting.
Dim Text = Me.TextBox1.Text
Dim ValidatedText As String = ""
Dim KeyChar As Char
For Each KeyChar In Text
If RegexValidator.IsMatch(ValidatedText + KeyChar) Then ValidatedText += KeyChar
Next
If (ValidatedText.Length > 0) And (TextBox1.Text <> ValidatedText) Then
Me.TextBox1.Text = ValidatedText
Me.TextBox1.SelectionStart += ValidatedText.Length
End If
End If
End Sub
End Class
im late for the party but here is my code
Private Sub LoanFeeTextBox_KeyPress(sender As Object, e As KeyPressEventArgs) Handles LoanFeeTextBox.KeyPress
If Char.IsControl(e.KeyChar) Then
ElseIf Char.IsDigit(e.KeyChar) OrElse e.KeyChar = "."c Then
If LoanFeeTextBox.TextLength = 12 And LoanFeeTextBox.Text.Contains(".") = False Then
LoanFeeTextBox.AppendText(".")
ElseIf e.KeyChar = "." And LoanFeeTextBox.Text.IndexOf(".") <> -1 Then
e.Handled = True
ElseIf Char.IsDigit(e.KeyChar) Then
If LoanFeeTextBox.Text.IndexOf(".") <> -1 Then
If LoanFeeTextBox.Text.Length >= LoanFeeTextBox.Text.IndexOf(".") + 3 Then
e.Handled = True
End If
End If
End If
Else
e.Handled = True
End If
End Sub
Private Sub TextBox2_KeyPress(
ByVal sender As Object,
ByVal e As System.Windows.Forms.KeyPressEventArgs
) Handles TextBox2.KeyPress
e.Handled = Not (Char.IsDigit(e.KeyChar) Or e.KeyChar = "." Or Asc(e.KeyChar) = 8)
End Sub
Just adding another solution. This code restricts user to entering only one "." decimal point, only two places beyond the decimal point, can set how many digits you want to use (currently I have it set to only allow up to to 5 whole numbers before the decimal. Also allows use of backspace and delete. That way they can't fat finger an extra "." and end up with something like "45.5.5".
If Char.IsControl(e.KeyChar) Then
ElseIf Char.IsDigit(e.keyChar) OrElse e.keyChar = "."c Then
If Amount_FundedTextBox.TextLength = 5 And Amount_FundedTextBox.Text.Contains(".") = False Then
Amount_FundedTextBox.AppendText(".")
ElseIf e.KeyChar = "." And Amount_FundedTextBox.Text.IndexOf(".") <> -1 Then
e.Handled = True
ElseIf Char.IsDigit(e.KeyChar) Then
If Amount_FundedTextBox.Text.IndexOf(".") <> -1 Then
If Amount_FundedTextBox.Text.Length >= Amount_FundedTextBox.Text.IndexOf(".") + 3 Then
e.Handled = True
End If
End If
End If
Else
e.Handled = True
End If
You can restrict character entries in your textboxes by adding a "KeyPress" handler (from TextBox properties) and specifying allowable characters. If the character is "handled" then it is not permitted.
Private Sub TextBox_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox.KeyPress
Dim txt As TextBox = CType(sender, TextBox)
If Not ((Char.IsDigit(e.KeyChar)) Or (e.KeyChar = "E") Or (e.KeyChar = "e") Or (e.KeyChar = "-")) Then e.Handled = True
If e.KeyChar = Chr(8) Then e.Handled = False 'allow Backspace
If e.KeyChar = "." And txt.Text.IndexOf(".") = -1 Then e.Handled = False 'allow single decimal point
If e.KeyChar = Chr(13) Then GetNextControl(txt, True).Focus() 'Enter key moves to next control
End Sub
Private Sub TextBox4_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox4.KeyPress
' its worked for only number with point and worked backspace
If Not Char.IsDigit(e.KeyChar) And Not e.KeyChar = "." Then
e.Handled = True
End If
If e.KeyChar = "." And TextBox4.Text.IndexOf(".") <> -1 Then
e.Handled = True
End If
If e.KeyChar = "." Then
e.Handled = False
End If
If e.KeyChar = Chr(Keys.Back) Then
e.Handled = False
End If
If Char.IsDigit(e.KeyChar) Then
If TextBox4.Text.IndexOf(".") <> -1 Then
If TextBox4.Text.Length >= TextBox4.Text.IndexOf(".") + 3 Then 'replace 2 for greater numbers after decimal point
e.Handled = True
TextBox4.Focus()
End If
End If
End If
' is for only digit with back space
e.Handled = Not Char.IsDigit(e.KeyChar)
If e.KeyChar = Chr(Keys.Back) Then
e.Handled = False
End If
If Char.IsDigit(e.KeyChar) Then
If TextBox4.Text.IndexOf(".") <> -1 Then
If TextBox4.Text.Length >= TextBox4.Text.IndexOf(".") + 3 Then 'replace 2 for greater numbers after decimal point
e.Handled = True
TextBox4.Focus()
End If
End If
End If
End Sub
Dim e As System.Windows.Forms.KeyPressEventArgs
If Asc(e.KeyChar) < 48 Or Asc(e.KeyChar) > 57 Then
e.Handled = True
Else
e.Handled = False
End If