【问题标题】:Can't set Userform.KeyPreview to true无法将 Userform.KeyPreview 设置为 true
【发布时间】:2017-08-14 00:52:36
【问题描述】:

我在 Excel 中构建了一个表单。它由 3 个命令按钮和一个包含复选框的框架组成。复选框在userform_initialize 处根据 Excel 工作表中的表格动态填充(这个想法很容易让用户自定义)。框架的原因是可能有很多复选框,我希望用户能够滚动它们。

我现在的目标是为表单创建键盘快捷键。我卡住的地方是我不能蛮力为每个复选框编写KeyDown 处理程序,因为我不知道哪些复选框会存在。我意识到如果我可以在表单级别拥有事件处理程序也会更好。谷歌搜索找到了表单的 KeyPreview 属性。不幸的是,VBA IDE 中的属性窗口没有显示它,当我尝试通过将Me.KeyPreview = True 设置为userform_initialize 以编程方式访问它时,VBA 抛出编译错误:“找不到方法或数据成员” - 我期望给出的它不在属性窗口中,但值得一试。

我觉得我显然遗漏了一些东西,所以我想在花时间学习如何编写然后将表单完全重写为 MSDN 示例代码中的类之前先问一下: https://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview(v=vs.110).aspx。 我有那么幸运吗?

我承认我的 VBA 知识有限,我正在寻求扩展它。任何我应该红色的一般概念或上下文将不胜感激。

更新

我现在正在考虑GetAsyncKeyStateApplication.Onkey

据我了解,GetAsyncKeyState 仅在无限 DoEvents 循环中有效。我尝试启动一个,希望表单仍能加载,但当然没有——我陷入了困境。

Application.Onkey 的问题是我无法将事件函数分配给用户表单模块中的键。这让我感到困惑,因为其他事件处理程序可以进入用户表单模块。事实上,我会把它放在Userform_Initialize 过程中。是不是因为不是表单事件而是应用事件?

编辑

我似乎有一些可行的方法,但是对于此处描述的奇怪问题: Event handling class will not fire unless I use a breakpoint when initializing form 谢谢@UGP

【问题讨论】:

  • 该链接适用于 VB.NET 而不是 VBA。它不能简单地应用于它。 KeyPreview 只是 Access VBA 中的一种方法,在 Excel 中不起作用。
  • 也许this可以帮到你。
  • 非常感谢@UGP,我一直抱有希望直到最后。海报说“KeyPress 是一个特例——通过在表单级别打开KeyPreview,我可以在表单的Form_KeyPress 事件中捕获mLastKeyPressedAscii 所需的KeyAscii,并传递它”。看来我又回到了第一方?另外,上面发布的更新。

标签: vba excel userform


【解决方案1】:

这是一个如何工作的例子,找到here

放入一个名为“KeyPreview”的类:

Option Explicit

Dim WithEvents u As MSForms.UserForm
Dim WithEvents t As MSForms.TextBox
Dim WithEvents ob As MSForms.OptionButton
Dim WithEvents lb As MSForms.ListBox
Dim WithEvents dp As MSComCtl2.DTPicker

Event KeyDown(ByVal KeyCode As Integer, ByVal Shift As Integer)
'Event KeyPress(ByVal KeyAscii As Integer)

Private FireOnThisKeyCode As Integer

Friend Sub AddToPreview(Parent As UserForm, KeyCode As Integer)
Dim c As Control
Set u = Parent
FireOnThisKeyCode = KeyCode
For Each c In Parent.Controls
Select Case TypeName(c)
Case "TextBox"
Set t = c
Case "OptionButton"
Set ob = c
Case "ListBox"
Set lb = c
Case "DTPicker"
Set dp = c
End Select
Next c
End Sub

Private Sub u_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = FireOnThisKeyCode Then RaiseEvent KeyDown(KeyCode, Shift)
End Sub

Private Sub t_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = FireOnThisKeyCode Then RaiseEvent KeyDown(KeyCode, Shift)
End Sub

Private Sub ob_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = FireOnThisKeyCode Then RaiseEvent KeyDown(KeyCode, Shift)
End Sub

Private Sub lb_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = FireOnThisKeyCode Then RaiseEvent KeyDown(KeyCode, Shift)
End Sub

Private Sub dp_KeyDown(KeyCode As Integer, ByVal Shift As Integer)
If KeyCode = FireOnThisKeyCode Then RaiseEvent KeyDown(KeyCode, Shift)
End Sub

输入用户表单:

Option Explicit 

Dim WithEvents kp As KeyPreview 

Private Sub UserForm_Initialize() 
Set kp = New KeyPreview 
kp.AddToPreview Me, 114 
End Sub 

Private Sub kp_KeyDown(ByVal KeyCode As Integer, ByVal Shift As Integer) 
MsgBox "F3 was pressed..." 
End Sub 

它适用于 TextBoxesOptionButtonsListBoxesDTPickers。其他可能获得焦点的控件也需要处理。

【讨论】:

  • 非常感谢@UGP!我可能需要几天时间才能尝试一下,因为朝九晚五的工作不是朝九晚五,但我感谢您的帮助!
  • 再次感谢@UGP,正如您从stackoverflow.com/questions/45662687/… 看到的那样,您的方法似乎奏效了,但我遇到了一个奇怪的问题,我认为有必要单独发帖。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-06-02
  • 2023-03-27
  • 2019-01-09
  • 2011-12-11
  • 2019-07-12
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多