【问题标题】:How to overwrite suggest text in textbox during typing?如何在输入过程中覆盖文本框中的建议文本?
【发布时间】:2019-12-16 20:02:48
【问题描述】:

我有用户窗体使用文本框输入日期。

我想在输入之前显示建议文本,例如 __ /__/____(格式相同 dd/mm/yyyy) 输入此文本框时,光标始终位于开头。当我输入时,每个_ 符号将被数字替换,并跳过/ 符号。

例如:我只是输入05041991,在文本框中会显示05/04/1991

请帮助我了解此代码。

【问题讨论】:

  • 把替换文本的逻辑放到Private Sub TextBox1_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger) ...这个事件捕获TextBox中的keypressed
  • 这只是一个例子。我对条形码句柄输入有同样的问题,比如需要输入 12 个数字字符到文本框,建议文本是 1xxx-xxxx-xxxx
  • 我建议使用This 作为日期:)
  • 你可以做的是编写一个字符串格式化程序,它读取一个字符串,删除所有非数字,然后在适当的位置用破折号把它吐出来。然后将其写回文本字段并将光标位置设置为原来的位置。在每个 textBox_Change 事件上执行此操作。

标签: excel vba textbox userform


【解决方案1】:

您可以执行如下所示的操作。这段代码只是一个例子(可能并不完美)。

图 1:注意只有数字键和退格键被按下。

将以下代码放入一个类模块中,命名为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

将以下代码放入您的用户表单中

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

【讨论】:

  • @HaiNguyen 我改进了代码并将其包装到一个类模块中。看看吧。
  • 我还将您的代码修改为另一种情况,例如1___-____-____,仅带有数字。但是你能帮我在文本框中允许粘贴(Ctrl+V)功能吗?谢谢。
  • @HaiNguyen 我添加了一些代码以允许粘贴 (Ctrl+V)
  • 完美运行。但我有更多要求: 1- 在最后一个数字中,例如:103456789012,在我输入“2”后,它会自动vbTab 更改为下一个对象。 2-如果我离开的文本框没有完整的数字(有几个_),它将BackColor更改为vbRed
  • @HaiNguyen 这不是免费的编码服务。您必须尝试自己实现这一目标(如果您遇到困难或错误,请提出新问题,展示您尝试过的内容)。根据您的需要更改课程模块。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-05
  • 2020-06-23
  • 2011-09-21
  • 2013-06-14
  • 2020-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多