Once and for all: how do I get a fully transparent checkbox, button, radio button, etc. in Windows API, and not with a black background?

核能气质少年 提交于 2019-11-27 04:56:03

问题


First, sorry if I sound arrogant/rude here.

All right, so everyone has run into this by now (I hope); I just haven't found any adequate answer anywhere. We start with a Common Controls 6 manifest and

case WM_CTLCOLORSTATIC:
    if (/* window has WS_EX_TRANSPARENT */) {
        SetBkMode((HDC) wParam, TRANSPARENT);
        return (LRESULT) GetStockObject(HOLLOW_BRUSH);
    }

and give our labels WS_EX_TRANSPARENT. They become transparent; so far so good. Now we have to add that style to our checkboxes (because checkboxes respond to that and not to WM_CTLCOLORBTN for some reason). And... the checkboxes become black!

Is there any way to make them fully transparent without resorting to owner draw? I'd rather not draw the checkboxes myself; I'd rather not have to guess whether it looks right or what the sizes are should the theming API fail on me (and I'm going to have to draw check boxes by themselves in the future when I add custom checkboxes to my list views and I'm already not happy with the amount of guessing involved).

These checkboxes are being drawn over a themed tab control. So far, I've found five dialogs in Windows XP with transparent checkboxes on themed tabs: General tab of Shortcut Properties, Taskbar tab of Taskbar and Start Menu Properties, System Restore tab of System Properties, General tab of Folder Options (radio buttons), and Keyboard tab of Accessibility Options. So this certainly must be possible! I'm sure the Windows UI authors didn't have to use custom draw throughout the OS... What are we all missing?

If I need to subclass that's fine (I already have a subclass anyway for event handling purposes), but I still would rather not have to draw myself.

As a bonus, what about push buttons? Overriding WM_CTLCOLORBTN gives buttons a black border, but I do notice that none of the standard dialogs mentioned above bother to make the corners of buttons transparent, so eh :/

Thanks!


回答1:


Mostly nailed this:

void paintControlBackground(HWND hwnd, HDC dc)
{
    HWND parent;
    RECT r;
    POINT p;
    int saved;

    parent = GetParent(hwnd);
    if (parent == NULL)
        xpanic("error getting parent container of control in paintControlBackground()", GetLastError());
    if (GetWindowRect(hwnd, &r) == 0)
        xpanic("error getting control's window rect in paintControlBackground()", GetLastError());
    // the above is a window rect; convert to client rect
    p.x = r.left;
    p.y = r.top;
    if (ScreenToClient(parent, &p) == 0)
        xpanic("error getting client origin of control in paintControlBackground()", GetLastError());
    saved = SaveDC(dc);
    if (saved == 0)
        xpanic("error saving DC info in paintControlBackground()", GetLastError());
    if (SetWindowOrgEx(dc, p.x, p.y, NULL) == 0)
        xpanic("error moving window origin in paintControlBackground()", GetLastError());
    SendMessageW(parent, WM_PRINTCLIENT, (WPARAM) dc, PRF_CLIENT);
    if (RestoreDC(dc, saved) == 0)
        xpanic("error restoring DC info in paintControlBackground()", GetLastError());
}

    case WM_CTLCOLORSTATIC:
    case WM_CTLCOLORBTN:
        if (SetBkMode((HDC) wParam, TRANSPARENT) == 0)
            xpanic("error setting transparent background mode to Labels", GetLastError());
        paintControlBackground((HWND) lParam, (HDC) wParam);
        *lResult = (LRESULT) hollowBrush;
        return TRUE;

There are a few loose ends:

This won't work if the immediate parent of the given control is a groupbox; in that case, you'll need to inspect the class name and walk up the parent chain.

You also need to implement WM_PRINTCLIENT on any custom containers AND in the window class.

This doesn't yet work for groupbox labels; you'll see the texture drawn properly, but the groupbox line will be drawn on top of it. I'll mark this as solved when I figure that out and update this post with that info.

(The flicker I was seeing seems to be caused by a stop-the-world garbage collector used by another part of the program, and is thus out of my control for the time being. This will change soon, hopefully.)

Thanks in the meantime!




回答2:


You have to return the hbrBackground element of registered class of window as follow:

case WM_CTLCOLORBTN:
case WM_CTLCOLORSTATIC: {
    wchar_t  class_Name[100];
    GetClassName(hWnd, class_Name, 100);
    WNDCLASS lpcls{};
    GetClassInfo(g_hInstance, class_Name, &lpcls);

    return  (LRESULT)lpcls.hbrBackground;
}


来源:https://stackoverflow.com/questions/25319918/once-and-for-all-how-do-i-get-a-fully-transparent-checkbox-button-radio-butto

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!