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

二楼 Robot兄弟 已经提供了更优秀的解决办法,此文只为立此存照,记录楼猪分析思路,请寻找答案的童鞋直接大跨步跳过~~

 

  • 缘起

在Excel的VBA编程中,设计一个用于录入的用户窗体,该窗体包含1个文本框和2个按钮,文本框用于扫描枪的录入。

要求扫描枪可以连续录入,即每扫描完一个条码,文本框自动清空,文本框继续获得焦点。

 VBA一例:如何保持文本框焦点_第1张图片

我们知道扫描枪录入实际上等同于往文本框录入一段字符串并回车, 那么刚才的要求理论上可以在文本框的KeyDown事件子过程中编程,先判断录入的字符是否回车键,如果是则清空文本框。

1  Private  Sub TextBox1_KeyDown(ByVal KeyCode  As MSForms.ReturnInteger, ByVal Shift  As  Integer)
2      If KeyCode =  13  Then TextBox1.Value =  ""
3  End Sub

至此,如果是VB编程,要求本应完成。但实际运行发现,扫描枪录入后,文本框虽然自动清空,但是焦点却跑到下一个按钮上去了。

 

  • 求因

未及细想,手动用SetFocuse方法来设置文本框获得焦点。

1  Private  Sub TextBox1_KeyDown(ByVal KeyCode  As MSForms.ReturnInteger, ByVal Shift  As  Integer)
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按钮获得焦点,依次产生如下事件:

1 TextBox1_KeyDown( ByVal KeyCode  As MSForms.ReturnInteger, ByVal Shift  As fmShiftState)
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事件代码逻辑的一部分。

1  ' UserForm1窗体
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

 

1  ' UserForm2窗体
2 
3  Private  Sub UserForm_Activate()
4     UserForm2.Hide
5     UserForm1.Show
6     UserForm1.TextBox1.SetFocus
7  End Sub

实测效果非常理想,窗体切换的速度肉眼根本察觉不到,感觉就是文本框保持焦点,用条码枪连续输入,不需要键盘和鼠标辅助定位。

 

这是我的解决之道,可能比较繁琐,如果你有更高明的方法,欢迎莅临指导!

你可能感兴趣的:(VBA一例:如何保持文本框焦点)