您的位置:首页 > 其它

VC不规则窗口实现—位图区域裁剪

2015-11-03 19:14 447 查看
既然默认创建的窗口是矩形区域,只要把不想显示的区域透明化,剩下的不就是不规则窗口了吗?!接下来所谓的窗口透明化,我们直接使用CRgn类来实现创建、裁剪和合并区域的功能,然后再使用SetWindowRgn函数来进行整个窗体的区域绘制。

不规则窗口,顾名思义,就是窗口的形状不是长方形、正方形或者圆形,而是一些不规则的图形。例如我们常常看到的一些可设置皮肤的窗口,机器人形状,五角星图形窗口一样等等。那应该如何实现呢?窗口贴图?

OK,就算我们采用窗口贴图的方式,默认的窗口创建还是只会显示规规矩矩的矩形对话框,无法实现该效果。可世上无难事,聪明的人总会能找到方法。根据网上提供的方法,在贴图的基础上,我们采用创建、裁剪和合并区域的方法来进行不规则窗口的创建。

在这里,我们要实现下图为例来讲解一下实现方法。



解题思路:

既然默认创建的窗口是矩形区域,只要把不想显示的区域透明化,剩下的不就是不规则窗口了吗?!接下来所谓的窗口透明化,我们直接使用CRgn类来实现创建、裁剪和合并区域的功能,然后再使用SetWindowRgn函数来进行整个窗体的区域绘制。

SetWindowRgn 函数是设置了一个窗口的区域。只有被包含在这个区域内的地方才会被重绘,而不包含在区域内的其他区域系统将不会显示。

于是要求设计MM给我把要去掉的位图区域加上纯红颜色,如下图所示:



1.把位图中不想显示的区域用另外的颜色填充,上图使用了红色RGB(255,0,0);

2.加载位图到对话框中,然后创建一个初始为0的区域;

3.以一个像素点为单位,从位图的最左边(0,0)位置开始扫描,然后到右下角(width,height)结束;

4.如果遇到是一个纯红色像素的,跳过,继续扫描;如果下一个遇到不是纯红色像素,则记录该点X1坐标,然后继续扫描;直到遇到纯红色像素,此时记录下该点X2坐标,用CreateRectRgn创建一个像素高的(x1,y,x2,y+1)区域,然后用CombineRgn与原先按要求创建好的区域进行合并,如此类推;

5.最后使用SetWindowRgn函数设置最终的窗体区域,成功。

ps:因为用PS填充的时候,红色和白色相交的地方会出现颜色渐变的情况,注意此时应该一个点一个点地用纯红色填充(RGB(255,0,0))同时程序中的颜色取值应使用范围值。

代码:

void CIrregularWindowDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
CDC picDC,memDC;
CBitmap *pOldBmp;
BITMAP bm;

CRgn wndRgn;
CRgn rgnTemp; //保存临时region

int iX=0, iLeftX=0;

CRect rcClient, rtWindow;
CFont *pOldFont;

GetClientRect(rcClient);

picDC.CreateCompatibleDC (&dc);
pOldBmp = picDC.SelectObject (&m_bitmap);

//没加载图片成功,退出
if (pOldBmp==NULL)
{
OnCancel();
}

m_bitmap.GetBitmap(&bm);

//创建总的窗体区域,初始region为0
wndRgn.CreateRectRgn(0,0,0,0);

for(int y=0; y<=bm.bmHeight; y++)
{
iX = 0;
do
{
//跳过透明色找到下一个非透明色的点.
while (iX <= bm.bmWidth  && (picDC.GetPixel(iX, y) >= m_TargetStartColor && picDC.GetPixel(iX, y) <= m_TargetEndColor))
iX++;

//记住这个起始点
iLeftX = iX;

//寻找下个透明色的点
while (iX <= bm.bmWidth  && (picDC.GetPixel(iX, y) < m_TargetStartColor || picDC.GetPixel(iX, y) > m_TargetEndColor))
++iX;

//创建一个包含起点与重点间高为1像素的临时"region"
rgnTemp.CreateRectRgn(iLeftX, y, iX, y+1);

//合并到主"region".
wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_OR);

//删除临时"region",否则下次创建时和出错
rgnTemp.DeleteObject();
}while(iX <= bm.bmWidth);
}

CWnd * pWnd = dc.GetWindow();
pWnd->SetWindowRgn(wndRgn,TRUE);
pWnd->SetForegroundWindow();

