VBA版本:7.1
系统:Win10 64位
VBA虽然是一门古老的语言,但是在办公方面仍然有奇效,特别是Excel模板打印,本人浸淫打印2年多,平均每天打印不下十张POP,经过不断探索,发现一条通过VBA实现自动化模板打印的解决之道。今天分享一下在UserForm中实现快捷键的方式
一、KeyMap
按键映射,每个键按下后,会有一个keyCode,和一个shift,前者表示单个键对应的键码,后者表示控制键的组合码。
65 | a |
66 | b |
67 | c |
68 | d |
69 | e |
70 | f |
71 | g |
72 | h |
73 | i |
74 | j |
75 | k |
76 | l |
77 | m |
78 | n |
79 | o |
80 | p |
81 | q |
82 | r |
83 | s |
84 | t |
85 | u |
86 | v |
87 | w |
88 | x |
89 | y |
90 | z |
188 | , |
190 | . |
191 | / |
186 | ; |
222 | ' |
219 | [ |
221 | ] |
220 | \ |
20 | Caps |
192 | ` |
49 | 1 |
50 | 2 |
51 | 3 |
52 | 4 |
53 | 5 |
54 | 6 |
55 | 7 |
56 | 8 |
57 | 9 |
48 | 0 |
189 | - |
187 | = |
8 | Cancel |
46 | Delete |
45 | Ins |
36 | Home |
35 | End |
33 | PageUp |
34 | PageDown |
44 | PageDown |
145 | ScrlLk |
19 | Pause |
123 | F12 |
122 | F11 |
27 | ESC |
45 | Ins |
112 | F1 |
113 | F2 |
114 | F3 |
115 | F4 |
116 | F5 |
117 | F6 |
118 | F7 |
119 | F8 |
120 | F9 |
121 | F10 |
38 | Up |
40 | Down |
37 | Left |
39 | Right |
93 | Menu |
1 | Shift |
2 | Ctrl |
4 | Alt |
例如:Ctrl + Shift + a,则Keycode = 65(a的KeyCode),Shift = 3(Ctrl=1 + Shift=2),注意此处Shift是Shift、Ctrl、Alt 3个键统称,
VBA有内置KeyCodeConstaints枚举常量,可以知道每个键对应的KeyCode,但是我没找到怎么通过KeyCode找到对应的键名,只好一个键一个键按,然后录入进去😶。可以直接将KeyCode的映射表复制到单元格内,利用Match或者Vlookup函数查询每次按键对应的按键名。
如下图:我将KeyCode与KeyName的映射保存在从101行开始往后,每次按键时将KeyCode填入A100,然后在B100中通过公式查找KeyCode对应的KeyName,在程序中就可以直接读取B100的值获取KeyName
通过textbox设置快捷键:
'keyUP快捷键注册
Private Sub ShortKeyTBox_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
ShortKeyTBox = getShortKey(KeyCode, Shift)
applyCBT.SetFocus '阻止后续的控制键keyup事件,将焦点转移到别处
ShortKeyTBox.SetFocus '再转移回来
End Sub
'快捷键录入的文本框调用此代码,获取用户按下的键名组合,并返回组合字符串
Public Function getShortKey(ByVal KeyCode As Integer, ByVal Shift As Integer)
Dim controlKey As String
Dim KeyName As String
Dim rowCount As Integer
If KeyCode = 16 Or KeyCode = 17 Or KeyCode = 18 Then '过滤单独的Ctrl,Shift,Alt按键事件
Exit Function
End If
Sheet1.Range("B28") = Shift '将Shift组合码保存在单元格中
Select Case Shift '根据Shift组合码分析控制按键组合,Shift=1,Ctrl=2,Alt=4,3者任意组合
Case 0
controlKey = ""
Case 1
controlKey = "Shift + "
Case 2
controlKey = "Ctrl + "
Case 4
controlKey = "Alt + "
Case 5
controlKey = "Alt + Shift + "
Case 6
controlKey = "Ctrl + Alt + "
Case 3
controlKey = "Ctrl + Shift + "
End Select
KeyName = ShortKeyTBox '如果是按下的0-9或者字母符号,并且没有按下控制键,可以直接在文本框中获取到按键名,不用通过KeyCode获取映射,如果不是文本框则此方法无效
If KeyName = "" Then '查询KeyCode对应的KeyName
Sheet1.Range("A100") = KeyCode
KeyName = Sheet1.Range("B100")
End If
If KeyName = "" Then '没查到KeyName,用户手动输入
KeyName = InputBox(CStr(KeyCode) + "键名为空,请输入您刚按下的最后一个键键帽上的字符,如F1键则输入'F1'", "键盘映射") '获取用户输入的对话框
rowCount = Sheet1.Range("A" & Rows.count).End(xlUp).Row '获取映射表最后一行行号,用于追加新信息
Sheet1.Range("A" & CStr(rowCount + 1)) = KeyCode '将KeyCode追加到映射表格的最后一行
Sheet1.Range("B" & CStr(rowCount + 1)) = KeyName '将KeyName追加到映射表格的最后一行
End If
Sheet1.Range("B29") = KeyCode '将KeyCode保存在单元格中
Sheet1.Range("C29") = KeyName '将KeyName保存在单元格中
getShortKey = controlKey + KeyName '快捷键的组合名
End Function
没有找到全局按键监听方式,好像VBA的按键不是冒泡机制,没有传递或者无法在按键触发的起点进行拦截,只能针对获取焦点的对象进行设置,所有想要实现全局快捷键。。。也不是不可以,将每一个控件都设置一下就可以了😎
例如为TextBox注册一个打印快捷键:
先通过前面的方法录入快捷键,例如Ctrl+Enter,Keycode=13,Shift=2
然后:
'注册快捷键的TextBox,在KeyUp中注册 Private Sub PD1PLUTB_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, _ ByVal Shift As Integer) Call setPrintListener(KeyCode, Shift) End Sub '注册快捷键 Sub setPrintListener(ByVal KeyCode As Integer, _ ByVal Shift As Integer) If KeyCode = Sheet1.Range("B29") And Shift = Sheet1.Range("B28") Then Call printNow End If End Sub Public Sub printNow() Excel.ActiveSheet.PrintOut If Sheet1.Range("B27") Then '打印后userform失去焦点,需要重新打开获取焦点 singlePageUSF.Hide singlePageUSF.Show End If End Sub
这样在注册了快捷键的文本框内按Ctrl+Enter,Excel就会打印激活的sheet
但是我比较懒,我觉得两个键还不够快,不够丝滑,所以我想将快捷键设置为一个键打印,也就是一键打印。比如说设置为空格(根据实际情况,需要输入的内容只有数字,没有其他的字符,所有可以设置为空格),但是有个问题,文本框中按空格键效果你懂的,就是多了一个空格,就算注册了快捷键也会多一个空格,一开我想将空格键KeyDown时之前文本框内的类容保存下来,空格键KeyUp之后再重新设置回去,我试了一下,效果差强人意,但还是不够丝滑,中间明显有一个过渡期,多了一个空格然后全部消失,然后再全部变回去。
经过一顿搜索,我找到了一点线索,耶~。
TextBox有个Boolean属性叫Locked(锁),当Locked属性为true时,文本框无法输入信息,但是可以选中,也可以监听Key事件,所以问题解决了:
'这里KeyCode = 32可以改成自己设置的,或者某个单元格,反正是某个变量,我这是之前测试的,还没改
Private Sub PD1PromotionStartDateTB_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
If KeyCode = 32 Then
PD1PromotionStartDateTB.Locked = True '如果按下了目标键,锁住TextBox,实现了过滤效果
End If
End Sub
Private Sub PD1PromotionStartDateTB_KeyPress(ByVal KeyAscii As MSForms.ReturnInteger)
End Sub
Private Sub PD1PromotionStartDateTB_KeyUp(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)
Call setPrintListener(KeyCode, Shift)
PD1PromotionStartDateTB.Locked = False '释放目标键后,将TextBox解锁
End Sub
效果非常丝滑~