VC++使用CRgn 创建了一个部分透明的不规则窗体,编译并运行本例程序,右上角的小圆圈为透明部分。大致思路是:不显示窗体的某一部分区域,露出窗体下面对应的画面,这样就达到了该部分透明的效果。CRgn可以构造任意形状的一个窗体区域,包括在窗体中间挖一个洞。而SetWindowRgn(HWND hWnd,HRGNhRgn,BOOL bRedraw)函数将一个窗口区域hRgn 分配给窗口hWnd,系统只显示该区域标识的地方,区域以外系统不会显示。为了加强效果,用了两幅位图作辅助。一幅(IDB_BACK)做为窗体背景,另一幅(IDB_MASK)作为窗体形状的模板,在中间挖了一个洞作为透明部分。
程序代码:
(1)通过AppWizard 生成一个基于对话框的应用程序TransparentWindow。
(2) 通过向导增加对话框的WM_SHOWWINDOW消息响应函数OnShowWindow,在其中用MoveWindow
函数调整对话框窗口的大小,使其和位图一样大:
01 | void CTransparentWindowDlg::OnShowWindow( BOOL bShow, UINT nStatus) |
03 | CDialog::OnShowWindow(bShow, nStatus); |
07 | rc.right = rc.left + 320; |
08 | rc.bottom = rc.top + 150; |
(3)在对话框的CPP 文件中加SetupRegion()函数,按模板(IDB_MASK)调整窗体形状,并在OnInitDialog()函数返回之前调用它。
01 | void CTransparentWindowDlg::SetupRegion() |
06 | CBitmap* pOldMemBmp = NULL; |
12 | GetWindowRect(&cRect); |
14 | cBitmap.LoadBitmap(IDB_MASK); |
15 | memDC.CreateCompatibleDC(pDC); |
16 | pOldMemBmp = memDC.SelectObject(&cBitmap); |
18 | wndRgn.CreateRectRgn(0, 0, cRect.Width(), cRect.Height()); |
19 | for (x=0; x<=cRect.Width(); x++) |
21 | for (y=0; y<=cRect.Height(); y++) |
24 | col = memDC.GetPixel(x, y); |
27 | rgnTemp.CreateRectRgn(x, y, x+1, y+1); |
28 | wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_XOR); |
29 | rgnTemp.DeleteObject(); |
33 | if (pOldMemBmp) memDC.SelectObject(pOldMemBmp); |
35 | SetWindowRgn(( HRGN )wndRgn, TRUE); |
38 | BOOL CTransparentWindowDlg::OnInitDialog() |
40 | CDialog::OnInitDialog(); |
(4)通过向导添加对话框的OnEraseBkgnd()函数,在其中添加更换背景的代码,并将缺省代码去掉。
01 | BOOL CTransparentWindowDlg::OnEraseBkgnd(CDC* pDC) |
07 | CBitmap* pOldMemBmp = NULL; |
09 | cBitmap.LoadBitmap(IDB_BACK); |
10 | memDC.CreateCompatibleDC(pDC); |
11 | pOldMemBmp = memDC.SelectObject(&cBitmap); |
13 | pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY); |
14 | if (pOldMemBmp) memDC.SelectObject( pOldMemBmp ); |
(5)处理WM_NCHITTEST 消息,使当击打窗口的任何位置时能移动窗口:
1 | UINT CTransparentWindowDlg::OnNcHitTest(CPoint point) |
3 | UINT nHitTest = CDialog::OnNcHitTest(point); |
4 | return (nHitTest == HTCLIENT)? HTCAPTION:nHitTest; |