MFC实现不规则形状窗口(CF登陆窗口)

1,目标

实现形状不规则的窗口,例如CF登陆窗口。

MFC实现不规则形状窗口(CF登陆窗口)_第1张图片

可以看到,窗口不是死板的矩形,而是带突出带凹陷的不规则形状。(PS:谢霆锋代言CF,还真是霸气测漏啊……)

2,原理

查询CWnd接口,有一个叫SetWindowRgn的方法,可以设置窗口显示的区域。
函数原型 int SetWindowRgn(HRGN hRgn,BOOL bRedraw);
hRgn代表一个区域,这个HRGN结构有一些生成的方法,其中有通过矩形、多边形、椭圆来创建一个HRGN,更奇妙的是可以2个HRGN相加或相减生成一个新的HRGN。所以需要求出不透明区域的HRGN,思路是用Photoshop制作一张与背景图同样大小的双色图片,其中不透明区域设为一种颜色(如白色),透明区域设为黑色,通过遍历像素将白色区域的HRGN全部加和,后得到显示的区域。(或者求出黑色区域,用总区域减掉它)


3,实现

①得到CF登陆界面的截图,如上图。(为了在PS中选中方便,这里最好把桌面背景换成单色)
②用PS将多余部分改成黑色,注意:代码中是以像素RGB值做判断的,这里一定要和代码中做筛选的RGB值相对应,我在PS中用的(0,0,0)的纯黑色。反选,将显示部分改成其他颜色(由于本示例代码是求出黑色部分做减法,所以要显示的部分只要不是黑色就行)如图:其余部分我改成了绿色。MFC实现不规则形状窗口(CF登陆窗口)_第2张图片
③新建MFC对话框程序,清空对话框上的控件,把对话框的属性中的边框设为无(有标题栏和边框的话,图片显示位置会不对)。导入登陆界面截图和双色图,ID分别设为IDB_BITMAP_CF,IDB_BITMAP_AREA。注意两张图大小一样(应该直接用前一张图制作双色图)。
④给dlg类添加成员函数SetRegion,实现如下:
[cpp]  view plain copy
  1. void CFDlg::SetRegion(CDC* pDC, UINT BackBitmapID, COLORREF TransColor)  
  2. {  
  3.     CDC dcMem;  
  4.     if(!dcMem.CreateCompatibleDC(pDC))  
  5.     {  
  6.         MessageBox(_T("创建兼容DC失败!"));  
  7.     }  
  8.   
  9.     CBitmap bitmap;  
  10.     if(!bitmap.LoadBitmap(BackBitmapID))  
  11.     {  
  12.         MessageBox(_T("加载位图失败!"));  
  13.     }  
  14.   
  15.     if(!dcMem.SelectObject(&bitmap))  
  16.     {  
  17.         MessageBox(_T("选进设备描述表失败!"));  
  18.     }  
  19.   
  20.     BITMAP bitmapinfo;  
  21.     bitmap.GetBitmap(&bitmapinfo);  
  22.     //把窗口设为图片的大小,去掉这个的话,那么程序分割会不正确  
  23.     MoveWindow(0,0,bitmapinfo.bmWidth,bitmapinfo.bmHeight,true);   
  24.     //整体区域  
  25.     CRgn rgn;  
  26.     CRgn tmpRgn;  
  27.     rgn.CreateRectRgn(0,0,bitmapinfo.bmWidth,bitmapinfo.bmHeight);  
  28.     //从整体区域中剔除所有黑色像素区域  
  29.     for(int i=0;i<bitmapinfo.bmWidth;i++)  
  30.     {  
  31.         for(int j=0;j<bitmapinfo.bmHeight;j++)  
  32.         {  
  33.             COLORREF cl=dcMem.GetPixel(i,j);  
  34.             if(cl== TransColor)  
  35.             {  
  36.                 tmpRgn.CreateRectRgn(i,j,i+1,j+1);  
  37.                 rgn.CombineRgn(&rgn,&tmpRgn,RGN_XOR);  
  38.                 tmpRgn.DeleteObject();  
  39.             }  
  40.         }  
  41.     }  
  42.     //设置窗口显示区域  
  43.     SetWindowRgn(rgn,true);  
  44. }  

⑤在dlg类OnInitDialog方法中调用SetRegion.
[cpp]  view plain copy
  1. BOOL CFDlg::OnInitDialog()  
  2. {  
  3.     CDialog::OnInitDialog();  
  4.   
  5.     SetIcon(m_hIcon, TRUE);         // Set big icon  
  6.     SetIcon(m_hIcon, FALSE);        // Set small icon  
  7.   
  8.     //根据双色图片设置窗口形状(非黑色区域有效)  
  9.     SetRegion(GetDC(),IDB_BITMAP_AREA,RGB(0,0,0));  
  10.   
  11.     //居中  
  12.     CenterWindow();  
  13.   
  14.     //播放背景音乐  
  15.     sndPlaySound(TEXT("cf_bgm.wav"),SND_ASYNC);  
  16.   
  17.     return TRUE;  // return TRUE  unless you set the focus to a control  
  18. }  
其中CenterWindow让窗口居中显示,同时用sndPlaySound函数播放了CF的背景音乐cf_bgm.wav,这是从游戏安装文件夹中找的。我转换过格式并重命名了。要使用这个音乐API,得加入如下lib:
[cpp]  view plain copy
  1. #include "mmsystem.h"  
  2. #pragma comment(lib,"winmm.lib")  
⑥现在窗口形状达到要求了,但是还没有背景图,在OnPaint中else分支中修改为如下,要去掉CDialog::OnPaint();
[cpp]  view plain copy
  1. void CFDlg::OnPaint()  
  2. {  
  3.     if (IsIconic())  
  4.     {  
  5.         CPaintDC dc(this); // device context for painting  
  6.   
  7.         SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);  
  8.   
  9.         // Center icon in client rectangle  
  10.         int cxIcon = GetSystemMetrics(SM_CXICON);  
  11.         int cyIcon = GetSystemMetrics(SM_CYICON);  
  12.         CRect rect;  
  13.         GetClientRect(&rect);  
  14.         int x = (rect.Width() - cxIcon + 1) / 2;  
  15.         int y = (rect.Height() - cyIcon + 1) / 2;  
  16.   
  17.         // Draw the icon  
  18.         dc.DrawIcon(x, y, m_hIcon);  
  19.     }  
  20.     else  
  21.     {  
  22.         CPaintDC  dc(this);     
  23.         CRect  rect;     
  24.         GetWindowRect(&rect);     
  25.         CDC  dcMem;     
  26.         dcMem.CreateCompatibleDC(&dc);     
  27.         CBitmap  bmpBackground;     
  28.         bmpBackground.LoadBitmap(IDB_BITMAP_CF);  //背景图  
  29.         BITMAP  bitmap;     
  30.         bmpBackground.GetBitmap(&bitmap);     
  31.         CBitmap  *pbmpOld=dcMem.SelectObject(&bmpBackground);   
  32.         dc.StretchBlt(0,0,rect.Width(),rect.Height(),&dcMem,0,0,bitmap.bmWidth,bitmap.bmHeight,SRCCOPY);  
  33.     }  
  34. }  

这是绘制我们那张背景图,其中边缘外的部分由于窗口大小关系被截掉,所以看不到了。

4,效果


边缘有点毛边,这个得靠PS处理的仔细程度了,我只是用魔棒工具简单的选择了下范围。


5,源码

附本文VC6+vs2008 MFC工程源码下载:

http://yun.baidu.com/s/1xODo1

你可能感兴趣的:(MFC实现不规则形状窗口(CF登陆窗口))