利用位图创建异形对话框窗口

本文介绍如何使用位图创建带有透明背景的异形对话框。通过指定颜色作为透明处理,实现对话框背景的位图化,并详细讲解了实现过程中的关键步骤和技术要点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用位图创建异形对话框原理是根据象素的颜色来进行“扣像”处理,对所有非指定颜色象素区域进行区域组合。利用这一技术,实际上就是实现对话框/窗口的位图背景,并且对指定的颜色区域进行透明处理。下面就以透明位图为背景的对话框为例来说明:  
   
  首先用绘图软件如PhotoShop绘制编辑一幅拟做对话框背景用的图片,用BMP格式保存,假设存为Back.Bmp。需要说明的是,虽然Visual   C++集成开发环境的资源编辑器只能编辑不超过16色的位图,但完全我们可以以真彩色方式存储,不必理会Visual   C++的警告。  
   
  下一步是用Visual   C++的AppWizard创建一个基于对话框的应用程序假定命名为Trans。用资源编辑器引入背景图片Back.Bmp,如果是高彩色,不必理会出现的警告信息,点击OK确认即可。为了明确,修改默认的资源ID标识IDB_BITMAP1为IDB_BACKBMP。然后修改对话框的Style为Popup,Border为None,如图1。  
   
     
  图1  
   
   
  向CTransDlg类添加区域处理功能模块void   CTransDlg::SetupRegion(CDC   *pDC   /*对话框窗口DC*/,   UINT   BackBitmapID   /*背景位图资源ID*/,   UINT   MaskBitmapID   /*区域处理位图资源ID*/,   COLORREF   TransColor   =   0x00000000   /*透明颜色值,默认为黑色*/)。到目前为止,我们暂时认为MaskBitmapID等同于BackBitmapID。其核心工作是根据MaskBitmapID指示位图的象素颜色进行区域组合。完整的代码如下:  
   
  void   CTransDlg::SetupRegion(CDC   *pDC   /*对话框窗口DC*/,    
   
                                                    UINT   BackBitmapID   /*背景位图资源ID*/,  
   
                                                    UINT   MaskBitmapID   /*区域处理位图资源ID*/,  
   
                                                    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(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消息处理过程,这一步可以借助ClassWizard来简化操作。  
   
  BOOL   CTransDlg::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,   SRCCOPY);  
   
   
                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()来实现。再添加一些变量的声名和初始化,即可编译运行。图2为运行结果示例:  
   
     
  图2   
   

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值