自定义按钮时出现奇怪的行为

时间:2017-03-04 22:30:50

标签: c++ winapi

我使用winapi在对话框上创建了按钮控件,我处理WM_NOTIFY - > NM_CUSTOMDRAW。 该对话框由菜单命令创建。奇怪的行为是:如果我通过键盘触发菜单命令(按菜单项上的Enter键),每件事都可以。如果我鼠标单击菜单项以打开对话框,按Alt键将删除按钮上的文本,直到我单击或移动按钮上的鼠标。在每个对话的生命周期中都会发生一次。我该如何防止这种行为?我绘制按钮的背景,让窗口在上面绘制文本和位图。我的代码有什么问题?这是我的代码的一部分:

/*---------------------------------------------------------*/
static int uOnPrePaint(HWND hDlg, LPARAM lParam)
{
    LPNMCUSTOMDRAW lpnmCD = (LPNMCUSTOMDRAW)lParam;
    COLORREF crPen = GetDCPenColor(lpnmCD->hdc);
    bool bHot = (lpnmCD->uItemState & CDIS_HOT) != 0;
    COLORREF crBack = RGB(200, 200, 200);
    COLORREF crHot = RGB(200, 200, 0);
    SetDCBrushColor(lpnmCD->hdc, bHot ? crHot : crBack);
    SetDCPenColor(lpnmCD->hdc, bHot ? crHot : crBack);
    SelectObject(lpnmCD->hdc, GetStockObject(DC_BRUSH));
    SelectObject(lpnmCD->hdc, GetStockObject(DC_PEN));
    int iThickness = 3;
    RoundRect(lpnmCD->hdc,
        lpnmCD->rc.left + iThickness,
        lpnmCD->rc.top + iThickness,
        lpnmCD->rc.right - iThickness,
        lpnmCD->rc.bottom - iThickness,
        5,
        5
    );
    SetDCPenColor(lpnmCD->hdc, crPen);
    SetWindowLongPtrW(hDlg, DWL_MSGRESULT, CDRF_DOERASE);
    return TRUE;
}

/*---------------------------------------------------------*/
static int uCustomDraw(HWND hwndDlg, LPARAM lParam)
{
    LPNMCUSTOMDRAW lpnmCD = (LPNMCUSTOMDRAW)lParam;
    switch (lpnmCD->dwDrawStage)
    {
    case CDDS_PREPAINT: return uOnPrePaint(hwndDlg, lParam);
    default: return (INT_PTR)0;
    }
}

/*---------------------------------------------------------*/
static int uOnNotify(HWND hwndDlg, WPARAM wParam, LPARAM lParam)
{
    LPNMHDR lpnmHeader = (LPNMHDR)lParam;
    switch (lpnmHeader->code)
    {
    case NM_CUSTOMDRAW: return uCustomDraw(hwndDlg, lParam);
    default: return (INT_PTR)0;
    }
}

/*---------------------------------------------------------*/
static HWND uCreateButton(HWND hWnd, int cpx, int cpy, int cpWidth, int cpHeight, const wchar_t * wszText, int iIdControl)
{
    int style = BS_TEXT | BS_NOTIFY | BS_VCENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_GROUP;
    int styleEx = WS_EX_RTLREADING | WS_EX_RIGHT;
    HWND hwndControl = CreateWindowExW(
        styleEx, L"BUTTON", wszText, style,
        cpx, cpy, cpWidth, cpHeight,
        hWnd, nullptr, g_hInstance, nullptr
    );
    //ShowWindow(hwndControl, SW_SHOW);
    SetWindowLongPtrW(hwndControl, GWLP_ID, iIdControl);
    unsigned cpImageWidth = 16;
    HICON hIcon1 = (HICON)LoadImageW(g_hInstance, 
        MAKEINTRESOURCEW(IDI_SMALL), IMAGE_ICON, cpImageWidth, cpImageWidth, LR_SHARED);
    if (hIcon1)
    SendMessageW(hwndControl, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hIcon1);
    return hwndControl;
}

提前致谢 mr.abzadeh 编辑1:重写问题以更好地描述问题并使其可供其他人使用。 EDIT2:我注意到这种行为与Windows中实现的键盘易用性完全相关。我打开控制面板/轻松访问中心/使键盘更容易使用 - >选中"下划线键盘快捷键和访问键"复选框,问题解决了。但我想在不修改控制面板设置的情况下解决问题。 编辑3:另一方面,我捕获WM_KEYDOWN控件事件并向对话框发布自定义消息,需要重新绘制对话框上的所有按钮 当第一次按下ALT键时,这解决了我的问题。但我保持问题的开放性,看看是否有更好的方法。

1 个答案:

答案 0 :(得分:0)

回复CDDS_PREPAINT的绘画可能存在问题,因为您要求窗口在某些情况下使用CDRF_DOERASE绘制背景。

尝试在CDRF_DOERASE中返回CDDS_PREPAINT并在稍后阶段进行实际绘制,可能在CDDS_POSTERASE