How to clear userform textbox without calling the _Change function? - vba

I have a userform in Excel with textboxes meant for numeric data only. I want to clear the textbox when it detects bad entry and gives an error message, but I don't want to have the textbox's _Change function called again or else the message pops up twice because I change the text to "". I didn't see a built in clear function.. is there a better way to do this?
Private Sub txtbox1_Change()
txt = userform.txtbox1.Value
If Not IsNumeric(txt) Then
disp = MsgBox("Please only enter numeric values.", vbOKCancel, "Entry Error")
txtbox1.Text = ""
End If
End Sub

A simple way to achieve this is to use the _Exit() Function:
Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If Not IsNumeric(TextBox1.Value) Then
MsgBox "Please only enter numeric values.", vbCritical, "Error"
End If
End Sub
This triggers as soon as the text box looses Focus.

prevent user from typing Alpha chars:
Private Sub TextBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
Select Case KeyAscii
Case Asc("0") To Asc("9")
Case Asc("-")
If Instr(1,Me.TextBox1.Text,"-") > 0 Or Me.TextBox1.SelStart > 0 Then
KeyAscii = 0
End If
Case Asc(".")
If InStr(1, Me.TextBox1.Text, ".") > 0 Then
KeyAscii = 0
End If
Case Else
KeyAscii = 0
End Select
End Sub
Hope this helps!
-Hugues

You can do this way, as shown here
Private Sub TextBox1_Change()
OnlyNumbers
End Sub
Private Sub OnlyNumbers()
If TypeName(Me.ActiveControl) = "TextBox" Then
With Me.ActiveControl
If Not IsNumeric(.Value) And .Value <> vbNullString Then
MsgBox "Sorry, only numbers allowed"
.Value = vbNullString
End If
End With
End If
End Sub

You can add this line at the very beginning
sub txtbox1_Change()
If txtbox1.Text = "" Or txtbox1.Text = "-" Then Exit Sub '<~~~
Alternatively, I found this even shorter and interesting:
Private Sub txtbox1_Change()
If Not IsNumeric(txtbox1.Text & "0") Then
disp = MsgBox("Please only enter numeric values.", vbOKCancel, "Entry Error")
txtbox1.Text = ""
End If
End Sub
The interesting part is that it accepts to enter things like ".2", "-3.2", and also "5e3", the last case being not allowed by the other methods!
Turning it into a while loop can remove only the last bad typed character(s):
Private Sub txtbox1_Change()
t = txtbox1.Text
Do While t <> "" And Not IsNumeric(t) And Not IsNumeric(t & "0")
t = Mid(t, 1, Len(t) - 1)
Loop
txtbox1.Text = t
End Sub

Seems since there is nothing built in that can do what I want, this would be the simplest way to handle the problem:
Private Sub txtbox1_Change()
txt = userform.txtbox1.Value
If (Not IsNumeric(txt)) And (txt <> "") Then
disp = MsgBox("Please only enter numeric values.", vbOKCancel, "Entry Error")
txtbox1.Text = ""
End If
End Sub

Declare a global boolean and at the beginning of each sub, add an if statement which exits the sub if the boolean is true. When you get an error message, set the value to true, and nothing will happen. Then set it to false again.
Dim ufEventsDisabled As Boolean
Private Sub txtbox1_Change()
'repeat the following line everywhere that you don't want to update
if ufeventsdisabled then exit sub
txt = userform.txtbox1.Value
If Not IsNumeric(txt) Then
disp = MsgBox("Please only enter numeric values.", vbOKCancel, "Entry Error")
ufeventsdisabled = true
txtbox1.Text = ""
ufeventsdisabled = false
End If
End Sub
*Credit goes to mikerickson from mrexcel.com

You can't stop the _Changed event from firing. I would advise you to back up a couple of steps in your design and ask if you can get the job done without having to clear it in the first place. In FoxPro we would set the 'format' to 9999.99 and it would automatically prevent users from typing alpha characters, but I think that particular field was unique to FP. You can hook the _Changed event and perform your own validation there. I would suggest not filtering individual key strokes, but validating the whole value each time it's changed.
If Text1.Value <> str(val(Text1.Value)) Then
Text1.Value = previousValue
EndIf
... which will require keeping a backup variable for the previous value, but I'm sure you can figure that out. There may be certain edge cases where VB's string-number conversion functions don't exactly match, like exponential notation as you mentioned, so you may need a more sophisticated check than that. Anyway, this will make it impossible to even enter a bad value. It also provides a better user experience because the feedback is more immediate and intuitive. You may notice that the value is being changed inside the _Changed event, which should raise a knee jerk red flag in your mind about infinite loops. If you do this, make sure that your previous value has already been validated, keeping in mind that the initial value will be an empty string. As such, the recursive call will skip over the If block thus terminating the loop. In any case, what you would consider "better" may differ depending on who you ask, but hopefully I've given you some food for thought.

