VBA一例:如何保持文本框焦点
Posted KL58
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VBA一例:如何保持文本框焦点相关的知识,希望对你有一定的参考价值。
- 缘起
在Excel的VBA编程中,设计一个用于录入的用户窗体,该窗体包含1个文本框和2个按钮,文本框用于扫描枪的录入。
要求扫描枪可以连续录入,即每扫描完一个条码,文本框自动清空,文本框继续获得焦点。
我们知道扫描枪录入实际上等同于往文本框录入一段字符串并回车, 那么刚才的要求理论上可以在文本框的KeyDown事件子过程中编程,先判断录入的字符是否回车键,如果是则清空文本框。
2 If KeyCode = 13 Then TextBox1.Value = ""
3 End Sub
至此,如果是VB编程,要求本应完成。但实际运行发现,扫描枪录入后,文本框虽然自动清空,但是焦点却跑到下一个按钮上去了。
- 求因
未及细想,手动用SetFocuse方法来设置文本框获得焦点。
2 If KeyCode = 13 Then
3 TextBox1.Value = ""
4 TextBox1.SetFocus
5 End If
6 End Sub
程序再运行,焦点还是跑到按钮上。不解,遂跟踪之,发现是在执行完KeyDown事件子过程后(End Sub语句后)发生的焦点转移,难怪SetFocus方法显得没有起作用。
为什么执行完KeyDown事件后会发生焦点自动转移呢?百思不得其解,遂清除代码反复测试,终于搞清楚一个结论:在Excel VBA编程中,文本框控件接收到回车键以后,会将焦点移到Tab键顺序的下一个对象。(这一结论通过参阅文本框控件的EnterKeyBehavior属性说明也可侧面印证)
之所以特别强调是在Excel VBA编程中,是因为我依稀仿佛记得在VB6里面,系统是不会“聪明的”帮文本框做焦点转移的。(多年不用VB6了,回忆的事情未必正确!但是,其它许多面向事件的UI编程里面,系统是不会自动帮忙文本框做焦点转移的。)
- 证果
既然查明原委,自然应找寻解决之道,且看我折腾。从文本框按下回车键到Button1按钮获得焦点,依次产生如下事件:
2
3 TextBox1_Exit( ByVal Cancel As MSForms.ReturnBoolean)
4
5 Button1_Enter( )
6
7 Button1_KeyPress( ByVal KeyANSI As MSForms.ReturnInteger)
8
9 Button1_KeyUp( ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As fmShiftState)
我的初步想法既然焦点转移是不可干预的系统行为,那就“事后”将它逆转回来,如此从Exit事件开始往后都可以用SetFocus方法将焦点重新设回文本框(此处说法不严谨,如果在Exit事件里面实现,不适用SetFocus方法,而是用Cancel=True,个中原因请自查VBA帮助)。但这样带来一个逻辑问题,从业务上判断,只有在文本框输入操作时,才需要让文本框保持焦点,其它时候不需要,否则会导致除了文本框之外的其它控件都得不到焦点,无法操作!因此干预焦点转移的代码逻辑只能在KeyDown事件中实现。
既然不能“事后”逆转,那就只能从中打断了。我又尝试了在KeyDown事件中用 Exit Sub 或 Call 跳出子过程,未果,系统仍然会自动做焦点转移。
灵光乍现间,我想到既然不能打断子过程,何不打断事件。方法是再做一个UserForm2窗体,当在文本框按回车时,隐藏现有窗体,显示
UserForm2窗体,这时会触发UserForm2的Activate事件, 同时窗体显示的切换也打断了文本框向按钮转移焦点,那么只要在Activate事件中再隐藏UserForm2窗体,显示原窗体,设置焦点到文本框就OK了。这个事件是在KeyDown事件子过程中通过代码人为产生的,是受控的,因此可以将其看作是KeyDown事件代码逻辑的一部分。
2
3 Private Sub TextBox1_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
4 If KeyCode = 13 Then
5 TextBox1.Value = ""
6 UserForm1.Hide
7 UserForm2.Show
8 End If
9 End Sub
2
3 Private Sub UserForm_Activate()
4 UserForm2.Hide
5 UserForm1.Show
6 UserForm1.TextBox1.SetFocus
7 End Sub
实测效果非常理想,窗体切换的速度肉眼根本察觉不到,感觉就是文本框保持焦点,用条码枪连续输入,不需要键盘和鼠标辅助定位。
当我点击它时,如何使文本框不可编辑?
【中文标题】当我点击它时,如何使文本框不可编辑?【英文标题】:How can I make textbox not editable when I click out of it? 【发布时间】:2021-08-31 06:45:24 【问题描述】:我有一个 TreeView,里面是 TextBoxes。 它看起来像这样: 我正在努力实现:
当我点击另一个复选框时应该失去焦点 当我点击已编辑的复选框时,它应该失去焦点,而不是保持可编辑状态。我可以通过按 Enter 或 Tab 键(或任何其他键)来实现类似的效果。
private void OnModuleNameEditKeyDownHandler(object sender, KeyEventArgs e)
if (e.Key == Key.Return || e.Key == Key.Tab)c
ModuleName.Visibility = Visibility.Visible;
ModuleNameEdit.Visibility = Visibility.Collapsed;
有办法吗? 功能是当我双击 TextBox 时,它变为可编辑,但我希望,当单击超出复选框范围时,在再次双击它之前不对其进行编辑。
【问题讨论】:
如果没有带有 UI 元素布局的至少部分 XAML 代码,将无法回答您的问题。 ModuleName、ModuleNameEdit 的元素是什么?它们与 IsReadOnly 有什么关系?为什么更改 IsReadOnly 会更改项目的可视化? 你为什么不能通过 LostFocus 和 DoubleClick 事件来做到这一点? @JonathanWillcock 如何检查文本框何时失去焦点(顺便说一句,有逻辑焦点和键盘焦点我不明白)所以我可以使其 Visibility.Collapsed ? 在 XAML 中为 TextBox 输入 "LostFocus=" ,它会提示您创建一个新的事件处理程序。 【参考方案1】:创建静态变量来存储工作节点(UIElement/Textbox)。并尝试在键盘焦点丢失时设置此事件。
静态变量:
public static TextBox CurrentTextBox = null;
在鼠标双击事件中:
CurrentTextBox = sender as TextBox;
CurrentTextBox.IsReadOnly = false;
CurrentTextBox.IsVisible = true;
在键盘焦点丢失事件中:
CurrentTextBox.IsReadOnly = true;
CurrentTextBox .IsVisible = false;
CurrentTextBox = null;
【讨论】:
以上是关于VBA一例:如何保持文本框焦点的主要内容,如果未能解决你的问题,请参考以下文章