实现控件的透明背景
很多情况下,我们需要控件的背景是透明的,就是要求直接看到控件父窗口的背景颜色、背景位图,比如标签控件、单选Radio控件、复选Check控件,通常都要求在父窗口的背景上进行绘制。然而要求控件的画布透明,这个技术在GDI的文档中没有看到Microsoft作任何说明,当然还是有别的办法。
其一:如果程序支持桌面主题服务的话,则可调用主题服务的API来实现背景。我们先看看这个API:
HRESULT DrawThemeParentBackground(HWND hwnd, HDC hdc, RECT *prc);
这个函数就是专门用来绘制父窗口的背景的,其中的hwnd参数是子窗口的句柄,hdc也时子窗口的画布句柄,prc是子窗口需绘制的区域,这个函数实际是把父窗口的背景拷贝到子窗口上来,以这种方法达到透明。
其二:如果程序不支持桌面主题服务,则不能使用上面的方法,比如程序运行在Windows 2000上。这时我们可以向父窗口发送WM_PAINT消息,不过此消息所附带的wParam参数是一个画布句柄:
HDC dc = GetDC(NULL);
HWND cWnd = ...;//子窗口句柄
HWND pWnd = ...;//父窗口句柄
RECT cRect;
GetClientRect(cWnd, &cRect);
HBITMAP bitmap = CreateCompatibleBitmap(dc, cRect.right, cRect.bottom);
ReleaseDC(dc);
HDC memDC = CreateCompatibleDC(NULL);
HGDIOBJ oldBitmap = SelectObject(memDC, bitmap);
//此处可以调用SetClipRect()等函数来限制绘制范围
SendMessage(pWnd, WM_ERASEBKGND, (WPARAM)memDC, 0);
SendMessage(pWnd, WM_PAINT, (WPARAM)memDC, 0);
//至此memDC上已经保存了父窗口的背景内容
//用户可以调用BitBlt(...)等函数拷贝memDC的内容到子窗口的某个区域,这样就达到了透明效果;
SelectObject(memDC, oldBitmap);
DeleteDC(memDC);
DeleteObject(bitmap);
上面的办法当然有限制,因为不是所有的父窗口都可以接受这种特殊的WM_PAINT消息功能,不过MSDN中提到大多数控件都有这个功能,大家要注意读它的文档内容。
其三:如果上面的办法都不行的话,就剩下最笨的办法了,用GDI函数涂刷子窗口的背景,但你事先就要知道父窗口的背景颜色、背景位图等信息。比如拿父窗口的颜色来填充子窗口的背景,可以调用FillRect()等:
//-------------------父窗口的背景是颜色的情况
COLORREF pColor = ...;//父窗口的颜色
HDC cDC = ...;//子窗口的画布句柄
RECT cRect = ...;//子窗口需刷新的区域
HBRUSH brush = CreateSolidBrush(pColor);
FillRect(cDC, &cRect, brush);
DeleteObject(brush);
//-------------------父窗口的背景是位图的情况
HBITMAP pBitmap = ...;父窗口的背景位图
HDC cDC = ...;//子窗口的画布句柄
RECT cRect = ...;//子窗口需刷新的区域
POINT rp;
SetBurshOrgEx(cDC, x, y, &rp);如果是位图刷子,则还需要调整画布的刷子原点偏移确保无缝
HBRUSH brush = CreatePatternBrush(pBitmap);
FillRect(cDC, &cRect, brush);
DeleteObject(brush);
SetBurshOrgEx(cDC, rp.x, rp.y, NULL);还原画布的刷子偏移