|
楼主 |
发表于 2005-11-23 16:48:31
|
显示全部楼层
向CTransDlg类添加区域处理功能模块void CTransDlg::SetupRegion(CDC *pDC /*对话框窗口DC*/, UINT BackBitmapID /*背景位图资源ID*/, UINT MaskBitmapID /*区域处理位图资源ID*/, COLORREF TransColor = 0x00000000 /*透明颜色值,默认为黑色*/)。到目前为止,我们暂时认为MaskBitmapID等同于BackBitmapID。其核心工作是根据MaskBitmapID指示位图的象素颜色进行区域组合。完整的代码如下:
<></P>void CTransDlg::SetupRegion(CDC *pDC /*对话框窗口DC*/,
<></P>UINT BackBitmapID /*背景位图资源ID*/,
<></P>UINT MaskBitmapID /*区域处理位图资源ID*/,
<></P>COLORREF TransColor /*透明颜色值*/)
<></P>{
<></P>CDC memDC;
<></P>CBitmap cBitmap;
<></P>CBitmap* pOldMemBmp = NULL;
<></P>COLORREF cl;
<></P>CRect cRect;
<P></P>UINT x, y;
<P></P>CRgn wndRgn, rgnTemp;
<P></P>
<P></P>//取得窗口大小
<P></P>GetWindowRect(&cRect);
<P></P>
<P></P>//背景位图资源ID
<P></P>m_BackBitmapID = BackBitmapID
<P></P>//装载位图
<P></P>cBitmap.LoadBitmap(MaskBitmapID);
<P></P>memDC.CreateCompatibleDC(pDC);
<P></P>pOldMemBmp = memDC.SelectObject(&cBitmap);
<P></P>
<P></P>//首先创建默认的完整区域为完整的窗口区域
<P></P>wndRgn.CreateRectRgn(0, 0, cRect.Width(), cRect.Height());
<P></P>
<P></P>//下面的两层循环为检查背景位图象素颜色,进行透明区域处理;
<P></P>//当象素颜色为指定的透明值时,即将该点从区域中剪裁掉。
<P></P>//其中用到的几个成员变量m_MaskLeftOff、m_MaskTopOff、
<P></P>//m_MaskRightOff、m_MaskBottomOff、m_FrameWidth
<P></P>//和m_CaptionHeight,其作用后面再作说明,此时可全部当作0来处理。
<P></P>for(x= m_FrameWidth+m_MaskLeftOff;
<P></P>x<=cRect.Width() - m_FrameWidth-m_MaskRightOff; x++){
<P></P>for(y = m_CaptionHeight+m_MaskTopOff; <BR>y<=cRect.Height() - m_FrameWidth-m_MaskBottomOff; y++){
<P></P>//取得坐标处象素的颜色值
<P></P>cl = memDC.GetPixel(x - m_FrameWidth-m_MaskLeftOff,
<P></P>y - m_CaptionHeight-m_MaskTopOff);
<P></P>if(col == TransColor)
<P></P>{
<P></P>//象素颜色为指定的透明色,创建透明“微区域”
<P></P>rgnTemp.CreateRectRgn(x, y, x+1, y+1);
<P></P>//“扣像”,从完整的区域中“扣除”透明的“微区域”
<P></P>wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_XOR);
<P></P>//删除刚创建的透明“微区域”,释放系统资源
<P></P>rgnTemp.DeleteObject();
<P></P>}
<P></P>}
<P></P>}
<P></P>if (pOldMemBmp) memDC.SelectObject(pOldMemBmp);
<P></P>
<P></P>//用设定窗口为指定的区域
<P></P>SetWindowRgn((HRGN)wndRgn, TRUE);
<P></P>}
<P></P>
<P></P>重置系统默认的背景擦除操作,即添加WM_ERASEBKGND消息处理过程,这一步可以借助ClassWizard来简化操作。
<P></P>BOOL CTransDlg::OnEraseBkgnd(CDC* pDC)
<P></P>{
<P></P>// TODO: Add your message handler code here and/or call default
<P></P>CRect rect;
<P></P>CDC memDC;
<P></P>CBitmap cBitmap;
<P></P>CBitmap* pOldMemBmp = NULL;
<P></P>
<P></P>GetWindowRect(&rect);
<P></P>
<P></P>//装载背景位图
<P></P>cBitmap.LoadBitmap(m_BackBitmapID);
<P></P>memDC.CreateCompatibleDC(pDC);
<P></P>pOldMemBmp = memDC.SelectObject(&cBitmap);
<P></P>
<P></P>//将背景位图复制到窗口客户区
<P></P>pDC->BitBlt(0, 0, rect.Width(), rect.Height(),
<P></P>&memDC, 0, 0, SRCCOPY);
<P></P>
<P></P>if (pOldMemBmp) memDC.SelectObject( pOldMemBmp );
<P></P>
<P></P>//删除系统却省的OnEraseBkgnd功能
<P></P>//return CDialog::OnEraseBkgnd(pDC);
<P></P>return TRUE;
<P></P>}
<P></P>
<P></P>接下来是在WM_PAINT的消息处理函数OnPaint()中添加代码。由于当背景位图比较大时,进行区域处理比较耗时,所以只在启动时进行一次处理。一种方法是OnInitDialog()处理,但这样会在从启动程序到窗口出现有相当的延迟,易引起程序尚未启动的误解。再一种方法就是在OnPaint()处理,但为了避免重复处理,可以加上一个判断标志。以下是OnPaint()的代码,正体为AppWizard生成,粗体为自己添加内容。
<P></P>
<P></P>void CTransDlg::OnPaint()
<P></P>{
<P></P>if (IsIconic())
<P></P>{
<P></P>……
<P></P>}
<P></P>else
<P></P>{
<P></P>if(m_nFirstRun){ //首次运行标志
<P></P>//修改鼠标光标为等待方式
<P></P>BeginWaitCursor();
<P></P>//设置背景区域
<P></P>SetupRegion(GetWindowDC(),<BR>IDB_BACKBMP, <BR>IDB_BACKBMP,<BR>0x00FFFFFF /*白色*/);
<P></P>//恢复鼠标光标为正常模式
<P></P>EndWaitCursor();
<P></P>m_nFirstRun = 0;
<P></P>}
<P></P>CDialog::OnPaint();
<P></P>}
<P></P>}
<P></P>
<P></P> |
|