zoukankan      html  css  js  c++  java
  • VBA一例:如何保持文本框焦点

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

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

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

     

    我们知道扫描枪录入实际上等同于往文本框录入一段字符串并回车, 那么刚才的要求理论上可以在文本框的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

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

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

  • 相关阅读:
    Swiper 自定义分页器 并实现多个用省略号显示
    Swiper插件 滚动自动切换标题
    HTML 点击返回按钮返回上一页,没有上一页转到首页
    HTML input 模仿Android原生焦点效果
    HTML基础篇(二、HTML文档结构)
    Vue开发 添加微信分享功能(全局分享)
    JS 命令模式(记读《JavaScript设计模式与开发实践》笔记)
    Vue中v-for配合使用Swiper插件问题
    permission-sudo获取权限
    使用es6模块化后打开页面报错
  • 原文地址:https://www.cnblogs.com/cancelpj/p/2234731.html
Copyright © 2011-2022 走看看