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
事件。但是,SetFocus
在AfterUpdate
事件中不起作用,我假设是因为在对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)用可变文本填充文本框