CHAPTER2
追加各种处理
--非矩形窗口
非矩形窗口
windows里提供的改变窗口形状的API:设定指定窗口的窗口区域,使操作系统不显示窗口区域以外的部分。
Win32 API
SetWindowRgn
int SetWindowRgn(
HWND hWnd, // handle to window
HRGN hRgn, // handle to region
BOOL bRedraw // window redraw option
);
MFC
CWnd::SetWindowRgn
int SetWindowRgn(
HRGN hRgn, BOOL bRedraw );
这里的重点是找到这个窗口区域(
HRGN hRgn)。
制作窗口区域(一)
制作区域用的API
API
|
用
途
|
CreateEllipticRgn
|
建立椭圆形的区域
|
CreatePolyPolygonRgn
|
建立复数个多边形构成的区域
|
CreatePolygonRgn
|
建立多边形的区域
|
CreateRectRgn
|
建立矩形的区域
|
CreateRoundRectRgn
|
建立圆角矩形的区域
|
CombineRgn
|
连接两个区域为一个新的区域
|
ExtCreateRegion函数从一个指定的区域或交换数据中创建一个区域。
HRGN ExtCreateRegion(
CONST XFORM *lpXform, // transformation data
DWORD nCount, // size of region data
CONST RGNDATA *lpRgnData // region data buffer
);
这里我没有用书上给的方法,他的方法是基于自己编写的显示图片函数的。
实现方法:
SetWindowRgn(
HRGN hRgn, BOOL bRedraw );函数将一个窗口区域hRgn分配给窗口hWnd,系统只显示该区域标示的地方,区域以外系统不会显示。
程序代码:
1、CMainFrame::RecalcLayout中更改窗口大小,使其与图片大小相同(600x120)。(SetWindowPos与MoveWindow起相同作用)
2、编辑函数SetupRegin,用来获取系统显示的窗口区域。
void CTextView::SetupRegion()
{
CRgn wndRgn,rgnTemp;
COLORREF color;
//将位图选入设备描述表中
HBITMAP hBitmap;
HBITMAP hOldBitmap = NULL;
HDC hdc;
CClientDC dc(this);
hdc = CreateCompatibleDC(dc.m_hDC);
hBitmap = (HBITMAP)LoadImage(AfxGetInstanceHandle(),"TextFrame.BMP",IMAGE_BITMAP,
600,120,LR_CREATEDIBSECTION | LR_LOADFROMFILE);
hOldBitmap = (HBITMAP)SelectObject(hdc,hBitmap);
SelectObject(hdc,hBitmap);
//这个函数要放到OnCreate中,此时窗口应该还没有创建,不能用GetWindowRect
//获得窗口区域(虽然我们也知道窗口是600x120)。但是因为窗口和图片大小一致
//在这里获得图片的宽度和高度数据
DIBSECTION ds;
BITMAPINFOHEADER &bm = ds.dsBmih; //做一个引用,就是别名
GetObject(hBitmap,sizeof(ds),&ds);//将位图信息取出交给ds
int width = bm.biWidth; //得到位图宽度值
int height = bm.biHeight; //得到位图高度值
//创建位图形状的不规则区域
int x , y ;
wndRgn.CreateRectRgn(0,0,width,height);//注意函数的变量是逻辑坐标,所以这样设置
//获取位图每一像素颜色,与指定颜色相同就把它创建成一个矩形区域
//然后从wndRgn抠除
for(x=0;x<=width;x++)
{
for(y=0;y<=height;y++)
{
//将位图中的绿色区域抠掉
color = GetPixel(hdc,x,y);
if(color == RGB(0,255,0))
{
rgnTemp.CreateRectRgn(x,y,x+1,y+1);
wndRgn.CombineRgn(&wndRgn,&rgnTemp,RGN_XOR);//异或操作,抠掉选中矩形
rgnTemp.DeleteObject();
}
}
}
if(hOldBitmap)
{
SelectObject(hdc,hOldBitmap);
}
//将不规则区域分配给窗体,也就是创建不规则窗体
SetWindowRgn((HRGN)wndRgn,TRUE);
DeleteObject(hBitmap);
DeleteObject(hOldBitmap);
DeleteDC(hdc);
}
3、在CTextView::OnCreate中调用SetupRegion。
4、在CTextView::PreCreateWindow中改变窗口样式(window syle)
cs.style = WS_POPUP | WS_VISIBLE;
cs.dwExStyle &= ~WS_EX_CLIENTEDGE;
5、在CTextView::OnPaint中载入背景图片(其实应该写在OnNcPaint或OnEraseBkgnd中)
void CTextView::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
// Do not call CFrameWnd::OnPaint() for painting messages
HBITMAP hBitmap; //声明位图句柄
HDC hdc; //声明设备描述表句柄
hdc = CreateCompatibleDC(dc.m_hDC); //创建兼容DC
//创建位图句柄
hBitmap = (HBITMAP)LoadImage(AfxGetInstanceHandle(),"TextFrame.BMP",IMAGE_BITMAP,
600,120,LR_CREATEDIBSECTION | LR_LOADFROMFILE);
SelectObject(hdc,hBitmap);//将位图句柄选入兼容DC
CRect rect;
GetClientRect(&rect); //获得客户端区域大小
BitBlt(dc.m_hDC, 0,0,
rect.Width(),rect.Height(),
hdc, //兼容DC
0,0,SRCCOPY);
DeleteObject(hBitmap);
DeleteDC(hdc);
dc.SetBkMode(TRANSPARENT);
dc.TextOut(120, 20,"文字区域");
}
6、处理WM_NCHITTEST消息,使当点击窗口任何位置时都能移动窗口。在这里返回HTCAPTION时,windows会认为现在按在标题栏上。
UINT CTextView::OnNcHitTest(CPoint point)
{
// TODO: Add your message handler code here and/or call default
return HTCAPTION;
}