在CLinkCtrl上按空格键后调用TrackPopupMenu()会发出警告消息蜂鸣声。为什么?

时间:2018-12-20 03:23:49

标签: c++ visual-studio winapi mfc dialog

与我同在。我必须给你我的设置。

我有一个带有syslink控件的对话窗口(CLinkCtrl):

enter image description here

可以单击以显示上下文菜单。

我现在正在尝试为用户设置一个可访问性选项,以按下空格键或按键盘上的Enter以显示该上下文菜单:

enter image description here

我为此使用了NM_RETURN通知:

LRESULT CTestMfcLinkCtrlDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    // TODO: Add your specialized code here and/or call the base class

    if(message == WM_NOTIFY)
    {
        NMHDR* pNmhdr = (NMHDR*)lParam;
        if(pNmhdr->code == NM_RETURN)
        {
            showMenu();
        }
    }

    return CDialogEx::WindowProc(message, wParam, lParam);
}

菜单本身如下所示:

void CTestMfcLinkCtrlDlg::showMenu()
{
    HMENU hMMenu = LoadMenu(GetModuleHandle(NULL),
        MAKEINTRESOURCE(IDR_MENU1));
    HMENU hMenu = GetSubMenu(hMMenu, 0);

    if(hMenu)
    {
        HWND hParentWnd = this->GetSafeHwnd();

        CWnd* pW = this->GetDlgItem(IDC_SYSLINK1);
        CRect rcW;
        pW->GetWindowRect(&rcW);

        UINT iCmdRes = ::TrackPopupMenu(hMenu, 
            TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON | 
            TPM_VERPOSANIMATION | TPM_HORPOSANIMATION | TPM_RETURNCMD, 
            rcW.left, rcW.bottom, 
            0, hParentWnd, NULL);

        switch(iCmdRes)
        {
            //...
        }

    }

    DestroyMenu(hMMenu);
}

IDR_MENU1来自以下资源:

enter image description here

这是怎么回事:如果system-link控件具有键盘焦点,请按空格键或键盘上的Enter(返回)键。将显示我的上下文菜单,但是与此同时,您会听到一条消息蜂鸣声,与MB_ICONWARNING参数类似。我进行了一些调试,此提示音来自TrackPopupMenu调用。

有人知道为什么要这样做以及如何防止发出警告蜂鸣声吗?

这是我正在对其进行测试的link至VS2017 MFC解决方案。

1 个答案:

答案 0 :(得分:2)

打开弹出菜单以响应WM_CHAR消息。似乎在WM_CHAR完全处理之前打开了菜单。因此,弹出菜单会收到相同的WM_CHAR消息。菜单不知道该键的作用,并发出烦人的哔哔声。

如果在菜单打开时按空格键,则会听到相同的蜂鸣声。

解决方案,请先运行默认功能:

LRESULT CMyDialog::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
    LRESULT lres = CDialogEx::WindowProc(message, wParam, lParam);

    if(message == WM_NOTIFY)
    {
        NMHDR* pNmhdr = (NMHDR*)lParam;
        if(pNmhdr->code == NM_RETURN)
        {
            showMenu();
        }
    }

    return lres;
}

或者,响应ON_NOTIFY来执行此操作,但是请确保使用来从线程中删除消息

PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_REMOVE);

示例:

void CMyDialog::showMenu()
{
    CMenu menu;
    menu.LoadMenu(IDR_MENU1);
    ASSERT(menu.GetSafeHmenu());
    CMenu *popup = menu.GetSubMenu(0);
    ASSERT(popup);

    CRect rc;
    CWnd *syslink = GetDlgItem(IDC_SYSLINK1);
    ASSERT(syslink);
    syslink->GetWindowRect(&rc);

    MSG msg;
    if (::PeekMessage(&msg, NULL, WM_CHAR, WM_CHAR, PM_NOREMOVE))
        AfxGetThread()->PumpMessage();

    UINT iCmdRes = popup->TrackPopupMenu(
            TPM_TOPALIGN | TPM_LEFTALIGN | TPM_LEFTBUTTON |
            TPM_VERPOSANIMATION | TPM_HORPOSANIMATION | TPM_RETURNCMD,
            rc.left, rc.bottom, this);

    switch(iCmdRes)
    {
        //...
    }
}