各位达人:
从http://topic.csdn.net/topicfiles/2004/04/18/20/2980563.xml
上copy了例子,成功显示了异形窗口。但研究代码时始终搞不清 以下这段代码的原理。
/*
CDC *pDC 对话框窗口DC
UINT BackBitmapID 背景位图资源ID
UINT MaskBitmapID 区域处理位图资源ID
COLORREF TransColor = 0x00000000 透明颜色值,默认为黑色
*/
void CTransDlg::SetupRegion(CDC *pDC, UINT BackBitmapID, UINT MaskBitmapID, COLORREF TransColor)
{
CDC memDC;
CBitmap cBitmap;
CBitmap* pOldMemBmp = NULL;
COLORREF cl;
CRect cRect;
UINT x, y;
CRgn wndRgn, rgnTemp;
//取得窗口大小
GetWindowRect(&cRect); //背景位图资源ID
m_BackBitmapID = BackBitmapID;
//装载位图
cBitmap.LoadBitmap(MaskBitmapID);
memDC.CreateCompatibleDC(pDC);
pOldMemBmp = memDC.SelectObject(&cBitmap); //首先创建默认的完整区域为完整的窗口区域
wndRgn.CreateRectRgn(0, 0, cRect.Width(), cRect.Height());
//下面的两层循环为检查背景位图象素颜色,进行透明区域处理;
//当象素颜色为指定的透明值时,即将该点从区域中剪裁掉。
//其中用到的几个成员变量m_MaskLeftOff、m_MaskTopOff、
//m_MaskRightOff、m_MaskBottomOff、m_FrameWidth
//和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(cl == 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);
}代码的文档说明是 利用抠像素的方式 来实现异形窗口。
获得像素点颜色
cl = memDC.GetPixel(x - m_FrameWidth-m_MaskLeftOff,y - m_CaptionHeight-m_MaskTopOff);
颜色与指定的颜色值比较
if(cl == TransColor)
{
如果两者颜色值相等,则抠像素
}虽然可以实现效果,但无论我设置TransColor为何种颜色,都能正确显示异形窗口。
所以我就不明白了。
既然是抠去所有指定的颜色,那为什么能正确的异形窗口,毕竟窗口本身的颜色只有一种啊。
请各位达人赐教!

解决方案 »

  1.   

    虽然可以实现效果,但无论我设置TransColor为何种颜色,都能正确显示异形窗口。
    所以我就不明白了
    -----------------------------
    好像不太可能阿。既然是抠去所有指定的颜色,那为什么能正确的异形窗口,毕竟窗口本身的颜色只有一种啊。
    ----------------------------------------
     wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_XOR); 这一句才是关键阿。相同的颜色作xor,就变得透明了。它是根据mask的位图来确定哪些要扣掉哪些不要。
      

  2.   

    谢谢hjunxu(hjun),的确 wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_XOR); 这一句才是关键。相同的颜色作xor,就变得透明了。
    但也必须在if(cl==TransColor){}中才行,否则整个窗口都透明了。
    我的确测试了一下。使用TransColor = 0x00000000 或者 0x00FFFFFF 或者 0x00F0000F 都出现相同的结果(也许细致的颜色变化我看不出,呵呵)。我对代码的理解如下:
    memDC.CreateCompatibleDC(pDC); 在内存中创建一块和传入参数pDC一致的内存区 
    pOldMemBmp = memDC.SelectObject(&cBitmap); 设置内存区新的替代图形 ——该区域我的理解是基色都是灰色,和源窗口一样大,只是左上角为图形
    wndRgn.CreateRectRgn(0, 0, cRect.Width(), cRect.Height()); 创建默认的完整区域为完整的窗口区域——该区域我的理解是都是灰色的,和源窗口一样大for(x...){
     for(y...){
       对内存区逐像素扫描
       获取内存区像素颜色
       if(判断内存区像素颜色是否为指定的颜色){
          如果是 对窗口区域和内存区域相同位置的区域合并,相同的颜色作xor,变透明。并将透明存储到窗口区域。——我的理解是将两者都是灰色的部分xor,所以变透明。
       }
     }
    }
    我不明白 if(判断内存区像素颜色是否为指定的颜色) 的原理,作用我是看到了,如果没有这个判断,整个窗口都透明了(这也是奇怪的地方)
      

  3.   

    原理很简单,创建一个像素的Rgn,然后把这个Rgn从原来那个Rgn里挖掉
    wndRgn.CombineRgn(&wndRgn, &rgnTemp, RGN_XOR);
    RGN_XOR的意思就是二个Rgn有相同的部分去掉,不同的部分保留,
    这里用RGN_DIFF效果是一样的如果没有这个判断,所有像素都会被扣掉,当然也就全部透明了
      

  4.   

    谢谢goodboyws,问题是为什么判断时,可以是任意的颜色 if(cl==白色)可以,if(cl==黑色)也可以,if(cl==其他色)也可以,这是我搞不明白的地方
      

  5.   

    所以说你参数给的不对,TransColor肯定只等于0x00000000,你的参数没传进来,用的是缺省值,你可以在Debug时进行验证
      

  6.   

    谢谢goodboyws,debug下我跟踪进去了,TransColor可以等于 0x00000000 0x00FFFFFF 0x00AABBFF,就测试了三个,都是能够正常显示。所以不是TransColor只等于0x00000000的原因。你有邮件吗?我把代码发给你看看如何?
      

  7.   

    if(cl == TransColor)你跟踪的时候如果两个颜色不相等这个判断里面的代码都不会被执行啊,怎么可能会有效呢 ??你看一下你改的程序有没有生效啊,不要弄错了.
      

  8.   

    cl为每个像素点的颜色值,由于载入的背景位图资源和模版装载位图都是彩色图片。所以cl值每种颜色都是有可能的。而TransColor是参数传入固定的。所以所有的像素扫描下来总是有和TransColor相同的时候。我的程序是VC6编辑环境下,重新编译好多次了,总是这样。