【问题标题】:Capture keypress completion event in a cell in an Excel worksheet在 Excel 工作表的单元格中捕获按键完成事件
【发布时间】:2019-11-26 11:36:15
【问题描述】:

VBA 有没有办法在 Excel 工作表中按下某个键后捕获事件?

这里回答了一个类似的问题: Is there any event that fires when keys are pressed when editing a cell?
这是带有答案的演示工作簿: http://www.321webs.com/download/30478.htm

这适用于捕获按键事件,检查并可能停止按键,但我想允许所有按键并在每个按键之后触发一个事件。

目的是在用户键入时捕获单元格值。如果用户正在输入“hello”,那么在目标单元格的这些状态下会触发一个事件:

  1. “h”
  2. “他”
  3. “赫尔”
  4. “地狱”
  5. “你好”

如果用户使用退格或删除,它也会在每个实例之后捕获单元格内容。

【问题讨论】:

  • 请分享您如何尝试使该答案适应您的需求。
  • 例如,如果一个单元格有“h”然后有按键“e”,那么我尝试与现有的连接并将目标单元格更改为“he”并关闭事件。这完全没有用。
  • 您是否有一个特定的单元格正在写入,并且需要从中捕获?
  • 我使用交集检查单元格是否在命名范围内。如果超出该范围,我将关闭按键事件检查。

标签: excel vba


【解决方案1】:

那么您发布的示例有什么问题?让我们稍微更正一下。

把这个放到模块中

Option Explicit

Private Type POINTAPI
    x As Long
    y As Long
End Type

Private Type MSG
    hwnd As Long
    Message As Long
    wParam As Long
    lParam As Long
    time As Long
    pt As POINTAPI
End Type


Private Declare Function WaitMessage Lib "user32" () As Long

Private Declare Function PeekMessage Lib "user32" Alias "PeekMessageA" _
    (ByRef lpMsg As MSG, ByVal hwnd As Long, _
     ByVal wMsgFilterMin As Long, _
     ByVal wMsgFilterMax As Long, _
     ByVal wRemoveMsg As Long) As Long

Private Declare Function TranslateMessage Lib "user32" _
    (ByRef lpMsg As MSG) As Long

Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" _
    (ByVal hwnd As Long, _
     ByVal wMsg As Long, _
     ByVal wParam As Long, _
     lParam As Any) As Long

Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" _
    (ByVal lpClassName As String, _
     ByVal lpWindowName As String) As Long

Private Const WM_KEYDOWN As Long = &H100
Private Const PM_REMOVE  As Long = &H1
Private Const WM_CHAR    As Long = &H102
Private bExitLoop As Boolean


Public pTemp As String
Public GlobalArray As Variant


Sub TrackKeyPressInit()

    Dim msgMessage As MSG
    Dim bCancel As Boolean
    Dim iKeyCode As Integer
    Dim lXLhwnd As Long
    GlobalArray = Array(19, 20, 46, 40, 35, 13, 27, 36, 45, 37, 144, 34, 33, 39, 145, 9, 38)
        'BACKSPACE  8
        'BREAK  19
        'CAPS LOCK  20
        'DELETE 46
        'DOWN ARROW 40
        'END    35
        'ENTER 13
        'ESC    27
        'HOME   36
        'INS    45
        'LEFT ARROW 37
        'NUM LOCK   144
        'PAGE DOWN  34
        'PAGE UP    33
        'RIGHT ARROW    39
        'SCROLL LOCK    145
        'TAB    9
        'UP ARROW   38
    On Error GoTo errHandler:
        Application.EnableCancelKey = xlErrorHandler
        bExitLoop = False
        lXLhwnd = FindWindow("XLMAIN", Application.Caption)
    Do
        WaitMessage
        If PeekMessage _
            (msgMessage, lXLhwnd, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE) Then
            iKeyCode = msgMessage.wParam
            TranslateMessage msgMessage
            PeekMessage msgMessage, lXLhwnd, WM_CHAR, WM_CHAR, PM_REMOVE
            If iKeyCode = vbKeyBack Then SendKeys "{BS}"
            'If iKeyCode = vbKeyReturn Then SendKeys "{ENTER}"
            bCancel = False
            Sheet_KeyPress ByVal msgMessage.wParam, ByVal iKeyCode, ByVal Selection, bCancel
            If bCancel = False Then
                PostMessage lXLhwnd, msgMessage.Message, msgMessage.wParam, 0
            End If
        End If
errHandler:
        DoEvents
    Loop Until bExitLoop

End Sub

Sub StopKeyWatch()
    bExitLoop = True
End Sub

Private Sub Sheet_KeyPress(ByVal KeyAscii As Integer, _
                           ByVal KeyCode As Integer, _
                           ByVal Target As Range, _
                           Cancel As Boolean)

    If Not Intersect(Target, Range("A1:D10")) Is Nothing Then
        If IsInArray(KeyAscii, GlobalArray) Then
            StopKeyWatch ' exit if pressed key in globalscope (restricted)
            Cancel = True
            SendKeys "{ENTER}" ' UPDATE CELL
        Else
            pTemp = pTemp & Chr(KeyAscii)
               Target.Offset(0) = pTemp
               Target.Offset(1) = pTemp
            Cancel = True
            Application.ScreenUpdating = True
        End If
    Else
        StopKeyWatch
    End If

End Sub

Function IsInArray(stringToBeFound As Integer, arr As Variant) As Boolean
    IsInArray = (UBound(Filter(arr, stringToBeFound)) > -1)
End Function

并将其放入活动工作表

Private Sub Worksheet_SelectionChange(ByVal Target As Range)
    pTemp = ""
    TrackKeyPressInit
End Sub

【讨论】:

  • 这适用于消息框MsgBox pTemp。是否可以使其与Target.Offset(1) = pTemp 一起使用以使下面的单元格镜像正在编辑的单元格的内容?我试过了,它只适用于第一个字母,然后不允许更多的击键。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多