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

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.

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

Number only text box not working on one of two text boxes in a userform

I have two text boxes on a userform that I would like to be numeric only. The first one works fine based on this( Link), however the second one, which I have implemented in exactly the same way as the first is not working, and I don't know why. Any idea why?
The first textbox is call TextBoxMainVal
The second is called perHour
Code:
'If the Main Value box does not recieve a number send a message to make them change it
Private Sub TextBoxMainVal_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If TextBoxMainVal.Value = "" Then
ElseIf Not IsNumeric(TextBoxMainVal.Value) Then
MsgBox "Enter numbers only"
Cancel = True
TextBoxMainVal.Value = vbNullString
End If
End Sub
'I DONT KNOW WHY THIS ONE ISNT WORKING!
Private Sub perHour_Exit(ByVal Cancel As MSForms.ReturnBoolean)
If perHour.Value = "" Then
ElseIf Not IsNumeric(perHour.Value) Then
MsgBox "Enter numbers only"
Cancel = True
perHour.Value = vbNullString
End If
End Sub
I thought there could be a naming error conflict, so I changed the textbox name, but that did not resolve it.
I cant understand why it is not working. What am I overlooking?
For those who are interested why this may happen there is an answer here. The reason, it appears, the textbox exit handler is not occurring is because it is outside of a frame. For the exit handler to work you need to stay inside the frame.

VBA Access Message Box woes

I followed a few simple comments on how to pop a confirmation box before executing a script, but sadly, if I press yes, the script doesn't run.
Private Sub Overwrite_Btn_Click()
If MsgBox("Yes?", vbOKCancel) = ok Then
Me.Product_Quantity = Me.Quantity_Input
Else
Exit Sub
End If
End Sub
I'm trying to set Product_Quantity equaling Quantity_Input, and although it works without the MsgBox command, it doesn't with it.
What am I doing wrong?
Instead of If MsgBox("Yes?", vbOKCancel) = ok Then try: If MsgBox("Yes?", vbOKCancel) = vbOK Then
Typically the interactions with forms will return one constant from a set of several constants. Those are catalogged in enums. In this case you have several constants in the VbMsgBoxResult class, and vbOK is a constant with value 1, which is returned from clicking the ok button.
Actually, If MsgBox("Yes?", vbOKCancel) = 1 Then would work as well, but it is harder to remember that clicking Ok returns 1 then simply stating a constant named vbOK
In object explorer (F2 on the VBE), searching for VbMsgBoxResult will give all possible results that comes from interacting with a message box.
https://www.techonthenet.com/access/constants/msgbox_ret.php
1) Dim a variable as integer.
2) Check for value of integer equal to 6, or check for vbYess
3) ?????
4) Profit
borrowed from link
Dim LResponse As Integer
LResponse = MsgBox("Do you wish to continue?", vbYesNo, "Continue")
If LResponse = vbYes Then
{...statements...}
Else
{...statements...}
End If
Single line:
If MsgBox("Yes?", vbOKCancel) <> vbOk then Exit Sub
'continue code here.
More Information:
MSDN : MsgBox Function (Office/VBA)

Excel VBA Userform QueryClose: Cancel not working

I've written the code below so that it will check if a process has been completed or not before closing the form. This userform is used as a scoresheet that will make range("A6") green to signify a pass, or range("B6") red to signify a fail as the final step of the sub, before unloading the form.
From what I've checked online so far, it should be working. While debugging, the macro gets all the way to where it says Cancel = True, reads over the line, but the form closes anyway.
Why isn't the cancel registering even when it reads over the line?
Private Sub Userform_queryclose(CloseMode As Integer, Cancel As Integer)
Dim wbScoreCard As Workbook
Dim wsScoreCard As Worksheet
Dim MSG As String
Set wbScoreCard = Workbooks(NameBox.Value)
Set wsScoreCard = wbScoreCard.Worksheets(Format(Date, "MM.dd.yy") & " " & CallType.Caption)
If Err.Number = 0 Then
If wsScoreCard.Range("A6").Interior.Color <> vbGreen Then
If wsScoreCard.Range("B6").Interior.Color <> vbRed Then
Beep
MSG = MsgBox("This scorecard is not complete! If you close it now, this scorecard will not be saved. Continue?", vbYesNo, "Warning - Scorecard Incomplete")
If MSG = vbYes Then
wbScoreCard.Close savechanges:=False
Exit Sub
Else
Cancel = True
Exit Sub
End If
End If
End If
End If
End Sub
Couple of things:
You're not shutting off error handling, so the Err.Number = 0 check has no effect; if there's a runtime error, execution jumps straight out of the procedure anyway.
MSG should be a vbMsgBoxResult, not a String. Your code only works because of implicit type conversions from the underlying Integer value to the String type you're forcing it into.
Unless you didn't post your entire code, Exit Sub is redundant in both branches.
The problem can be reproduced with simpler code:
Private Sub Userform_queryclose(CloseMode As Integer, Cancel As Integer)
Cancel = True
End Sub
The problem is that you made up that signature or somehow typed it up from memory. This is the signature for the QueryClose handler:
Private Sub UserForm_QueryClose(Cancel As Integer, CloseMode As Integer)
Notice the ordering of parameters.
You'll get the expected behavior by setting your CloseMode to True instead of Cancel... but a better fix would be to put the parameters in the correct order.
Event handlers don't really care about parameter names: it's about types and order. Since both parameters are Integer, it's down to ordering: the first Integer parameter is interpreted as the Cancel parameter, and the second is the CloseMode - the form / COM doesn't care how you called them, it's going to read the Cancel value from the first parameter anyway.
You can avoid this problem in the future, by selecting the event from the dropdowns at the top of the code pane:
Make sure the left-hand dropdown says "UserForm", and then select "QueryClose" from the right-hand dropdown:
If there's no handler for it, the VBE will create one properly formed for you.

How to clear userform textbox without calling the _Change function?

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.