首页 > 代码库 > 实现控件的透明背景

实现控件的透明背景

很多情况下,我们需要控件的背景是透明的,就是要求直接看到控件父窗口的背景颜色、背景位图,比如标签控件、单选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);还原画布的刷子偏移