I am using a userform with multiple textbox. I was wondering if there is a way of forcing the user to input a minimum value or higher before moving to the next textbox.
Thanks a lot,
Assuming one of your textboxes is named TextBox1 you can place this code in your userform:
Option Explicit
Dim blnClosing As Boolean
Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
If blnClosing = False Then
Dim iVal As Integer
Dim minVal As Integer
minVal = 10 'Change to your needs
'Test for numeric characters
On Error Resume Next
iVal = CInt(Me.TextBox1.Value)
'If characters are not numeric
If Err.Number = 13 Then
MsgBox "Value must be numeric!", vbCritical, "Incorrect Value"
Me.TextBox1.Text = vbNullString
Cancel = True 'Retain focus on the textbox
Exit Sub
End If
'Reset error handling to normal
On Error GoTo 0
'Check if textbox value is less than the minimum
If Me.TextBox1.Value < minVal Then
MsgBox "Value must be greater than " & minVal & "", vbCritical, "Incorrect Value"
Me.TextBox1.Value = vbNullString
Cancel = True 'Retain focus on the textbox
End If
End If
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
blnClosing = True
End Sub
I took the liberty of checking for a numeric value as well, since you are asking if the value in the textbox appears to be required to be numeric. If that's not the case remove the lines of code from the 'Test for numeric characters comment down to the On ErrorGoTo 0 line.
The global variable blnClosing allows us to skip over the code when the form is closing. If this wasn't included and the user pressed 'X' on the upper right hand corner of the form with invalid data (blank, less than the minimum, or non-numeric) then the messageboxes would show.
Related
Dears,
I am preparing a simple userform to let a teacher to enter each student’s name and height in a class. There are two textboxes (textbox_name and textbox_height) and one “add to record” command button. I tried to make some validation control to prevent empty string to be entered. My validation control is in case textbox is empty, when the click the “add to record” button, the corresponding empty textbox turns pink; and when both textboxes are empty, both textboxes should turn pink, however only the first textbox turns pink in my below codes. Can you tell me why and how to correct it? Thanks.
Private Sub Cmd_addtorecord_Click()
If TextBox_Name = "" Then
TextBox_Name.BackColor = rgbPink
Exit Sub
End If
If TextBox_height = "" Then
TextBox_height.BackColor = rgbPink
Exit Sub
End If
'....
End sub
You can do it like this:
Private Sub Cmd_addtorecord_Click()
'ensure required fields have content
If FlagEmpty(Array(TextBox_Name, TextBox_height)) > 0 Then
MsgBox "One or more required values are missing", vbExclamation
Exit Sub
End If
'....
End Sub
'check required textboxes for content, and flag if empty
' return number of empty textboxes
Function FlagEmpty(arrControls) As Long
Dim i As Long, numEmpty As Long, clr As Long
For i = LBound(arrControls) To UBound(arrControls)
With arrControls(i)
clr = IIf(Len(Trim(.Value)) > 0, vbWhite, rgbPink)
.BackColor = clr
If clr = rngpink Then numEmpty = numEmpty + 1
End With
Loop
FlagEmpty = numEmpty
End Function
You're Exiting the sub before you get to the second textbox. Change your code to something like this:
Private Sub Cmd_addtorecord_Click()
If TextBox_Name = "" or TextBox_height = "" Then
If TextBox_Name = "" Then
TextBox_Name.BackColor = rgbPink
End If
If TextBox_height = "" Then
TextBox_height.BackColor = rgbPink
End If
Exit Sub
End If
'....
End sub
Hi I try this code in my Userform to check if Data entered in textbox1 is a number and if is not show a msgbox to user and select text in textbox1, but below code doesn't select text in textbox1 when Userform is vBModeless
Private Sub TextBox1_Change()
If Not IsNumeric(TextBox1) Then
MsgBox " only number"
TextBox1.SetFocus
TextBox1.SelStart = 0
TextBox1.SelLength = Len(TextBox1.Text)
End If
End Sub
is any solution?
The root of the problem isn't a selection, since it there and works as expected:
Private Sub TextBox1_Change()
If Not IsNumeric(TextBox1) Then
MsgBox " only number"
TextBox1.SetFocus
TextBox1.SelStart = 0
TextBox1.SelLength = Len(TextBox1.Text)
Debug.Print TextBox1.SelText
End If
End Sub
I think the fundamental problem here is that MSForms controls aren't real windows, but "windowless" entity without window handle (of course, there's exceptions like listbox, tabstrip, multipage), which easily can be tested via hidden method:
'Which obviously returns a zero.
Debug.Print TextBox1.[_GethWnd]
In other hand there's the Window's message-passing model where each control is a window (hence Windows OS) with a proper window handle and with ability to send and recive messages like WM_SETFOCUS/WM_KILLFOCUS and act appropriately.
And back to MSForms - the UserForm manages all the interaction between outer world and child controls internally.
Let's start by declaring WIN API function GetFocus:
Public Declare Function GetFocus Lib "user32.dll" () As Long
And let's add some of Debug.Print's to see what is happening:
Private Sub TextBox1_Change()
If Not IsNumeric(TextBox1) Then
Debug.Print "--"
Debug.Print GetFocus
MsgBox " only number"
Debug.Print GetFocus
TextBox1.SetFocus
Debug.Print GetFocus
Debug.Print "--"
TextBox1.SelStart = 0
TextBox1.SelLength = Len(TextBox1.Text)
End If
End Sub
Which yields this sequence:
--
<userform hwnd>
<outer hwnd>
<outer hwnd>
--
As you can see - the SetFocus has no effect, because the Userform has no idea that focus is lost (hence there's no Exit event either). To overcome this problem you should explicitly lose your focus by transferring focus to another child control or by switching Enabled (or even Visible) property:
Private Sub TextBox1_Change()
If Not IsNumeric(TextBox1) Then
Debug.Print "--"
Debug.Print GetFocus
TextBox1.Enabled = False
'or use CommandButton1.SetFocus or something
MsgBox " only number"
TextBox1.Enabled = True
Debug.Print GetFocus
TextBox1.SetFocus
Debug.Print GetFocus
Debug.Print "--"
TextBox1.SelStart = 0
TextBox1.SelLength = Len(TextBox1.Text)
End If
End Sub
Which yields a desired appearance and a proper sequence:
--
<userform hwnd>
<outer hwnd>
<userform hwnd>
--
As a conclusion, the cause is internal and external focus states got out of sync, which stems from a slightly different managment model between MSForms and WinForms/WinAPI plus a non-modal regime of work, that mixes them both, giving an opportunity to lose focus to something non-MSForms.
In my version of Excel A msgbox is always vbModal, it cannot be vbModeless, you can only set its Modal scope property to be as application level or system level
At Application level, it stops the application until it is responded
At system level it suspends all applications until the user responds
to it
In order to do what you intend to do; I have created a Modeless UserForm and use it as a message box
The code becomes
Private Sub TextBox1_Change()
If Not IsNumeric(TextBox1) Then
UserForm2.Label1 = "Only Number is Allowed"
UserForm2.Show
'At this point TextBox1 has lost focus,
'to set the focus again you have to setfocus on something else
'and then again set focus on textbox1 (a way to reinitialize it).
'I have added a hidden textbox2 and will set focus on it
TextBox2.Visible = True
TextBox2.SetFocus
TextBox2.Visible = False
TextBox1.SetFocus
TextBox1.SelStart = 0
TextBox1.SelLength = Len(TextBox1.Text)
End If
End Sub
The screenshot is only a test, you can do the formatting etc according to your application.
I vote for usmanhaq and CommonSense!
just something to add: I've tried to implement similiar thing on one of my projects, I end up avoiding pop up another window. Just use a label to alert.
And after i implement this i find this more userfriendly!
Hope this helps!
userform:
Private Sub TextBox1_Change()
If Not IsNumeric(TextBox1.Value) Then
Label1.Caption = "NUMBER ONLY!"
UserForm1.TextBox1.SetFocus
UserForm1.TextBox1.SelStart = FirstNonDigit(TextBox1.Value) - 1
UserForm1.TextBox1.SelLength = Len(TextBox1.Text)
Else
Label1.Caption = ""
End If
End Sub
this function is funded online that would help highlight starting from the first non number
Public Function FirstNonDigit(xStr As String) As Long
Dim xChar As Integer
Dim xPos As Integer
Dim I As Integer
Application.Volatile
For I = 1 To Len(xStr)
xChar = Asc(Mid(xStr, I, 1))
If xChar <= 47 Or _
xChar >= 58 Then
xPos = I
Exit For
End If
Next
FirstNonDigit = xPos
End Function
All,
I have a simple userform with two textboxes. I'm attempting to trap an error and send the user back to TextBox1 if the entry is > 1,000. I found code on this site which gets close under the same Title as above.
The code below traps the error and highlights the number >1,000 entered in Textbox1 (without an error message box). However, if I "uncomment" and enter the
MsgBox ("Value is Greater than 1,000")
after the Cancel = True the error will trap, the msg box displays, but the number greater than 1,000 will not highlight.
I've pulled most of what remains of my hair trying to see why this doesn't work and the example I'm following does. Help!!
Thanks
Stan
Private SkipIT As Boolean
'------------------------------------------------------
Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
If SkipIT Then Exit Sub
With Me.TextBox1
If Val(Me.TextBox1.Value) > 1000 Then
Cancel = True
'MsgBox ("Value is Greater than 1,000") 'Will highlight if this line is commented, but no error message box
.SetFocus
.SelStart = 0
.SelLength = Len(.Text)
End If
End With
End Sub
'--------------------------------------------------------------------
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
SkipIT = True
End Sub
I have an input box asking user to enter a date. How do I let the program know to stop if the user click cancel or close the input dialog instead of press okay.
Something like
if str=vbCancel then exit sub
Currently, user can hit OK or Cancel but the program still runs
str = InputBox(Prompt:="Enter Date MM/DD/YYY", _
Title:="Date Confirmation", Default:=Date)
If the user clicks Cancel, a zero-length string is returned. You can't differentiate this from entering an empty string. You can however make your own custom InputBox class...
EDIT to properly differentiate between empty string and cancel, according to this answer.
Your example
Private Sub test()
Dim result As String
result = InputBox("Enter Date MM/DD/YYY", "Date Confirmation", Now)
If StrPtr(result) = 0 Then
MsgBox ("User canceled!")
ElseIf result = vbNullString Then
MsgBox ("User didn't enter anything!")
Else
MsgBox ("User entered " & result)
End If
End Sub
Would tell the user they canceled when they delete the default string, or they click cancel.
See http://msdn.microsoft.com/en-us/library/6z0ak68w(v=vs.90).aspx
Following example uses InputBox method to validate user entry to unhide sheets:
Important thing here is to use wrap InputBox variable inside StrPtr so it could be compared to '0' when user chose to click 'x' icon on the InputBox.
Sub unhidesheet()
Dim ws As Worksheet
Dim pw As String
pw = InputBox("Enter Password to Unhide Sheets:", "Unhide Data Sheets")
If StrPtr(pw) = 0 Then
Exit Sub
ElseIf pw = NullString Then
Exit Sub
ElseIf pw = 123456 Then
For Each ws In ThisWorkbook.Worksheets
ws.Visible = xlSheetVisible
Next
End If
End Sub
The solution above does not work in all InputBox-Cancel cases. Most notably, it does not work if you have to InputBox a Range.
For example, try the following InputBox for defining a custom range ('sRange', type:=8, requires Set + Application.InputBox) and you will get an error upon pressing Cancel:
Sub Cancel_Handler_WRONG()
Set sRange = Application.InputBox("Input custom range", _
"Cancel-press test", Selection.Address, Type:=8)
If StrPtr(sRange) = 0 Then 'I also tried with sRange.address and vbNullString
MsgBox ("Cancel pressed!")
Exit Sub
End If
MsgBox ("Your custom range is " & sRange.Address)
End Sub
The only thing that works, in this case, is an "On Error GoTo ErrorHandler" statement before the InputBox + ErrorHandler at the end:
Sub Cancel_Handler_OK()
On Error GoTo ErrorHandler
Set sRange = Application.InputBox("Input custom range", _
"Cancel-press test", Selection.Address, Type:=8)
MsgBox ("Your custom range is " & sRange.Address)
Exit Sub
ErrorHandler:
MsgBox ("Cancel pressed")
End Sub
So, the question is how to detect either an error or StrPtr()=0 with an If statement?
If your input box is an array, it does not work. I have solved it by adding a check for if it is an array first.
Dim MyArrayCheck As String
Dim MyPlateMapArray as variant
MyPlateMapArray = Application.InputBox("Select ....", Type:=8)
MyArrayCheck = IsArray(MyPlateMapArray)
If MyArrayCheck = "False" Then
Exit Sub
End If
I have solved it with a False like below
MyLLOQ = Application.InputBox("Type the LLOQ number...", Title:="LLOQ to be inserted in colored cells.", Type:=1)
If MyLLOQ = False Then Exit Sub
If user click cancel the sub will exit.
Another suggestion.
Create a message box when inputbox return null value. Example:
Dim PrC as string = MsgBox( _
"No data provided, do you want to cancel?", vbYesNo+vbQuestion, "Cancel?")
Sub TestInputBox()
Dim text As String
text = InputBox("Type some text")
If text = "" Then
MsgBox "button cancel pressed or nothing typed"
Else
MsgBox text
End If
End Sub
Inputbox send a boolean False value when Cancel is pressed.
contenidoy = Application.InputBox("Cantidad = ", titulox, contenidox, , , , , Type:=1)
'ESC or CANCEL
If contenidoy = False Then
MsgBox "Cancelado"
Else
MsgBox "Edición aceptada"
'End If
I am trying to highlight entered value in TextBox. TextBox value is representing date value in date forma DD-MM-YYYY. I wrote some code to validate if inserted date is ok (in example 31 of April).
Hightlight itself is not a problem, however I want to do this right after an error occurs. So when I insert 31-04-2014, I should get the message "You have inserted wrong date" and the date value should hightlighted. For now it shows me message, highlights value and focus is set to another CommandButton
So far I made something like this:
Private Sub data_faktury_AfterUpdate()
Dim dzien As Byte, miesiac As Byte
Dim rok As Integer
On Error GoTo blad:
dzien = Mid(data_faktury.Value, 1, 2)
miesiac = Mid(data_faktury.Value, 4, 2)
rok = Right(data_faktury.Value, 4)
Call spr_date(dzien, miesiac, rok)
Exit Sub
blad:
If Err.Number = 13 Then
If data_faktury <> "" Then
If Len(data_faktury) < 10 Then: MsgBox ("Źle wpisana data faktury.")
End If
End If
End Sub
And code for 2nd procedure:
Sub zle()
MsgBox ("Wybrałeś zły dzień")
With Faktura.data_faktury
.SetFocus
.SelStart = 0
.SelLength = Len(.Text)
End With
End Sub
This is a bit long for a comment so here goes. The basic principle is to use the exit event and cancel when necessary. To prevent this being fired when you close the form, you need to use a flag variable - example userform code:
Private bSkipEvents As Boolean
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If bSkipEvents Then Exit Sub
With TextBox1
If Not IsValidDate(.Text) Then
Cancel = True
MsgBox "Invalid date"
.SelStart = 0
.SelLength = Len(.Text)
End If
End With
End Sub
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
bSkipEvents = True
End Sub