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

Posted KL58

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了VBA一例:如何保持文本框焦点相关的知识,希望对你有一定的参考价值。

  • 缘起

在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)

3 TextBox1_Exit( ByVal Cancel As MSForms.ReturnBoolean)

5 Button1_Enter( )

7 Button1_KeyPress( ByVal KeyANSI As MSForms.ReturnInteger)

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窗体

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窗体

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一例:如何保持文本框焦点的主要内容,如果未能解决你的问题,请参考以下文章

弹出窗口时如何保持文本框的焦点

如何在onchange事件后某个文本框得到焦点并传值?

VBA如何使用上下左右键控制焦点

vba textbox在失去焦点后如何重新获取焦点

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

wpf 焦点定位到 文本框开头? 2:如何按Tab,让焦点不进入第3个文本框,意思是在前两个文本框中切换