void CTransDlg::SetupRegion(CDC *pDC /*对话框窗口DC*/, UINT BackBitmapID /*背景位图资源ID*/,
UINT MaskBitmapID /*区域处理位图资源ID*/, COLORREF TransColor = 0x00000000 /*透明颜色值,默认为黑色*/)。
{
//我们暂时认为MaskBitmapID等同于BackBitmapID。
//其核心工作是根据MaskBitmapID指示位图的象素颜色进行区域组合。
CDC memDC;
CBitmap cBitmap;
CBitmap* pOldMemBmp = NULL;
COLORREF cl;
CRect cRect;
UINT x, y;
CRgn wndRgn, rgnTemp;
//取得窗口大小
GetWindowRect(&cRect);
//背景位图资源ID
UINT m_BackBitmapID = BackBitmapID;
//装载位图
cBitmap.LoadBitmap(MaskBitmapID);
memDC.CreateCompatibleDC(pDC);
pOldMemBmp = memDC.SelectObject(&cBitmap);
//首先创建默认的完整区域为完整的窗口区域
wndRgn.CreateRectRgn(0, 0, cRect.Width(), cRect.Height());
//下面的两层循环为检查背景位图象素颜色,进行透明区域处理;
//当象素颜色为指定的透明值时,即将该点从区域中剪裁掉。
int m_MaskLeftOff=0,m_MaskTopOff=0;
int m_MaskRightOff=0,m_MaskBottomOff=0;
int m_FrameWidth=0,m_CaptionHeight=0;
for(x= m_FrameWidth+m_MaskLeftOff;x<=cRect.Width() - m_FrameWidth-m_MaskRightOff; x++)
{
for(y = m_CaptionHeight+m_MaskTopOff; y<=cRect.Height() - m_FrameWidth-m_MaskBottomOff; y++)
{
//取得坐标处象素的颜色值
cl = memDC.GetPixel(x - m_FrameWidth-m_MaskLeftOff,y - m_CaptionHeight-m_MaskTopOff);
if(col == TransColor)
{
//象素颜色为指定的透明色,创建透明“微区域”
rgnTemp.CreateRectRgn(x, y, x+1, y+1);
//“扣像”,从完整的区域中“扣除”透明的“微区域”
wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_XOR);
//删除刚创建的透明“微区域”,释放系统资源
rgnTemp.DeleteObject();
}
}
}
if (pOldMemBmp)
memDC.SelectObject(pOldMemBmp);
//用设定窗口为指定的区域
SetWindowRgn((HRGN)wndRgn, TRUE);
}
//即添加WM_ERASEBKGND消息处理过程
OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
CRect rect;
CDC memDC;
CBitmap cBitmap;
CBitmap* pOldMemBmp = NULL;
GetWindowRect(&rect);
//装载背景位图
cBitmap.LoadBitmap(m_BackBitmapID);
memDC.CreateCompatibleDC(pDC);
pOldMemBmp = memDC.SelectObject(&cBitmap);
//将背景位图复制到窗口客户区
pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRC/DownloadFiles\a\2001-10-12\COPY);
if (pOldMemBmp)
memDC.SelectObject( pOldMemBmp );
//删除系统却省的OnEraseBkgnd功能
//return CDialog::OnEraseBkgnd(pDC);
return TRUE;
}
//接下来是在WM_PAINT的消息处理函数OnPaint()中添加代码。
//由于当背景位图比较大时,进行区域处理比较耗时,所以只在启动时进行一次处理。
//一种方法是OnInitDialog()处理,但这样会在从启动程序到窗口出现有相当的延迟,
//易引起程序尚未启动的误解。
//再一种方法就是在OnPaint()处理,但为了避免重复处理,可以加上一个判断标志。
//以下是OnPaint()的代码,正体为AppWizard生成,粗体为自己添加内容。
//
void CTransDlg::OnPaint()
{
if (IsIconic()){……}
else
{
if(m_nFirstRun)
{
//首次运行标志//修改鼠标光标为等待方式BeginWaitCursor();
//设置背景区域
SetupRegion(GetWindowDC(),IDB_BACKBMP, IDB_BACKBMP,0x00FFFFFF /*白色*/);
//恢复鼠标光标为正常模式
EndWaitCursor();
m_nFirstRun = 0;
}
CDialog::OnPaint();
}
}
//剩下的工作就是根据背景位图的大小来设置对话框窗口的大小和位置
//这可以在OnInitDialog()中通过调用MoveWindow()来实现
//但有些情况下又需要不同的样式,如有标题栏、边框等,或者只作局部的处理
//这就是前面两个成员变量m_FrameWidth和m_CaptionHeight作用
BOOL CTransBmpDlg::OnInitDialog()
{
// TODO: Add extra initialization here
m_nFirstRun = 1;
//数据设置,窗口左上角坐标:
m_Left=0;
m_Top=0;
//背景位图宽高:
m_Width=535;
m_Height=105;
SetSize(0, 0, 535, 105);
//蒙板处理区域与窗口边框的距离
m_MaskLeftOff=m_MaskTopOff=m_MaskRightOff=m_MaskBottomOff=0;
//窗口边框与标题栏象素值
m_FrameWidth = m_CaptionHeight = 0;
//取得窗口样式
LONG style = ::GetWindowLong(this->m_hWnd, GWL_STYLE);
//如保留窗口风格样式,则根据不同的窗口边框类型
//选取不同的m_FrameWidth和m_CaptionHeight值,
//也可以根据处理位置的需要进行付值
if((style & WS_BORDER) == WS_BORDER)
m_FrameWidth = ::GetSystemMetrics(SM_CXBORDER);
if((style & WS_THICKFRAME) == WS_THICKFRAME)
m_FrameWidth = ::GetSystemMetrics(SM_CXFIXEDFRAME);
if((style & DS_MODALFRAME) == DS_MODALFRAME)
m_FrameWidth = ::GetSystemMetrics(SM_CXFIXEDFRAME);
if((style & WS_CAPTION) == WS_CAPTION)
{
m_FrameWidth = ::GetSystemMetrics(SM_CXFIXEDFRAME);
m_CaptionHeight = ::GetSystemMetrics(SM_CYSMCAPTION);
}
m_CaptionHeight += m_FrameWidth * 2;
//重置窗口的位置和大小
MoveWindow(m_Left, m_Top, _FrameWidth * 2m_Width + m, m_Height + m_CaptionHeight, TRUE);
……return TRUE;
// return TRUE unless you set the focus to a control
}
//使窗口样式不仅仅受背景位图颜色的控制。
//通过指定SetupRegion()的MaskBitmapID 为一个我们称之为“蒙板”的双色位图
posted on 2008-08-04 11:56
cpsprogramer 阅读(3144)
评论(3) 编辑 收藏 引用 所属分类:
VC++