pOldFont = picDC.SelectObject(m_pSysFont);
if (m_pTargetFont!=NULL)
{
picDC.SelectObject(m_pTargetFont);
}
picDC.SetBkMode(TRANSPARENT);
picDC.SetTextColor(m_clTargetColor);
picDC.DrawText(m_strText, m_rcText, DT_WORDBREAK);
picDC.SelectObject(pOldFont);

dc.BitBlt (0, 0, bm.bmWidth, bm.bmHeight, &picDC, 0, 0, SRCCOPY);
dc.SelectObject(pOldBmp);
}

void CIrregularWindowDlg::InitDialogInfo()
{
if (!m_bitmap.LoadBitmap(m_uiResourceID))
{
CDialog::OnCancel();
return;
}

BITMAP bm;
CRect rtWindow;

m_bitmap.GetBitmap(&bm);

GetWindowRect(&rtWindow);
rtWindow.right = rtWindow.left+bm.bmWidth;
rtWindow.bottom =rtWindow.top +bm.bmHeight;
MoveWindow(&rtWindow);
}

void CIrregularWindowDlg::SetReplacePicColorRange(COLORREF TargetStartColor, COLORREF TargetEndColor)
{
m_TargetStartColor = TargetStartColor;
m_TargetEndColor = TargetEndColor;
}

/************************************************************************/
/* 加载位图
/************************************************************************/
BOOL CIrregularWindowDlg::SetLoadBitmap(UINT BitmapID)
{
if (BitmapID>0)
{
m_uiResourceID = BitmapID;
}
else
{
return FALSE;
}

return TRUE;
}

/************************************************************************/
/*
设置对话框显示的文字,可支持换行\n
参数:
rcText:文字位置,CRect类型
lstrText:显示的内容
/************************************************************************/
void CIrregularWindowDlg::SetDrawText(CRect rcText, CString lstrText)
{
m_rcText = rcText;
m_strText = _T("");
m_strText = lstrText;
}

/************************************************************************/
/*
设置对话框显示的文字字体
参数:
fontObject:字体指针
/************************************************************************/
void CIrregularWindowDlg::SetDrawTextFont(CFont *fontObject)
{
if (fontObject!=NULL)
{
m_pTargetFont = fontObject;
}
}

/************************************************************************/
/*
设置对话框显示的文字字体颜色
参数:
clValue:目标颜色
/************************************************************************/
void CIrregularWindowDlg::SetDrawTextColor(COLORREF clTargetValue)
{
m_clTargetColor = clTargetValue;
}

void CIrregularWindowDlg::OnClose()
{
// TODO: Add your message handler code here and/or call default
// 删除字体
if (m_pSysFont)
{
m_pSysFont->DeleteObject();
delete m_pSysFont;
m_pSysFont = NULL;
}

if (m_pTargetFont)
{
m_pTargetFont->DeleteObject();
delete m_pTargetFont;
m_pTargetFont = NULL;
}

CDialog::OnClose();
}


调用代码:

// 系统默认字体
m_pSysFont = new CFont;
m_pSysFont->CreateFont(12, // nHeight
0, // nWidth
0, // nEscapement
0, // nOrientation
FW_NORMAL, // nWeight
FALSE, // bItalic
FALSE, // bUnderline
0, // cStrikeOut
ANSI_CHARSET, // nCharSet
OUT_DEFAULT_PRECIS, // nOutPrecision
CLIP_DEFAULT_PRECIS, // nClipPrecision
DEFAULT_QUALITY, // nQuality
DEFAULT_PITCH | FF_SWISS, // nPitchAndFamily
_T("宋体")); // lpszFac

m_pIrrDlg = new CIrregularWindowDlg;
ASSERT(m_pIrrDlg);
if (!m_pIrrDlg->SetLoadBitmap(IDB_IRREGULAR_PICTURE))
{
return FALSE;
}

m_pIrrDlg->SetDrawTextFont(m_pSysFont);
m_pIrrDlg->SetDrawTextColor(RGB(95,107,122));
m_pIrrDlg->SetReplacePicColorRange(RGB(200,5,5), RGB(255,5,5));
m_pIrrDlg->Create(CIrregularWindowDlg::IDD, this);
m_pIrrDlg->ShowWindow(SW_HIDE);


ps:这里的对话框创建不要使用DoModal (),因为它是模态对话框的。为了能够隐藏和灵活调用显示对话框,我们应该使用Create来创建对话框。

OK,完工。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: