Excel VBA - 在用户窗体上手动调用文本框退出事件?

Posted

技术标签:

【中文标题】Excel VBA - 在用户窗体上手动调用文本框退出事件?【英文标题】:Excel VBA - Calling TextBox Exit Event on Userform manually? 【发布时间】:2016-07-22 20:21:07 【问题描述】:

我正在构建一个用户表单,其中有两个文本框可以输入日期。输入日期后,我将在 Exit 事件触发时验证它们。如果验证结果表明用户数据不是所需要的,则会通知用户,清除文本框,并将焦点返回到文本框。

如果用户使用鼠标在框外进行选择,而不是 Tab,就会出现问题。如果使用 Tab,它会按预期完美触发,并清除该字段并返回焦点。如果使用鼠标,它不会触发。根据this article,这是预期行为(适用于 Access,但我没有看到类似的 Excel 相关 MSDN 文章。)

所以我尝试了AfterUpdate 事件。但是,SetFocusAfterUpdate 事件中不起作用,我假设是因为在对this question 的响应中概述的事件链。因此,我没有办法在它触发后将焦点返回到文本框。该线程有一个建议作为SetFocus 对另一个控件的替代答案并作为解决方法返回,但这对我不起作用,所以我认为这可能是特定于访问的解决方法。

我考虑的最后一个选择是让AfterUpdate 事件只调用Exit 事件,但是Exit 事件有一个必需的参数(ByVal Cancel As MSForms.ReturnBoolean),这是您取消退出并返回的方式用户到文本框。因此,没有一个值可以传递给它,它不会引发我能找到的错误(我发现最接近的是传递Nothing,但在稍后尝试将其设置为True 时失败了取消退出。)

有没有办法实现我在这里寻找的东西,或者我应该坚持AfterUpdate 而忽略我想要实现的SetFocus

【问题讨论】:

对展示您现有的代码非常有帮助。但是,您不必将所有代码都放在事件处理程序中:将日期比较移动到独立的子程序中,然后从您的事件处理程序中触发它。新的 Sub 负责将焦点设置回适当的文本框。 谢谢蒂姆,我会先尝试将其移至单独的子目录。这实际上可以帮助我减少一些代码,因为我目前对不同的文本框有一些重复。我没有发布完整的代码,因为它很长(它正在检查不同日期和当前时间之间的很多比较),但如果需要,我会回来编辑相关位。 【参考方案1】:

我知道几个月前已经回答了这个问题,但提供了替代解决方案。对于任何发现此问题的人。

对于 Excel 文本框数据的验证,请使用更新前事件,它在更新后事件之前触发,并且能够防止失去对控件的焦点。

根据您的要求修改示例代码

记住Cancel = True 停止对控件的控件更新并保持焦点。

Private Sub TextBox1_BeforeUpdate(ByVal Cancel As MSForms.ReturnBoolean)
    Cancel = doValidation(Textbox1.Text) 'Validation Route
End Sub

Private Function doValidation(strText) as Boolean
    'Do Validation
    if Valid then
        doValidation = False
    Else
        msgBox "Not Valid"
        doValidation = True
    End if
End Sub

在我看来,这是在 Excel 用户表单文本框中验证输入的最简单方法

目前我无法找到正确的 MSDN 文章,Google 想要返回的只是访问结果。

【讨论】:

【参考方案2】:

Exit 事件适用于所有触发Enter 的鼠标单击,用于窗体上的另一个控件。但是,当您直接单击表单而不是任何其他控件时,什么也没有发生。

在这里,使用ActiveControl 属性来确定您在退出并移动到用户表单之前的最后一个控件。

示例代码,根据您的要求重新编写。

Private Sub TextBox1_Exit(ByVal Cancel As MSForms.ReturnBoolean)
    Call doValidation(Me.TextBox1.Text)  '/ Validation Routine when user leaves TextBox
End Sub

Private Sub UserForm_Click()
    '/ If user clicked on the user form instead of ay other control
    If Me.ActiveControl.Name = Me.TextBox1.Name Then
        Call doValidation(Me.TextBox1.Text)  '/ Validation Routine when user leaves TextBox
    End If
End Sub

Private Sub doValidation(strText)
        MsgBox strText
End Sub

建议:对于日期输入,请使用DateTimePicker 而不是TextBox,这样可以避免您以后遇到很多麻烦。

【讨论】:

这最终是我能找到的最佳分辨率,谢谢。我不能使用 DateTimePicker,因为它需要在 x64 版本的 Office 中不起作用的 ActiveX 控件。 啊 64 位的困境... :)【参考方案3】:

在 VBA 中,您可以使用 Call Subname 一词来调用任何已定义的子或函数: 例如调用 Textbox1_exit(params)

但是,从有点令人困惑的描述来看,我认为您的问题是您将自己限制在几个事件函数中。我建议探索所有事件函数,看看哪一个最适合您的事件触发。 以下是 Access VBA 中事件及其序列的列表: https://msdn.microsoft.com/en-us/library/office/jj249049.aspx

以及表单事件的顺序:

https://support.office.com/en-us/article/Order-of-events-for-database-objects-e76fbbfe-6180-4a52-8787-ce86553682f9

我认为对于您的应用程序,您为某些组件提供 lost_focus 或 got_focus 的描述可能有用。 此外,您可以手动将焦点设置到几乎任何组件,它是一个内置方法:compName.SetFocus()

【讨论】:

不幸的是,这没有帮助。链接的文章是针对 Access 的,如果您进一步阅读,您会注意到 Excel VBA 没有 Lost_Focus 事件,它被捆绑到 Exit 事件中,这需要一个似乎不能手动调用的参数。此外,SetFocus 在 AfterUpdate 中不起作用,这是(轻松)捕获用户退出控件并单击其他任何位置的唯一方法。最后,在很多情况下,通常使用 Call 并不是最佳实践,因为您无法返回值,并且使用括号会导致求值。 猜我看错了我以为他在制作访问表单。谢谢

以上是关于Excel VBA - 在用户窗体上手动调用文本框退出事件?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Excel 2010 VBA 用户窗体文本框字体会根据框架的大小而变化?

VBA一例:如何保持文本框焦点

Excel VBA入门用户窗体开发

根据单选按钮选择组合(VBA Excel)用可变文本填充文本框

Excel VBA,如果一个或多个文本框为空,如何禁用命令按钮

单击保存按钮后如何在用户窗体中添加依赖于另一个组合框的excel vba组合框而不影响清除数据功能