【问题标题】:PreTranslateMessage method is not getting called inorder to implement Ctrl+A in C++为了在 C++ 中实现 Ctrl+A,未调用 PreTranslateMessage 方法
【发布时间】:2017-11-18 07:54:56
【问题描述】:

我正在尝试在笔记编辑控件中实现 ctrl+A :m_editNoteTypeView",它是类 NoteDialog 中的 cEdit 实例。 我的笔记编辑如下所示。

NoteDialog::initDialog()
{
    m_editNoteTypeView.CreateEx(::GetWindowLong(m_editSubject.m_hWnd, GWL_EXSTYLE), "edit", "", dwStyle | ES_READONLY, CRect(0, 0, 0, 0), this, 0);
    m_editNoteTypeView.SetSel(0,-1,TRUE);
}

NoteDialog 类派生自另一个名为 Sdialog 的类,该类最终派生自 CDialog

我在 SDialog 中定义了PreTranslateMessage(MSG* pMsg),但控制不会转到 PreTranslateMessage,因此当我在笔记编辑上打字时,我无法检查我在键盘上按下的键。

bool Sdialog::PreTranslateMessage(MSG* pMsg)
{
    if (GetFocus() == this) 
    {
        if (pMsg->message == WM_CHAR)
        {
            if ((LOWORD(pMsg->wParam) & VK_CONTROL) == VK_CONTROL)
            {
                //SetSel(0, -1);
            }
        }
    }

    return CDialog::PreTranslateMessage(pMsg);
}

【问题讨论】:

  • 如果编辑控件有焦点,它什么时候不会处理按键?你试过WM_KEYDOWN吗?

标签: visual-c++ mfc ctrl editcontrol


【解决方案1】:

PreTranslateMessagereturn 类型应为BOOL,否则在 MFC 中会出现编译错误。

if (pMsg->message == WM_CHAR)
    if ((LOWORD(pMsg->wParam) & VK_CONTROL) == VK_CONTROL)
        {...}

WM_CHAR 消息在 wParam 中不携带 VK_CONTROL

拦截Ctrl + A

  • 等待WM_KEYDOWN消息
  • 检查 A
  • 检查Ctrl键是否被按下

因此:

BOOL Sdialog::PreTranslateMessage(MSG* pMsg)
{
    static int i = 0;
    CString s;

    if(pMsg->message == WM_KEYDOWN)
    {
        if(GetKeyState(VK_CONTROL) & 0x8000)
        {
            if(pMsg->wParam == 'A')
            {
                ...
            }
        }
    }

    return CDialog::PreTranslateMessage(pMsg);
}

此外,您还可以添加这些辅助宏:

// Handy functions
#define IsCTRLpressed()  ( GetKeyState(VK_CONTROL) & 0x8000 )
#define IsSHIFTpressed()  ( GetKeyState(VK_SHIFT) & 0x8000 )
//15 = sizeof(SHORT) * 8 - 1
//0000 0000 0000 0001 = 1
//1000 0000 0000 0000 = 15 << 1

那么就可以这么简单:

if (IsCTRLpressed() &&
    pMsg->message == WM_KEYDOWN && pMsg->wParam == _TINT(_T('A')))
{
    // Do whatever

    // Eat it.
    bNoDispatch = TRUE;
    bDealtWith = TRUE;
}

请记住,您必须决定是否仍要运行基本实现。如果您实际上自己处理消息并处理它,那么您应该返回TRUE。否则,让基类处理它。

例子:

BOOL Sdialog::PreTranslateMessage(MSG* pMsg)
{
    BOOL    bNoDispatch, bDealtWith;

    bDealtWith = FALSE;

    if (IsCTRLpressed() &&
        pMsg->message == WM_KEYDOWN && pMsg->wParam == _TINT(_T('A')))
    {
        // Deal with it

        // Eat it.
        bNoDispatch = TRUE;
        bDealtWith = TRUE;
    }

    if (!bDealtWith)
        bNoDispatch = CDialogEx::PreTranslateMessage(pMsg);

    return bNoDispatch;
}

【讨论】:

  • @AndrewTruckle 我认为应该是 0x8000 = 15 &lt;&lt; 1,而不是 0x1E = 1 &lt;&lt; 15
  • 代码取自 Chris Maunder 的 CodeProject CGridCtrl 类数据文件。
  • @AndrewTruckle 我在编辑时又写错了。我的意思是写(GetKeyState(VK_CONTROL) &amp; (15 &lt;&lt; 1)),但这仍然是不必要的混乱,只需使用GetKeyState(VK_CONTROL) &amp; 0x8000GetKeyState(VK_CONTROL) &lt; 0 这将检查高位,如文档中所述。 1 &lt;&lt; (sizeof(SHORT)*8 - 1) 错了。
  • 在您的第一个代码示例中,您使用的是GetAsyncKeyState(),但后来您切换到GetKeyState()。后者是您想要使用的正确keys state at the time the input message was send, instead of the keystate at this very instant
  • @BijayKumar 通过在头文件中的函数声明中添加override specifier,可以在编译时轻松检测到此类错误。如果您的函数与您要覆盖的基类的函数之间存在签名不匹配,编译器会报错。应该始终使用的 C++11 的最佳补充之一。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-11
  • 1970-01-01
  • 2020-08-18
  • 2012-08-11
  • 1970-01-01
  • 2011-06-04
相关资源
最近更新 更多