Excel VBA Textbox_Exit 事件处理程序

Excel VBA Textbox_Exit Event Handler

这里有一个路障。使用三个文本框的简单用户表单,一个用于用户 ID,两个用于使用手持扫描仪输入序列号。用户加载 excel 文件,userform.show 加载,用户输入 id 然后简单验证验证数字,然后将焦点设置在第一个文本框上,用户扫描条形码输入序列号,再次简单验证以确保数字和长度, 与上一个文本框相同,扫描序列号,验证第一个文本框条目是否与第二个文本框条目匹配。

手持扫描仪用于输入序列号和returns一个"return carriage"字符;例如序列号扫描后按下进入按钮。

使用 "return carriage" 触发 textbox_exit 事件处理程序。问题非常间歇但一致。我加载用户窗体,输入数据,记录完成后,数据传输到对象工作表。但是,在进行故障排除时,我首先打开工作簿和用户窗体,创建一些记录,保存并关闭。一切正常,数据被记录和归档。当我第二次加载工作簿、为一条记录输入数据、保存并开始第二条记录时,通常会出现问题。一旦将序列号输入到第一个文本框中,使用 "return carriage" 就不会触发退出事件。我可以手动将焦点转移到其他对象;例如diff 文本框,但整体运行不尽如人意

我尝试插入 application.eventhandler=true 命令、不同的事件处理程序以及大量代码更改;例如在 IF 语句结束时退出 sub,以使其工作。

我想我会联系社区以获得一些反馈。仅供参考,如果我使用 copy/paste 模拟手持扫描仪并输入密钥,问题仍然会出现。

下面第一个串行文本框的退出事件处理程序示例。

Private Sub SerialIn_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    Cancel = False

If Not IsNumeric(SerialIn.Value) Then        'validate serial number is numeric

    'error msg serial number is not numeric
    Msg = "Opps, something went wrong!  Serial number was incorrect." _
        & vbNewLine & vbNewLine & "Rescan module serial number."
        MsgBox Msg, vbCritical, "Warning"           'display msg

    Cancel = True                               'stop user from changing focus

    SerialIn.SelStart = 0                       'highlight user text
    SerialIn.SelLength = Len(SerialIn.Value)    'select user text
    'Image1.Picture = LoadPicture(StopLightRed)  'display red stop light
    Exit Sub
Else
    If Not Len(SerialIn.Value) = 19 Then           'validate serial number length
        'error msg incorrect length
        Msg = "Opps, something went wrong!  Serial number was incorrect." _
            & vbNewLine & vbNewLine & "Rescan module serial number."
            MsgBox Msg, vbCritical, "Warning"

        Cancel = True                               'stop user from changing focus

        SerialIn.SelStart = 0                       'highlight user text
        SerialIn.SelLength = Len(SerialIn.Value)    'select user text
        'Image1.Picture = LoadPicture(StopLightRed)  'display red stop light
        Exit Sub
    Else
        SerialInTime.Caption = Now                      'record date and time
        'Image1.Picture = LoadPicture(StopLightYellow)   'display yellow WIP stop light
        Me.SerialOut.SetFocus
        Exit Sub
    End If

结束如果 结束子

新代码:

Private Sub SerialIn_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    Cancel = ValidateSerialIn(SerialIn)
End Sub

Function ValidateSerialIn(ByVal TextBox As Object) As Boolean

If Not IsNumeric(SerialIn.Value) Then        'validate serial number is numeric
'error msg serial number is not numeric
Msg = "Opps, something went wrong!  Serial number was incorrect." _
    & vbNewLine & vbNewLine & "Rescan module serial number."
    msgbox Msg, vbCritical, "Warning"           'display msg

SerialIn.SetFocus
SerialIn.SelStart = 0                       'highlight user text
SerialIn.SelLength = Len(SerialIn.Value)    'select user text
'Image1.Picture = LoadPicture(StopLightRed)  'display red stop light

ValidateSerialIn = True

Else
    If Not Len(SerialIn.Value) = 19 Then           'validate serial number length
'error msg incorrect length
Msg = "Opps, something went wrong!  Serial number was incorrect." _
    & vbNewLine & vbNewLine & "Rescan module serial number."
msgbox Msg, vbCritical, "Warning"

'Cancel = True                               'stop user from changing focus

SerialIn.SelStart = 0                       'highlight user text
SerialIn.SelLength = Len(SerialIn.Value)    'select user text
'Image1.Picture = LoadPicture(StopLightRed)  'display red stop light

ValidateSerialIn = True
Else
    SerialInTime.Caption = Now                      'record date and time
    'Image1.Picture = LoadPicture(StopLightYellow)   'display yellow WIP stop light

    ValidateSerialIn = False
    End If
End If
End Function

第三次使用 Tim 的 TextBox_Change 解决方案:

Private Sub SerialIn_Change()
Dim v
v = ScannedValue1(SerialIn.Text)

If Len(v) > 0 Then
    If Not IsNumeric(v) Then        'validate serial number is numeric
        'error msg serial number is not numeric
        Msg = "Opps, something went wrong!  Serial number was incorrect." _
            & vbNewLine & vbNewLine & "Rescan module serial number."
        msgbox Msg, vbCritical, "Warning"           'display msg

        SerialIn.Text = vbNullString
    Else
        If Not Len(v) = 19 Then           'validate serial number length
            'error msg incorrect length
            Msg = "Opps, something went wrong!  Serial number was incorrect." _
                & vbNewLine & vbNewLine & "Rescan module serial number."
            msgbox Msg, vbCritical, "Warning"

            SerialIn.Text = vbNullString
            'Image1.Picture = LoadPicture(StopLightRed)  'display red stop light
        Else
            SerialInTime.Caption = Now                      'record date and time
            'Image1.Picture = LoadPicture(StopLightYellow)   'display yellow WIP stop light
            SerialOut.SetFocus
        End If
    End If
End If
End Sub

'check if a value ends with vbcrlf or vblf
' - if yes strip that off and return the rest
' - otherwise returns empty string
Function ScannedValue1(vIn) As String
Dim rv As String
If Right(vIn, 2) = vbCrLf Then
    ScannedValue1 = Replace(vIn, vbCrLf, "")
ElseIf Right(vIn, 1) = vbLf Then
    ScannedValue1 = Replace(vIn, vbLf, "")
End If
End Function

Exit 活动的意义远不止于此。在大多数表单中,用户在文本框中输入一个值,然后单击命令按钮 "OK"。 Tbx.Exit 事件发生。如果您单击其他任何地方(例如关闭表单的按钮),也会发生这种情况。在您的系统中,CR 也会触发事件,这似乎是问题所在。

当在您的 Tbx 中输入 CR 或 TAB 时,表单的点击顺序将接管。退出发生,然后是您点击顺序中下一个控件的输入事件。 (将其与用户确定下一个控件时发生的手动焦点更改进行比较。)

因此,解决方案应该不是使用 Exit 事件,而是让 CR 发起焦点更改,使用点击顺序设置,将焦点放在 "OK" 按钮上,然后让按钮的 Enter 事件触发其 Click 事件(如果默认情况下不这样做)。

您可能想要一个循环,其中 CR 触发工作表条目并且焦点返回到 Tbx。这是不使用 Exit 事件的另一个原因,因为您不希望在退出 Tbx 以关闭表单时在工作表中创建条目。

但是,您的表单可能没有或不需要 "OK" 按钮。在那种情况下,我会推荐 Tbx 的 BeforeUpdate 事件。 ExitBeforeUpdate 紧接着出现。然而顺序并不重要(虽然这不是我忘记它的原因:-))但它们的性质。在表单控件、设置焦点或响应焦点更改的上下文中使用退出事件。 BeforeUpdate 明显是指数据。这些事件中的每一个都针对自己的任务进行了微调,因此比另一个更好。

如果你想检测来自扫描仪的 "Enter" 然后使用 Change 事件来检查文本框值是否以 vbCrLfvbLf 结尾(在那order): 如果是,则触发 "scan" 动作。

请注意,您需要将文本框设置为 "multiline=true" 和 "EnterKeyBehaviour = true",以便 Change 事件捕获回车键。

Private Sub TextBox1_Change()

    Dim v

    v = ScannedValue(TextBox1.Text)

    If Len(v) > 0 Then
        TriggerScanAction v
        TextBox1.Value = ""
    End If

End Sub

'check if a value ends with vbcrlf or vblf
' - if yes strip that off and return the rest
' - otherwise returns empty string
Function ScannedValue(vIn) As String
    Dim rv As String
    If Right(vIn, 2) = vbCrLf Then
        ScannedValue = Replace(vIn, vbCrLf, "")
    ElseIf Right(vIn, 1) = vbLf Then
        ScannedValue = Replace(vIn, vbLf, "")
    End If
End Function

'execute some action triggered by a scanned value
Sub TriggerScanAction(v)
    MsgBox "You scanned " & v
End Sub