• 对话框不响应按键消息


    今天给测试程序加了热键和按键响应函数,然而未能按照预期响应。一瞬间有点懵!

    查了一下资料发现焦点始终没有到窗口上而是在窗口的按钮上,于是问题就在这儿了,消息被按钮或者父窗口处理了。以下是查到的部分资料,文尾有对window消息深入介绍的链接:

    基于MFC对话框的应用程序,CDialog类的消息循环中去掉了TranslateAccelerator函数,因此不能响应热键;同时由于对话框上可能有很多控件,且默认情况下这些子窗口已经截获了焦点,因此键盘消息已经被控件捕获了;同时为了实现控件焦点切换和对话框默认行为,  VK_TAB、VK_LEFT、VK_RIGHT、VK_UP、VK_DOWN、 VK_RETURN、VK_ESCAPE 等键已经被截获处理,因此对话框没有控件时仍然不能完全响应按键消息。对话框不能收到WM_KEYDOW,关键是基类的CDialog::PreTranslateMessage(pMsg)做了手脚,所以你必须在它做手脚之前做自己想做的事。
    在对话框程序中,我们经常是利用对话框上的子控件进行命令响应来处理一些事件。如果我们想要让对话框(子控件的父窗口)类来响应我们的按键消息,我们可以通过ClassWizard对WM_KEYDOWN消息进行响应,当程序运行后,我们按下键盘上的按键,但对话框不会有任何的反应。这是因为在对话框程序中,某些特定的消息,例如按键消息,它们被Windows内部的对话框过程处理了(即在基类中完成了处理,有兴趣的读者可以查看MFC的源代码),或者被发送给子控件进行处理,所以我们在对话框类中就捕获不到按键的消息了。
    有次,我在一个对话框(有水平滑块与垂直滑块)上面的组合框控件(或者是下拉列表框控件)中浏览控件项,但是主对话框的滑块并没有移动。我想这也能够用上述理由解释。
    既然我们知道了这个处理的过程,我们就可以找到底层处理按键消息的函数,然后在子类中重载它,就可以在对话框程序中处理按键消息了。
    我查了资料,有人用ProcessMessageFilter来处理,PreTranslateMessage,ProcessMessageFilter都是虚函数,你重载就行。但是,我在VS10里没有找到ProcessMessageFilter虚函数,估计在VC6.0里面有,我想ProcessMessageFilter可能已经过时了,因此,不推荐大家使用这个函数,而是PreTranslateMessage函数更合适。
    与按键相关的消息大概有4个:WM_KEYDOWN、WM_KEYUP、WM_SYSKEYDOWN、WM_SYSKEYUP,需要说明的包括以下几点:
        1、KEY与SYSKEY消息的区别在于:如果某个按键动作的同时,ALT键或F10键被按下,则发送SYSKEY消息,否则发送KEY消息;
        2、某个按键动作依次产生WM_KEYDOWN和WM_KEYUP消息;
        3、一个按键一直按着不放,会按一定间隔时间不断发送WM_KEYDOWN消息;
        4、单键动作最好响应WM_KEYUP,组合键动作响应WM_KEYDOWN或WM_SYSKEYDOWN;

        关于几个按键消息的具体解释,请参考MSDN。

    BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)   
    {
    if(pMsg->message == WM_KEYUP) 
    {
    // 响应keyup消息
    if(pMsg->wParam == VK_RETURN)
    {
    // 回车
    }
    }
    return CDialog::PreTranslateMessage(pMsg); 
    }
    
        那么怎样判断组合键呢?使用GetKeyState函数。示例代码如下:
    BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)   
    {
    if(pMsg->message == WM_KEYDOWN)
    {
    // 组合键响应keydown消息
    if( pMsg->wParam == VK_SPACE && (GetKeyState(VK_SHIFT) & 0x8000))
    {
    // 空格 + Shift
    }
    }
    else if(pMsg->message == WM_SYSKEYDOWN)
    {
    // Alt组合键响应syskeydown消息
    if( pMsg->wParam == 'A' && (HIWORD(pMsg->lParam) & KF_ALTDOWN))
    {
    // A + Alt
    }
    }
    
    return CDialog::PreTranslateMessage(pMsg); 
    }

    另外,还有GetAsyncKeyState和GetKeyboardState等类似函数,涉及到逻辑按键和物理按键值等问题,大家可以参考MSDN的说明。

    目前window过程中对消息的分类以及消息队列进行处理的函数包括:

     

    以下是消息的传递路径

    GetMessage与PeekMessage

    GetMessage 有消息且该消息不为WM_QUIT,返回TRUE。
                  有消息且该消息为WM_QUIT,返回FALSE。
                      没有消息时,挂起该UI线程,控制权交还给系统。
    PeekMessage 有消息返回TRUE,如果没有消息返回FALSE;不会阻塞。
                       是否从消息队列中删除此消息(PM_REMOVE),由函数参数来指定。

    关于消息的深入了解可查阅以下链接:

    https://blog.csdn.net/shenya1314/article/details/54924685

  • 相关阅读:
    [转]面向接口编程详解(二)——编程实例
    [转]面向接口编程详解(一)——思想基础
    [转] LINQ to SQL快速上手 step by step
    Java备份MySQl数据库,并备份图片数据
    用密码密码拦截
    引用 MySQL集群:主从数据库配置 实现查询负载
    Oracle 对表操作 提示:资源正忙,要求指定nowait
    Jquery一款非好的图片轮换效果
    CodeBlocks集成ObjectiveC开发 Windows下学习ObjectiveC
    查询指定库中所有表
  • 原文地址:https://www.cnblogs.com/ice-arrow/p/13724263.html
Copyright © 2020-2023  润新知