VS中不规则窗体的创建
1、基本思路
逐个扫描图片的每个像素,如这个像素不属于定义的透明色,则在相应位置创建一个只含一个像素的region,然后将这些小region合并起来组成一个任意形状的region。
2、图片资源处理
将背景图片中不需要显示的部分涂上一种单一的颜色,此颜色不要与需要显示的部分有相同色。本例中将不需要显示的部分涂为白色。将图片资源加入到工程中,并设置其ID。本例中设为IDB_BACKGROUND。
3、主实现程序(来源于网络)
主实现程序如下:
//CDC *pDC, //窗体的DC指针
//CBitmap &cBitmap, //含有窗体形状的位图对象
//COLORREF TransColor //透明色
void SetupRegionCDC(CDC * pDC, CBitmap & cBitmap, COLORREF TransColor)
{
//本函数只调用一次即可
static int nExit=1;
if (nExit>1)
{
return;
}
nExit++;
CDC memDC;//创建与传入DC兼容的临时DC
memDC.CreateCompatibleDC(pDC);
CBitmap *pOldMemBmp = NULL;//将位图选入临时DC
pOldMemBmp = memDC.SelectObject(&cBitmap);
static CRgn wndRgn;//创建总的窗体区域,初始region为0
wndRgn.CreateRectRgn(0, 0, 0, 0);
BITMAP bit;
cBitmap.GetBitmap (&bit);//取得位图参数,这里要用到位图的长和宽
//逐个扫描图片的每个像素,如这个像素不属于透明色,
//则在相应位置创建一个只含一个像素的region,然后将这些小region
//合并起来组成一个任意形状的region
int y;
CRgn rgnTemp; //保存临时region
for(y = 0; y <= bit.bmHeight ; y++)
{
int iX = 0;
do
{
//在图片的第y行寻找第一个非透明色的点
while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) == TransColor)
iX++;
int iLeftX = iX;//记住这个起始点
//在图片的第y行寻找第一个透明色的点
while (iX <= bit.bmWidth && memDC.GetPixel(iX, y) != TransColor)
++iX;
//创建一个包含起点与终点间高为1像素的临时“region”
rgnTemp.CreateRectRgn(iLeftX, y, iX, y + 1);
//合并到主"region".
wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR);
//删除临时"region",否则下次创建时会出错
rgnTemp.DeleteObject();
}
while(iX<= bit.bmWidth);
}
this->SetWindowRgn(wndRgn, TRUE);
memDC.DeleteDC();
}
4、处理WM_ERASEBKGND消息
添加WM_ERASEBKGND消息,并在消息中做如下处理:
(1)去除标题和边框
SetWindowLong(m_hWnd, GWL_STYLE,GetWindowLong(m_hWnd, GWL_STYLE) & (~(WS_CAPTION | WS_BORDER)));
(2)窗口贴图
CDC memDC;
memDC.CreateCompatibleDC(pDC);
BITMAP bmp;
CBitmap bkImg;
bkImg.LoadBitmap(IDB_BACKGROUND);
bkImg.GetBitmap(&bmp);
memDC.SelectObject(&bkImg);
(3)设置窗口大小
SetWindowPos(NULL, 0, 0, bmp.bmWidth, bmp.bmHeight, SWP_NOMOVE|SWP_NOZORDER);
CRect rect;
GetClientRect(&rect);
pDC->StretchBlt(0, 0,bmp.bmWidth, bmp.bmHeight, &memDC, 0, 0, bmp.bmWidth, bmp.bmHeight,SRCCOPY);
memDC.DeleteDC();
(4)设置窗口透明
SetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE,
GetWindowLong(AfxGetMainWnd()->m_hWnd,GWL_EXSTYLE) | 0x80000);
HINSTANCE hInst=LoadLibrary(_T("User32.DLL"));
if(hInst)
{
typedef BOOL (WINAPI * MYFUNC)(HWND,COLORREF,BYTE,DWORD);
MYFUNC fun=NULL;
//取得SetLayeredWindowAttributes函数指针
fun=(MYFUNC)GetProcAddress(hInst,"SetLayeredWindowAttributes");
if(fun)
fun(AfxGetMainWnd()->m_hWnd,RGB(0,0,0),0,1);
FreeLibrary(hInst);
}
(5)调用主程序,实现不规则窗体
static CBitmap m_Bmp;
m_Bmp.LoadBitmap(IDB_BACKGROUND);
static COLORREF cr;
cr=RGB(0,0,0);
SetupRegionCDC(pDC,m_Bmp,cr);
return TRUE;
5、移动窗口时不出现边框
若要移动窗口时不出现边框,需处理WM_NCHITTEST消息。在此消息中做如下处理:
//禁止显示移动矩形窗体框
::SystemParametersInfo(SPI_SETDRAGFULLWINDOWS,TRUE,NULL,0);
CRect rect;
GetClientRect(&rect);
ClientToScreen(&rect);
return rect.PtInRect(point) ? HTCAPTION : CDialog::OnNcHitTest(point);
6、不规则窗口效果