1

I have Userform using Textbox to input date.

I'd like to show suggestion text before input like __ /__/____ (same format dd/mm/yyyy) When enter this Textbox, cursor always in beginning. When I typing, each _ symbol will be replaced by number, and skip / symbol.

For example: I just type 05041991, in Textbox will show 05/04/1991.

Please help me about this code.

First show like this picture

During typing like this picture

Hai Nguyen
  • 13
  • 6
  • Put the logic of Replacing text in `Private Sub TextBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)` ...This event captures the keypressed in TextBox – Mikku Aug 09 '19 at 05:46
  • It's just example. I have same issue with barcode handle input, like 12 number characters need to input to textbox with suggestion text is `1xxx-xxxx-xxxx` – Hai Nguyen Aug 09 '19 at 05:54
  • I reommend using [This](https://stackoverflow.com/questions/54650417/how-can-i-create-a-calendar-input-in-vba-excel) for date :) – Siddharth Rout Aug 09 '19 at 06:01
  • What you can do is write a string-formatter, that read a string, removes all non-numbers and spits it back out with the dashes in the proper place. Then write it back to the textfield and set the curser position to where it was. Do this on every textBox_Change Event. – L8n Aug 09 '19 at 06:46

1 Answers1

4

You could do something like shown below. This code is just an example (probably not perfect).

enter image description here

Image 1: Note that only number keys and backspace were pressed.

Put the following code into a class module and name it MaskedTextBox

Option Explicit

Public WithEvents mTextBox As MSForms.TextBox

Private mMask As String
Private mMaskPlaceholder As String
Private mMaskSeparator As String

Public Enum AllowedKeysEnum
    NumberKeys = 1     '2^0
    CharacterKeys = 2  '2^1
    'for more options next values need to be 2^2, 2^3, 2^4, …
End Enum
Private mAllowedKeys As AllowedKeysEnum

Public Sub SetMask(ByVal Mask As String, ByVal MaskPlaceholder As String, ByVal MaskSeparator As String, Optional ByVal AllowedKeys As AllowedKeysEnum = NumberKeys)
    mMask = Mask
    mMaskPlaceholder = MaskPlaceholder
    mMaskSeparator = MaskSeparator
    mAllowedKeys = AllowedKeys

    mTextBox.Text = mMask
    FixSelection
End Sub


' move selection so separators get not replaced
Private Sub FixSelection()
    With mTextBox
        Dim Sel As Long
        Sel = InStr(1, .Text, mMaskPlaceholder) - 1
        If Sel >= 0 Then
            .SelStart = Sel
            .SelLength = 1
        End If
    End With
End Sub

Private Sub mTextBox_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
    Dim tb As MSForms.TextBox
    Set tb = Me.mTextBox

    'allow paste
    If Shift = 2 And KeyCode = vbKeyV Then
        On Error Resume Next
        Dim DataObj As MSForms.DataObject
        Set DataObj = New MSForms.DataObject

        DataObj.GetFromClipboard
        Dim PasteData As String
        PasteData = DataObj.GetText(1)

        On Error GoTo 0
        If PasteData <> vbNullString Then
            Dim LikeMask As String
            LikeMask = Replace$(mMask, mMaskPlaceholder, "?")

            If PasteData Like LikeMask Then
                mTextBox = PasteData
            End If
        End If
    End If

    Select Case KeyCode
        Case vbKey0 To vbKey9, vbKeyNumpad0 To vbKeyNumpad9
            'allow number keys
            If Not (mAllowedKeys And NumberKeys) = NumberKeys Then
                KeyCode = 0
            ElseIf Len(tb.Text) >= Len(mMask) And InStr(1, tb.Text, mMaskPlaceholder) = 0 Then
                KeyCode = 0
            End If

        Case vbKeyA To vbKeyZ
            'allow character keys
            If Not (mAllowedKeys And CharacterKeys) = CharacterKeys Then
                KeyCode = 0
            ElseIf Len(tb.Text) >= Len(mMask) And InStr(1, tb.Text, mMaskPlaceholder) = 0 Then
                KeyCode = 0
            End If

        Case vbKeyBack
            'allow backspace key
            KeyCode = 0
            If tb.SelStart > 0 Then 'only if not first character
                If Mid$(tb.Text, tb.SelStart, 1) = mMaskSeparator Then
                    'jump over separators
                    tb.SelStart = tb.SelStart - 1
                End If

                'remove character left of selection and fill in mask
                If tb.SelLength <= 1 Then
                    tb.Text = Left$(tb.Text, tb.SelStart - 1) & Mid$(mMask, tb.SelStart, 1) & Right$(tb.Text, Len(tb.Text) - tb.SelStart)
                End If
            End If

            'if whole value is selected replace with mask
            If tb.SelLength = Len(mMask) Then tb.Text = mMask

        Case vbKeyReturn, vbKeyTab, vbKeyEscape
            'allow these keys

        Case Else
            'disallow any other key
            KeyCode = 0
    End Select

    FixSelection
End Sub

Private Sub mTextBox_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    FixSelection
End Sub

Put the following code into your userform

Option Explicit

Private MaskedTextBoxes As Collection

Private Sub UserForm_Initialize()
    Set MaskedTextBoxes = New Collection
    Dim MaskedTextBox As MaskedTextBox

    'init TextBox1 as date textbox
    Set MaskedTextBox = New MaskedTextBox
    Set MaskedTextBox.mTextBox = Me.TextBox1
    MaskedTextBox.SetMask Mask:="__/__/____", MaskPlaceholder:="_", MaskSeparator:="/"
    MaskedTextBoxes.Add MaskedTextBox

    'init TextBox2 as barcode textbox
    Set MaskedTextBox = New MaskedTextBox
    Set MaskedTextBox.mTextBox = Me.TextBox2
    MaskedTextBox.SetMask Mask:="____-____-____", MaskPlaceholder:="_", MaskSeparator:="-", AllowedKeys:=CharacterKeys + NumberKeys
    MaskedTextBoxes.Add MaskedTextBox
End Sub
Pᴇʜ
  • 56,719
  • 10
  • 49
  • 73
  • @HaiNguyen I improved the code and wrapped it into a class module. Have a look. – Pᴇʜ Aug 09 '19 at 07:20
  • I also modified your code into another case like `1___-____-____` with number only. But can you help me to allow Paste (Ctrl+V) function in text box? Thanks. – Hai Nguyen Aug 09 '19 at 07:22
  • @HaiNguyen I added some code to allow paste (Ctrl+V) – Pᴇʜ Aug 09 '19 at 07:40
  • It's work perfectly. But I have more requests: 1- In last number, for example: 103456789012, after I type "2", it automatic `vbTab` to change to next Objects. 2- If I leave textbox without full of number (have several `_`), It change BackColor to `vbRed`. – Hai Nguyen Aug 09 '19 at 07:49
  • 2
    @HaiNguyen This is not a free coding service. You must try to achieve that on your own (and if you get stuck or errors ask a new question, showing what you have tried). Change the class module to your needs. – Pᴇʜ Aug 09 '19 at 08:00
  • @PEH: Thanks so much for your support, and sorry about my Impolite :) – Hai Nguyen Aug 09 '19 at 08:06