Related

Moving the cursor to another textbox after Enter Event - VBA

Could you please help me?
With the code below, I can "Setfocus" and change the "Backcolor" of "Me.txtFT".
But, when I am trying to move the cursor to "Me.txtFT" after an "Enter" event on "txtPT", the cursor is not moving, it keeps on the "txtPT".
I am using the code below.
Private Sub txtPT_Enter()
If Trim(Me.txtPT.Value & vbNullString) = 0 Then
MsgBox """FT field"" must contain a value before continue. Please try again": _
Me.txtFT.SetFocus: _
Me.txtFT.BackColor = &H80FFFF: _
Exit Sub
End If
End Sub
Could you please help me?
The condition is testing the length of txtPT but the message is warning about txtFT, so it's unclear from the code what the intent might be.
Instead of handling the entry into control B to validate the value of control A, consider handling the exit from control A - and cancel it losing the focus with an invalid value in the first place:
Private Sub txtFT_Exit(ByVal Cancel As MSForms.ReturnBoolean)
With txtFT
If Len(Trim(.Text & vbNullString)) = 0 Then
Cancel.Value = True
.BackColor = &H80FFFF
MsgBox "[FT] cannot be empty!"
End If
End With
End Sub

What property will return the caret (or cursor type bar) to the designated textbox in VBA Excel UserForms? [duplicate]

I have a textbox on a userform. If the user fails to enter anything in this textbox, I need to trap that to force an entry. I can do this easily enough, but after notifying the user tht they need to make an entry, I want the focus to return to the textbox. Right now, it doesn't do that. Here is my code:
Private Sub txtAnswer_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case 13:
If Me.txtAnswer.Value = "" Then
temp = MsgBox("You need to enter an answer!", vbCritical + vbOKOnly, "No Answer Found!")
Me.txtAnswer.SetFocus
Else
recordAnswer
End If
End Select
End Sub
This code works fine in that the message box pops up if the textbox is left blank. After clearing the message box, if I hit enter immediately again, the message box reappears, suggesting that the focus is on the textbox. However, if I try to enter a character (like the number '1' for example) nothing appears in the textbox.
Can anybody suggest how I can get the focus back on this textbox in a way that will allow the user to enter data? Thank you!
Why are you not using an 'ok' button to complete the action?
You should not bother users with messages while they are typing in a form. Do it at the end.
Private Sub OK_Click()
'// Validate form
If txtAnswer.Text = vbNullString Then
MsgBox "You need to enter an answer!", vbExclamation, "No Answer Found!"
txtAnswer.SetFocus
Exit Sub
End If
'// You have reached here so form is correct carry on
recordAnswer
End Sub
If you really want to use the behaviour you asked for then try this:
Private Sub txtAnswer_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case 13:
If Me.txtAnswer.Value = "" Then
temp = MsgBox("You need to enter an answer!", vbCritical + vbOKOnly, "No Answer Found!")
KeyCode = 0
Else
recordAnswer
End If
End Select
End Sub
The problem is that in your code you are setting focus but the enter key is firing afterwards. You don't need to set focus because the textbox already has the focus you just need to cancel the enter key.
The other answers seem really complicated. I had a similar problem and really wanted a text warning. It seemed easier for me to just make an invisible label on the form that would show up if the input was incorrect. I also made the background of the label red so that the user would notice something was wrong. Doing it this way kept the cursor visible and right where they left off.
Public Function amount(ByRef cont As MSForms.TextBox) As Integer
'makes sure that a number is used
'could change to account for decimals if necessary
Dim i As Long
On Error Resume Next
i = 0
If (cont.Value = "") Then Exit Function
Do While i < 1000000
If (cont.Value = i) Then
UserForm1.Label257.Visible = False
Exit Function
End If
i = i + 1
Loop
UserForm1.Label257.Visible = True
amount = 1
End Function
Public Sub qty_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
If amount(UserForm1.qty) = 1 Then
Cancel = True
End If
End Sub
I hope this helps other who run into this problem later on.
Looking at the above code, I assume the i counter is to keep it going? Sorry a bit rusty, been a few years since I've done code.
At any rate, if thats the case you could always run it while i=0, do (or while true).
Sorry, first time posting here, hope that made sense.

Advanced customization of InputBox edit control

So I have some basic VBA code:
Sub Test()
' Set error handler
On Error GoTo ErrorHandler
Dim strElevation As String
strElevation = InputBox("Enter elevation difference:", "Create Cross Lines", 0.5)
Exit Sub
ErrorHandler:
Call ReportError("Test")
End Sub
And it looks fine:
Is it possible to extend this so that the edit box will only allow a numeric value to 2 decimal places? Or is it simply too much work?
I know how to format text itself, eg: Format("1234.5678", "#.00"). But can the actual edit control have any customization itself?
You basically have three options here... In order of difficulty:
1. Validate the input
This uses the native InputBox() function as you have in your code sample above. You can return the value into a string variable, then do your validation at that point to make sure the data is formatted the way you want. If it doesn't pass, then display the input box again.
2. Custom VBA form
If you create your own VBA User Form, you can customize the text box to use a specific format, and perform the validation before the form accepts the input and closes. This is probably the most user-friendly approach, but involves a little more code than the first method.
Example:
Create sample VBA form with two input boxes and a command button. Name them txtDiff1, txtDiff2, and cmdOK respectively.
Double-click one of the controls, and add the following code to the code module behind the form:
Option Explicit
Private Sub cmdOK_Click()
MyElevationDifference = txtDiff1 ' (or txtDiff2)
Unload Me
End Sub
Private Sub txtDiff1_AfterUpdate()
Dim dblValue As Double
If IsNumeric(txtDiff1) Then
' Determine rounded amount
dblValue = Round(txtDiff1, 2)
' Automatically round the value
If dblValue <> CDbl(txtDiff1) Then txtDiff1 = dblValue
Else
MsgBox "Please enter a numeric value", vbExclamation
End If
End Sub
Private Sub txtDiff2_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
Dim dblValue As Double
If IsNumeric(txtDiff2) Then
' Determine rounded amount
dblValue = Round(txtDiff2, 2)
' Require a max of 2 decimal places
If dblValue <> CDbl(txtDiff2) Then
Cancel = True
MsgBox "Please only use 2 decimal places", vbExclamation
End If
Else
MsgBox "Please enter a numeric value", vbExclamation
' Cancel change
Cancel = True
End If
End Sub
Paste the following into a regular code module. (This is how you can get the input in your main code through the custom form. Essentially the form assigns a value to the global variable, and you reference that after showing the form.)
Option Explicit
Public MyElevationDifference As Double
Public Sub GetElevationDifference()
UserForm1.Show
MsgBox "Elevation difference: " & MyElevationDifference, vbInformation
End Sub
Now when you run GetElevationDifference(), you will see a couple different approaches demonstrated on the user form. The first text box automatically rounds the input, while the second text box does not allow the user to continue unless they correct the input to use two decimal places or less.
Of course you will want to add some error handling and make the form look nice, but this gives you a simple example of how to use a VBA form to get user input. They involve a little more code, but obviously provide a huge level of additional flexibility over the simple InputBox() function.
3. Windows API calls
Just for completeness, there are ways to use Windows API calls to actually affect the controls on an input box, but this would end up being far more complex than the first two approaches, and I would not recommend it for something like this.
this is how you can restrict to input box to allow only numeric values:
strElevation = Application.InputBox(prompt:="Enter elevation difference:", Title:="Create Cross Lines", Default:=0.5, Type:=1)
https://msdn.microsoft.com/en-us/vba/excel-vba/articles/application-inputbox-method-excel
To validate the lenght, you can use the following code:
Do
strElevation = Application.InputBox(prompt:="Enter elevation difference:", Title:="Create Cross Lines", Default:=0.5, Type:=1)
If Len(strElevation) > 2 Then MsgBox "You typed in too many characters... 2 maximum!"
Loop While Len(strElevation) > 2
Private Sub TextBox1_AfterUpdate()
If InStr(1, Me.TextBox1.Value, ".") > 0 Then
If Len(Mid(Me.TextBox1.Value, _
InStr(1, Me.TextBox1.Value, "."), _
Len(Me.TextBox1.Value) - InStr(1, Me.TextBox1.Value, "."))) > 2 Then
Me.TextBox1.SetFocus
MsgBox "cannot have more than 2 decimal places"
End If
End If
End Sub
Apply to your situation but this gets you there
Sub Test()
' Set error handler
On Error GoTo ErrorHandler
Dim strElevation As String
strElevation = InputBox("Enter elevation difference:", "Create Cross Lines", 0.5)
If InStr(1, strElevation, ".") > 0 Then
If Len(Mid(strElevation, InStr(1, strElevation, "."), Len(strElevation) - InStr(1, strElevation, "."))) > 2 Then
MsgBox "cannot have more than 2 decimal places"
End If
End If
Exit Sub
ErrorHandler:
Call ReportError("Test")
End Subc

Arithmetic Operations in a Userform

I have made the userform so I will use that to describe my problem.
I want to take four user inputs (cost of product, number of units sold, number of units returned, and cost of fix per unit) and calculate 6 things from it such as total earnings (cost of product x number of units sold) and total returned cost (cost of product x number of units returned).
How would I go about writing the code?
Userform image here: http://imgur.com/a/qc3Kk
So, here is my take on this solution. It isn't a very complicated program to create. Overall, it is one UserForm, following the design of yours in the image with one section of code doing the calculations and one section of code that ensures the values input in the textboxes are numeric. The interface is a combination of labels and textboxes:
There is a code for each textbox that evaluates whether the value entered is numerica and alerts you if it is not. Each routine uses the IsNumeric function for the purpose and also sees if there is a value in the textbox at all. The AfterUpdate event ensures that the routine only runs after you input something. You have the option of either having a routine for each textbox separately, or write a more integrated routine in a module that each textbox references. For the sake of the example:
Private Sub txtCost_AfterUpdate()
With UserForm1
With .txtCost
If Not IsNumeric(.Value) Or .Value = "" Then
MsgBox "Please enter a numeric value only!"
End If
End With
End With
End Sub
Private Sub txtReturned_AfterUpdate()
With UserForm1
With .txtReturned
If Not IsNumeric(.Value) Or .Value = "" Then
MsgBox "Please ensure you enter only numeric values"
End If
End With
End With
End Sub
Private Sub txtTotalFix_AfterUpdate()
With UserForm1
With .txtTotalFix
If Not IsNumeric(.Value) Or .Value = "" Then
MsgBox "Please ensure you enter only numeric values"
End If
End With
End With
End Sub
Private Sub txtUnits_AfterUpdate()
With UserForm1
With .txtUnits
If Not IsNumeric(.Value) Or .Value = "" Then
MsgBox "Please ensure you enter only numeric values"
End If
End With
End With
End Sub
The meat and potatoes of the routine are also not complicated. I've directly used the values of each textbox to spit out the values of the computations. Alternatively, you might choose to use variables (I've decalred x As Double, because you could be dealing with quite large numbers, but it isn't used in this example). The routine lives in Module1 and checks that all the values are numbers with the same IsNumeric function and runs through the formulas, alerting you if any of them are empty or not a number. I wasn't positive of how you calculated savings or your criteria of YES or NO, so you may have to adjust that.
Sub QA_prog()
Dim x As Double
With UserForm1
If IsNumeric(.txtCost.Value) And IsNumeric(.txtUnits.Value) _
And IsNumeric(.txtReturned.Value) And IsNumeric(.txtTotalFix.Value) Then
.lblEarn.Caption = .txtCost.Value * .txtUnits.Value
.lblTRC.Caption = .txtCost * .txtTotalFix
.lblProfit = .lblEarn.Caption - .lblTRC.Caption
.lblCostFix = .txtReturned * .txtTotalFix
.lblTE.Caption = .lblProfit - .lblCostFix
.lblSave.Caption = .lblTRC + .lblCostFix
If .lblSave.Caption > 5000 Then
.txtYorN.Text = "NO"
Else
.txtYorN.Text = "YES"
End If
Else
MsgBox "Double check your values!"
End If
End With
End Sub
Finally, the buttons. Exit button closes the program using Unload:
Private Sub cmdExit_Click()
Unload UserForm1
End Sub
Calculate button calls the QA Sub routine:
Private Sub cmdCalc_Click()
Module1.QA_prog
End Sub
To trigger the program, you just need to add a button to the spreadsheet and type "UserForm1.show" in its code window to activate the program.

VBA in Access. How to require a field if another field has been answered

I am working on an Access DB and need to require that ScrapAmount1 has an answer if they have put data into ScrapCodes1. I want to have an error message pop up that reminds them to make the amount of scrap higher than 0. I'm using VBA and here is what I have that is not working. PS. ScrapCodes1 is a drop down list that they choose from and the ScrapAmount is 0 by default.
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Me.ScrapCodes1 Then
If Nz(Me.ScrapAmount1, "") = "" Then
Cancel = True
MsgBox "If Scrap Code is selected, then Scrap Amount must have a value.", vbExclamation, "Data Required"
End If
End If
End Sub
Thank you for your answers in advance. :)
I don't think you need anything more than:
Private Sub Form_BeforeUpdate(Cancel As Integer)
If Me.ScrapAmount1= 0 Then
Cancel = True
MsgBox "If Scrap Code is selected, then Scrap Amount must have a value.", vbExclamation, "Data Required"
End If
End Sub
Your if is using the Nz to check if ScrapAmount1 is null. ScrapAmount1 defaults to 0, so it's not null.
I'd have a second If condition myself:
'check for null
If Nz(Me.ScrapAmount1, "") = "" Then
Cancel = True
MsgBox "If Scrap Code is selected, then Scrap Amount must have a value.", vbExclamation, "Data Required"
'checks for 0 and negative numbers
ElseIf Me.ScrapAmount1 <= 0 then
Cancel = True
MsgBox "Scrap Amount must be higher than 0"
End If
If Cancel then
'do cancel stuff, I have no idea what you use this var for
end if