ExcelHome技术论坛

 找回密码
 免费注册

QQ登录

只需一步,快速开始

快捷登录

搜索
EH技术汇-专业的职场技能充电站 妙哉!函数段子手趣味讲函数 Excel服务器-会Excel,做管理系统 效率神器,一键搞定繁琐工作
HR薪酬管理数字化实战 Excel 2021函数公式学习大典 Excel数据透视表实战秘技 打造核心竞争力的职场宝典
让更多数据处理,一键完成 数据工作者的案头书 免费直播课集锦 ExcelHome出品 - VBA代码宝免费下载
用ChatGPT与VBA一键搞定Excel WPS表格从入门到精通 Excel VBA经典代码实践指南
查看: 2540|回复: 4

[求助] 请问大神,如何实现Excel单元格的change或keypress事件

[复制链接]

TA的精华主题

TA的得分主题

发表于 2018-2-2 20:25 | 显示全部楼层 |阅读模式
看到国外一段响应Excel单元格按键事件的代码,在键盘输入内容到单元格时,先拦截信息(PeekMessage),判断是否符合条件(代码的目的是不能输入数字),不符合条件则不传递信息(PostMessage)。而在Excel正常情况下,是需要按了回车键或者移动鼠标到其他位置,单元格才会响应change。
这种实时获取输入内容的方式非常好,在做逐步提示功能时,可以不再使用非常别扭难看的textbox控件。

我的问题是:

我只能用这段代码实时获取顺序输入的内容,但输入过程中把光标移到某个字符,就得不到正确的字符串顺序了。例如:我先在A1单元格输入EXCELHME,然后把光标插到H后面,输入O,得到的字符串是EXCELHMEO,而不是EXCELHOME。请问这个问题怎么解决?请大神出手。
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  

Sub TrackKeyPressInit()  

    Dim msgMessage As MSG  
    Dim bCancel As Boolean  
    Dim iKeyCode As Integer  
    Dim lXLhwnd As Long  

    On Error GoTo errHandler:  
        Application.EnableCancelKey = xlErrorHandler  
        'initialize this boolean flag.  
        bExitLoop = False  
        'get the app hwnd.  
        lXLhwnd = FindWindow("XLMAIN", Application.Caption)  
    Do  
        WaitMessage  
        'check for a key press and remove it from the msg queue.  
        If PeekMessage _  
            (msgMessage, lXLhwnd, WM_KEYDOWN, WM_KEYDOWN, PM_REMOVE) Then  
            'strore the virtual key code for later use.  
            iKeyCode = msgMessage.wParam  
           'translate the virtual key code into a char msg.  
            TranslateMessage msgMessage  
            PeekMessage msgMessage, lXLhwnd, WM_CHAR, _  
            WM_CHAR, PM_REMOVE  
           'for some obscure reason, the following  
          'keys are not trapped inside the event handler  
            'so we handle them here.  
            If iKeyCode = vbKeyBack Then SendKeys "{BS}"  
            If iKeyCode = vbKeyReturn Then SendKeys "{ENTER}"  
           'assume the cancel argument is False.  
            bCancel = False  
            'the VBA RaiseEvent statement does not seem to return ByRef arguments  
            'so we call a KeyPress routine rather than a propper event handler.  
            Sheet_KeyPress _  
            ByVal msgMessage.wParam, ByVal iKeyCode, ByVal Selection, bCancel  
            'if the key pressed is allowed post it to the application.  
            If bCancel = False Then  
                PostMessage _  
                lXLhwnd, msgMessage.Message, msgMessage.wParam, 0  
            End If  
        End If  
errHandler:  
        'allow the processing of other msgs.  
        DoEvents  
    Loop Until bExitLoop  

End Sub  

Sub StopKeyWatch()  

    'set this boolean flag to exit the above loop.  
    bExitLoop = True  

End Sub  


'\\This example illustrates how to catch worksheet  
'\\Key strokes in order to prevent entering numeric  
'\\characters in the Range "A1:D10" .  
Private Sub Sheet_KeyPress(ByVal KeyAscii As Integer, _  
                           ByVal KeyCode As Integer, _  
                           ByVal Target As Range, _  
                           Cancel As Boolean)  

    Const MSG As String = _  
    "Numeric Characters are not allowed in" & _  
    vbNewLine & "the Range:  """  
    Const TITLE As String = "Invalid Entry !"  

    If Not Intersect(Target, Range("A1:D10")) Is Nothing Then  
        If Chr(KeyAscii) Like "[0-9]" Then  
            MsgBox MSG & Range("A1:D10").Address(False, False) _  
            & """ .", vbCritical, TITLE  
            Cancel = True  
        End If  
    End If  

End Sub  




TA的精华主题

TA的得分主题

 楼主| 发表于 2018-2-5 21:10 | 显示全部楼层
自顶一下。
回答了很多问题,自己问的问题却从来没人回答上来!
也许我问的问题太难了!这个问题,会的人应该没有。

TA的精华主题

TA的得分主题

发表于 2018-12-30 14:43 | 显示全部楼层
[广告] Excel易用宝 - 提升Excel的操作效率 · Excel / WPS表格插件       ★免费下载 ★       ★ 使用帮助
高手永远在付出!!顶你

TA的精华主题

TA的得分主题

发表于 2019-11-22 01:05 | 显示全部楼层
[广告] VBA代码宝 - VBA编程加强工具 · VBA代码随查随用  · 内置多项VBA编程加强工具       ★ 免费下载 ★      ★使用手册
路过看一下,真的没人会么

TA的精华主题

TA的得分主题

发表于 2023-9-17 19:59 | 显示全部楼层
您需要登录后才可以回帖 登录 | 免费注册

本版积分规则

手机版|关于我们|联系我们|ExcelHome

GMT+8, 2024-11-18 10:57 , Processed in 0.038385 second(s), 9 queries , Gzip On, MemCache On.

Powered by Discuz! X3.4

© 1999-2023 Wooffice Inc.

沪公网安备 31011702000001号 沪ICP备11019229号-2

本论坛言论纯属发表者个人意见,任何违反国家相关法律的言论,本站将协助国家相关部门追究发言者责任!     本站特聘法律顾问:李志群律师

快速回复 返回顶部 返回列表