Rendering menu glyphs is slightly trickier - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20050802-13/?p=34743
Raymond Chen 2005年08月02日
上次,我们看到了如何绘制有主题和无主题的单选按钮,我提到菜单位图更加棘手。它们之所以棘手,是因为它们是以原始单色位图提供的,而不是完全形成的颜色协调位图。
首先,我们做个错误的示范看看会得到什么。然后将尝试修复它。
从一个干净的新初始程序开始。
class RootWindow : public Window
{…
protected:void PaintContent(PAINTSTRUCT *pps);BOOL WinRegisterClass(WNDCLASS *pwc){pwc->hbrBackground = (HBRUSH)(COLOR_MENU + 1);return __super::WinRegisterClass(pwc);}…
};void RootWindow::PaintContent(PAINTSTRUCT *pps)
{int cxCheck = GetSystemMetrics(SM_CXMENUCHECK);int cyCheck = GetSystemMetrics(SM_CYMENUCHECK);RECT rc = { 0, 0, cxCheck, cyCheck };DrawFrameControl(pps->hdc, &rc, DFC_MENU, DFCS_MENUCHECK);
}
这段代码天真地使用 DrawFrameControl
函数直接在绘制 DC 中绘制菜单勾选标记。如果你使用默认的 Windows XP 主题,你可能不会注意到任何问题,但切换到 Windows 经典主题,你将看到勾选标记是以黑白方式绘制的,即使经典菜单背景颜色是灰色。
原因在于 DrawFrameControl
的文档中指出:
如果 uType 是 DFC_MENU 或 DFC_BUTTON 并且 uState 不是 DFCS_BUTTONPUSH,框架控件是黑白掩码(即,在白色背景上的黑色框架控件)。
我们从 DrawFrameControl
得到的所有东西就是一个单色掩码。将其着色是我们要作的工作。
为此,我们将掩码绘制到单色位图中,然后使用 BitBlt
函数对其进行着色。
回想一下,当从单色位图复制到彩色位图时,源位图中的黑色变成目标 DC 的文本颜色,源位图中的白色变成目标 DC 的背景颜色。
void RootWindow::PaintContent(PAINTSTRUCT *pps)
{HDC hdcMem = CreateCompatibleDC(pps->hdc);if (hdcMem) {int cxCheck = GetSystemMetrics(SM_CXMENUCHECK);int cyCheck = GetSystemMetrics(SM_CYMENUCHECK);HBITMAP hbmMono = CreateBitmap(cxCheck, cyCheck, 1, 1, NULL);if (hbmMono) {HBITMAP hbmPrev = SelectBitmap(hdcMem, hbmMono);if (hbmPrev) {RECT rc = { 0, 0, cxCheck, cyCheck };DrawFrameControl(hdcMem, &rc, DFC_MENU, DFCS_MENUCHECK);COLORREF clrTextPrev = SetTextColor(pps->hdc,GetSysColor(COLOR_MENUTEXT));COLORREF clrBkPrev = SetBkColor(pps->hdc,GetSysColor(COLOR_MENU));BitBlt(pps->hdc, 0, 0, cxCheck, cyCheck,hdcMem, 0, 0, SRCCOPY);SetBkColor(pps->hdc, clrBkPrev);SetTextColor(pps->hdc, clrTextPrev);SelectBitmap(hdcMem, hbmPrev);}DeleteObject(hbmMono);}DeleteDC(hdcMem);}
}
这里的关键是:
- 在临时单色位图中绘制以生成掩码,
- 设置目标 DC 的文本和背景颜色,
- 使用
BitBlt
进行颜色映射。
函数的其余部分只是无聊的流水账。
观察到勾选标记的颜色现在与系统菜单颜色相匹配,因为我们将它们设置为单色到彩色复制的文本和背景颜色。
掌握了这些知识,你或许就能帮助那位尝试透明绘制菜单勾选标记的人。我立刻便能想到两种不同的解决方案。