Reputation: 1425
I'm working on a userform with several textboxes, which are arranged just like an excel chart. I've set the TabIndexes, and they work perfectly with TAB/shift+TAB. However, the react of pressing arrow keys is not what I expected. I named those textboxes like this:
boxA1 boxB1 boxC1 boxD1
boxA2 boxB2 boxC2 boxD2 ...
boxA3 boxB3 boxC3 boxD3
:
:
Assuming that the focus is at boxB1. When pressing the down arrow key, I wish the focus goes to boxB2, but it will go to boxA3 or something.
I've tried this code:
Private Sub boxB1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case vbKeyDown
boxB2.SetFocus
Case vbKeyUp
boxA10.SetFocus
End Select
End Sub
It works fine, however, if there are only several textboxes in my form, this is a great and clear solution. But there are about 70 textboxes in my form, this will make my code large and really duplicated. Are there any parameters I can adjust to make it right? Or is there any function I can use such as below? Just sudo, you know.
Private Sub name_i_KeyDown(ByVal KeyCode as MSForms.ReturnInteger, ByVal Shift As Integer)
Select Case KeyCode
Case vbKeyDown
Controls("name_" & i+1).SetFocus
Case vbKeyUp
Controls("name_" & i-1).SetFocus
End Select
End Sub
Thank you!
Upvotes: 1
Views: 3027
Reputation: 1944
You are on the right path. Add the below two UDF's in your form module:
Sub SetTextBoxFocus(ByVal KeyCode As MSForms.ReturnInteger)
Dim sPrevControl As String
Dim sNextControl As String
Dim sBoxToSet As String
Dim oC As Control
' Cater for TAB key press. Setting it so that it behaves like vbKeyDown. Remove this If condition if not required
If Asc(KeyCode) = 57 Then
KeyCode = vbKeyDown
End If
' We only want to check if pressed key was either vbKeyDown or vbKeyUp and the key was pressed on a TextBox
If TypeName(Me.ActiveControl) = "TextBox" And (KeyCode = vbKeyDown Or KeyCode = vbKeyUp) Then
With Me.ActiveControl
' Lets set both previous and next text box names
If InStr(1, .Name, "boxD") > 0 Then
sPrevControl = "boxC" & GetNumFromString(.Name)
sNextControl = "boxA" & GetNumFromString(.Name) + 1
ElseIf InStr(1, .Name, "boxA") > 0 Then
sPrevControl = "boxD" & GetNumFromString(.Name) - 1
sNextControl = "boxB" & GetNumFromString(.Name)
Else
sPrevControl = "box" & Chr(Asc(Mid(.Name, 4, 1)) - 1) & GetNumFromString(.Name)
sNextControl = "box" & Chr(Asc(Mid(.Name, 4, 1)) + 1) & GetNumFromString(.Name)
End If
' Bases on which key was pressed, lets set the name of the text box to move to
Select Case KeyCode
Case vbKeyDown: sBoxToSet = sNextControl
Case Else: sBoxToSet = sPrevControl
End Select
' Loop through all controls in the form and set the focus to the control if found
For Each oC In Me.Controls
If oC.Name = sBoxToSet Then
oC.SetFocus
Exit For
End If
Next
End With
End If
End Sub
Function GetNumFromString(ByVal txt As String) As String
Dim oRe As New RegExp
With oRe
.pattern = "\d"
If .Test(txt) Then GetNumFromString = .Execute(txt)(0)
End With
End Function
Now, in KeyDown for each TextBox, make the following call: SetTextBoxFocus KeyCode
. This should do the trick
NOTE: I have boxD
as the last text box. You should change that to whatever the last text box you have in the same row
Upvotes: 1