定制按钮时的奇怪行为

Strange behaviour when customdrawing a button

本文关键字:按钮      更新时间:2023-10-16

我已经在对话框上使用winapi创建了按钮控件,并且我处理wm_notify-> nm_customdraw。对话框由菜单命令创建。奇怪的行为是这样的:如果我触发键盘菜单命令(按菜单项,请按Enter键),则每件事都可以。如果鼠标鼠标单击菜单项以打开对话框,请按Alt键删除按钮上的文本,直到我单击或在按钮上移动鼠标为止。在每次对话的生命中,一次都发生一次。如何防止这种行为?我绘制按钮的背景,让Windows绘制文本和位图。我的代码有什么问题?这是我的代码的一部分:

/*---------------------------------------------------------*/
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;
}

预先感谢阿布扎德先生EDIT1:重写问题以更好地描述问题并使其其他人可用。EDIT2:我注意到此行为与Windows中实现的键盘完全相关。我打开了控制面板/宽松中心/使键盘更易于使用 ->检查"下划线键盘快捷键和访问密钥"复选框,并且解决了问题。但是我想在不修改控制面板设置的情况下解决问题。EDIT3:另一种方式,我捕获了控件的WM_KEYDOWN事件,并发布了一个自定义消息到对话框,需要重新粉刷对话框上的所有按钮当第一次按下alt键时,这解决了我的问题。但是我将问题开放,看看是否有更好的方法。

响应CDDS_PREPAINT的绘画可能是有问题的,因为您要求Windows在某些情况下使用CDRF_DOERASE绘制背景。

尝试仅在CDDS_PREPAINT中返回CDRF_DOERASE,然后在以后的阶段进行实际图纸,也许在CDDS_POSTERASE中。