MFC异形窗口
Windows中所有窗口显示默认为矩形,很多时候我们希望窗口的形状可以随意变化。这个时候我们就需要使用MFC的CRgn类,
每一个窗口都有一个自己的CRgn,定义了当前窗口的显示区域,CRgn就好像是在一张图片上添加了相框,相框的形状就决定了
窗口的显示范围。当然显示区域之外就属于其他窗口。
一,多边形窗口
CRect rc;
GetWindowRect(&rc); //获取窗口矩形(大小)
CPoint ptVertex[4]; //多边形顶点数组,形状为平行四边形
ptVertex[0].x = rc.Width() / 2;;
ptVertex[0].y = 0;
ptVertex[1].x = 0;
ptVertex[1].y = rc.Height()/2;
ptVertex[2].x = rc.Width()/2;
ptVertex[2].y = rc.Height();
ptVertex[3].x = rc.Width();
ptVertex[3].y = rc.Height() / 2;
CRgn m_rgn; //定义窗口显示区域
m_rgn.CreatePolygonRgn(ptVertex, 4, ALTERNATE);//根据顶点数组创建窗口的显示区域
SetWindowRgn(m_rgn, TRUE);//添加到当前窗口
代码直接放在OnInitDialog()方法里。
运行效果如图
这个时候是拖不动窗口的,要添加WM_NCHITTEST消息处理函数
LRESULT CGDI对象Dlg::OnNcHitTest(CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
UINT nHitTest = CDialog::OnNcHitTest(point);
if (nHitTest == HTCLIENT)
nHitTest = HTCAPTION;
return nHitTest;
}
添加完之后点击对话框客户区就可以拖动窗口了。
二,两区域进行连接
CRgn rgn1;
rgn1.CreateRoundRectRgn(0, 0, 300, 200, 15, 15);
CRgn rgn2;
rgn2.CreateRectRgn(133, 83, 168, 118);
rgn1.CombineRgn(&rgn1, &rgn2, RGN_XOR);
SetWindowRgn(rgn1, true);
CombineRgn的第三个参数指定合并两个源区域时要执行的操作。 可以是以下任一值:
- RGN_AND,使用两个区域的重叠区域(交集)。
- RGN_COPY,创建区域 1(由 pRgn1 标识)的副本。
- RGN_DIFF,创建由区域 1(由 pRgn1 标识)中不属于区域 2(由 pRgn2 标识)的区域组成的区域。
- RGN_OR,将两个区域整体合并(联合)。
- RGN_XOR,将两个区域合并,但删除重叠区域。
效果如图:
中间的那块区域被删掉了
还可以再OnPaint()函数里给区域上色
void CGDI对象Dlg::OnPaint()
{
CPaintDC dc(this);
CRgn rgn1;
rgn1.CreateRoundRectRgn(0, 0, 300, 200, 15, 15);
CRgn rgn2;
rgn2.CreateRectRgn(133, 83, 168, 118);
rgn1.CombineRgn(&rgn1, &rgn2, RGN_XOR);
CBrush brush(RGB(0, 200, 200));
dc.SelectObject(&brush);
dc.FillRgn(&rgn1, &brush);
}
三,根据图片定义窗口
将图像显示在对话框上(使对话框和图像一样大)
给CGDI对象Dlg类添加成员变量
CBitmap m_img;
在OnInitDialog()方法里添加如下代码
m_img.LoadBitmap(IDB_BITMAP3);
BITMAP logBitmap;
m_img.GetBitmap(&logBitmap);
MoveWindow(0, 0, logBitmap.bmWidth, logBitmap.bmHeight);
CDC memDc;
memDc.CreateCompatibleDC(NULL);
memDc.SelectObject(&m_img);
在OnPaint()方法里添加如下代码
CPaintDC dc(this);
BITMAP logBitmap;
m_img.GetBitmap(&logBitmap);
CDC memDc;
memDc.CreateCompatibleDC(NULL);
memDc.SelectObject(&m_img);
dc.BitBlt(0, 0, logBitmap.bmWidth, logBitmap.bmHeight, &memDc,
0, 0, SRCCOPY);
我的图片(格式是bmp):
运行程序,就可以把图片加载到对话框上了:
但这只是把图片添加到对话框上,还没有实现不规则窗口,还要在在OnInitDialog()方法里添加如下代码,添加在上一次代码的下面
m_img.LoadBitmap(IDB_BITMAP1);
BITMAP logBitmap;
m_img.GetBitmap(&logBitmap);
MoveWindow(0, 0, logBitmap.bmWidth, logBitmap.bmHeight);
CDC memDc;
memDc.CreateCompatibleDC(NULL);
memDc.SelectObject(&m_img);
CRgn rgn;
rgn.CreateRectRgn(0, 0, logBitmap.bmWidth, logBitmap.bmHeight);
for (int i = 0; i < logBitmap.bmHeight; i++)
{
for (int j = 0; j < logBitmap.bmWidth; j++)
{
CRgn temp;
temp.CreateRectRgn(j, i, j + 1, i + 1);
if (memDc.GetPixel(j, i) == 0xFFFFFF)
{
rgn.CombineRgn(&rgn, &temp, RGN_XOR);
}
}
}
SetWindowRgn(rgn, true);
运行效果
和之前一次运行的效果没什么区别,那是因为图片没选取好。试试下面这张图片
运行效果
窗口现在是这个精灵的形状,图片的白色部分被删除了。
if(memDc.GetPixel(j, i)==0xFFFFFF)
{
rgn.CombineRgn(&rgn,&temp, RGN_XOR);
}
实现这个功能的代码就是这段。通过判断像素块的颜色是不是白色,如果是白色就将这块区域和整个对话框合并(RGN_XOR)就删除了白色的区域。