📄 csdn_文档中心_用vc++实现异形窗口.htm
字号:
size=3>消息,</FONT><FONT size=3>Windows</FONT><FONT face=宋体 lang=ZH-CN
size=3>向窗口发送一个</FONT><FONT size=3>WM_ERASEBKGND</FONT><FONT face=宋体
lang=ZH-CN size=3>消息通知该窗口擦除背景,可以使用</FONT><FONT
size=3>VC++</FONT><FONT face=宋体 lang=ZH-CN size=3>的</FONT><FONT
size=3>ClassWizard</FONT><FONT face=宋体 lang=ZH-CN
size=3>重载该消息的缺省处理程序来擦除背景(实际是用刷子画),并返回</FONT><FONT
size=3>TRUE</FONT><FONT face=宋体 lang=ZH-CN size=3>以防止</FONT><FONT
size=3>Windows</FONT><FONT face=宋体 lang=ZH-CN size=3>擦除窗口。</P>
<P align=justify></P></FONT><FONT size=3>
<P align=justify>2</FONT><FONT face=宋体 lang=ZH-CN size=3>.改变窗口外形</P>
<P align=justify>通过使用新的</FONT><FONT size=3>SDK</FONT><FONT face=宋体
lang=ZH-CN size=3>函数</FONT><FONT size=3>SetWindowRgn()</FONT><FONT
face=宋体 lang=ZH-CN
size=3>,可以将绘画和鼠标消息限定在窗口的一个指定的区域,因此实际上是使窗口成为指定的不规则形状(区域形状)。“区域”是</FONT><FONT
size=3>Windows GDI</FONT><FONT face=宋体 lang=ZH-CN
size=3>中一种强有力的机制,区域是设备上的一块空间,可以是任意形状,复杂的区域可以由各个小区域组合而成。</FONT><FONT
size=3>Windows</FONT><FONT face=宋体 lang=ZH-CN
size=3>内含的区域创建函数有</FONT><FONT size=3>CreateRectRgn()</FONT><FONT
face=宋体 lang=ZH-CN size=3>、</FONT><FONT
size=3>CreatePolyRgn()</FONT><FONT face=宋体 lang=ZH-CN
size=3>、</FONT><FONT size=3>CreatePolygonRgn()</FONT><FONT face=宋体
lang=ZH-CN size=3>、</FONT><FONT
size=3>CreateRoundRectRgn()</FONT><FONT face=宋体 lang=ZH-CN
size=3>和</FONT><FONT size=3>CreateEllipticRgn()</FONT><FONT face=宋体
lang=ZH-CN size=3>,再通过</FONT><FONT size=3>CombineRgn()</FONT><FONT
face=宋体 lang=ZH-CN size=3>来组合区域,即可得到复杂形状的区域,获得复杂形状的窗口外形。</P>
<P align=justify>通过上面的方法虽然可以得到“异形”窗口,但感觉颜色单调,外形也不够“</FONT><FONT
size=3>COOL</FONT><FONT face=宋体 lang=ZH-CN
size=3>”,能否获得更酷的“异形”对话框</FONT><FONT size=3>/</FONT><FONT face=宋体
lang=ZH-CN size=3>窗口呢?回答是肯定的。下面就介绍利用位图和蒙板创建“异形”对话框</FONT><FONT
size=3>/</FONT><FONT face=宋体 lang=ZH-CN size=3>窗口的方法。</P>
<P align=justify></P></FONT><FONT size=3>
<P align=justify>3</FONT><FONT face=宋体 lang=ZH-CN
size=3>.利用位图创建异形对话框窗口</P>
<P
align=justify>利用位图创建异形对话框原理是根据象素的颜色来进行“扣像”处理,对所有非指定颜色象素区域进行区域组合。利用这一技术,实际上就是实现对话框</FONT><FONT
size=3>/</FONT><FONT face=宋体 lang=ZH-CN
size=3>窗口的位图背景,并且对指定的颜色区域进行透明处理。下面就以透明位图为背景的对话框为例来说明:</P>
<P align=justify>首先用绘图软件如</FONT><FONT size=3>PhotoShop</FONT><FONT
face=宋体 lang=ZH-CN size=3>绘制编辑一幅拟做对话框背景用的图片,用</FONT><FONT
size=3>BMP</FONT><FONT face=宋体 lang=ZH-CN
size=3>格式保存,假设存为</FONT><FONT size=3>Back.Bmp</FONT><FONT face=宋体
lang=ZH-CN size=3>。需要说明的是,虽然</FONT><FONT size=3>Visual
C++</FONT><FONT face=宋体 lang=ZH-CN
size=3>集成开发环境的资源编辑器只能编辑不超过</FONT><FONT size=3>16</FONT><FONT face=宋体
lang=ZH-CN size=3>色的位图,但完全我们可以以真彩色方式存储,不必理会</FONT><FONT
size=3>Visual C++</FONT><FONT face=宋体 lang=ZH-CN size=3>的警告。</P>
<P align=justify>下一步是用</FONT><FONT size=3>Visual C++</FONT><FONT
face=宋体 lang=ZH-CN size=3>的</FONT><FONT size=3>AppWizard</FONT><FONT
face=宋体 lang=ZH-CN size=3>创建一个基于对话框的应用程序假定命名为</FONT><FONT
size=3>Trans</FONT><FONT face=宋体 lang=ZH-CN
size=3>。用资源编辑器引入背景图片</FONT><FONT size=3>Back.Bmp</FONT><FONT face=宋体
lang=ZH-CN size=3>,如果是高彩色,不必理会出现的警告信息,点击</FONT><FONT
size=3>OK</FONT><FONT face=宋体 lang=ZH-CN
size=3>确认即可。为了明确,修改默认的资源</FONT><FONT size=3>ID</FONT><FONT face=宋体
lang=ZH-CN size=3>标识</FONT><FONT size=3>IDB_BITMAP1</FONT><FONT
face=宋体 lang=ZH-CN size=3>为</FONT><FONT
size=3>IDB_BACKBMP</FONT><FONT face=宋体 lang=ZH-CN
size=3>。然后修改对话框的</FONT><FONT size=3>Style</FONT><FONT face=宋体
lang=ZH-CN size=3>为</FONT><FONT size=3>Popup</FONT><FONT face=宋体
lang=ZH-CN size=3>,</FONT><FONT size=3>Border</FONT><FONT face=宋体
lang=ZH-CN size=3>为</FONT><FONT size=3>None</FONT><FONT face=宋体
lang=ZH-CN size=3>,如图</FONT><FONT size=3>1</FONT><FONT face=宋体
lang=ZH-CN size=3>。</P>
<P align=justify></P>
<P align=justify><IMG height=173
src="CSDN_文档中心_用VC++实现异形窗口.files/Image90.jpg" width=489></P>
<P align=justify></P>
<P align=center>图</FONT><FONT size=3>1</P>
<P align=center></P></FONT><FONT face=宋体 lang=ZH-CN size=3>
<P align=justify>向</FONT><FONT size=3>CTransDlg</FONT><FONT face=宋体
lang=ZH-CN size=3>类添加区域处理功能模块</FONT><FONT size=3>void
CTransDlg::SetupRegion(CDC *pDC /*</FONT><FONT face=宋体 lang=ZH-CN
size=3>对话框窗口</FONT><FONT size=3>DC*/, UINT BackBitmapID
/*</FONT><FONT face=宋体 lang=ZH-CN size=3>背景位图资源</FONT><FONT
size=3>ID*/, UINT MaskBitmapID /*</FONT><FONT face=宋体 lang=ZH-CN
size=3>区域处理位图资源</FONT><FONT size=3>ID*/, COLORREF TransColor =
0x00000000 /*</FONT><FONT face=宋体 lang=ZH-CN
size=3>透明颜色值,默认为黑色</FONT><FONT size=3>*/)</FONT><FONT face=宋体
lang=ZH-CN size=3>。到目前为止,我们暂时认为</FONT><FONT
size=3>MaskBitmapID</FONT><FONT face=宋体 lang=ZH-CN
size=3>等同于</FONT><FONT size=3>BackBitmapID</FONT><FONT face=宋体
lang=ZH-CN size=3>。其核心工作是根据</FONT><FONT
size=3>MaskBitmapID</FONT><FONT face=宋体 lang=ZH-CN
size=3>指示位图的象素颜色进行区域组合。完整的代码如下:</P></FONT><FONT size=3>
<P align=justify>void CTransDlg::SetupRegion(CDC *pDC /*</FONT><FONT
face=宋体 lang=ZH-CN size=3>对话框窗口</FONT><FONT size=3>DC*/, </P>
<P align=justify>UINT BackBitmapID /*</FONT><FONT face=宋体 lang=ZH-CN
size=3>背景位图资源</FONT><FONT size=3>ID*/,</P>
<P align=justify>UINT MaskBitmapID /*</FONT><FONT face=宋体 lang=ZH-CN
size=3>区域处理位图资源</FONT><FONT size=3>ID*/,</P>
<P align=justify>COLORREF TransColor /*</FONT><FONT face=宋体
lang=ZH-CN size=3>透明颜色值</FONT><FONT size=3>*/)</P>
<P align=justify>{</P>
<P align=justify>CDC memDC;</P>
<P align=justify>CBitmap cBitmap;</P>
<P align=justify>CBitmap* pOldMemBmp = NULL;</P>
<P align=justify>COLORREF cl;</P>
<P align=justify>CRect cRect;</P>
<P align=justify>UINT x, y;</P>
<P align=justify>CRgn wndRgn, rgnTemp;</P>
<P align=justify></FONT><FONT face=宋体 lang=ZH-CN size=3></P>
<P align=justify></FONT><FONT size=3>//</FONT><FONT face=宋体
lang=ZH-CN size=3>取得窗口大小</P></FONT><FONT size=3>
<P align=justify>GetWindowRect(&cRect);</P>
<P align=justify></P></FONT><FONT face=宋体 lang=ZH-CN size=3>
<P align=justify></FONT><FONT size=3>//</FONT><FONT face=宋体
lang=ZH-CN size=3>背景位图资源</FONT><FONT size=3>ID</P></FONT><FONT
face=宋体 lang=ZH-CN size=3>
<P align=justify></FONT><FONT size=3>m_BackBitmapID =
BackBitmapID</P></FONT><FONT face=宋体 lang=ZH-CN size=3>
<P align=justify></FONT><FONT size=3>//</FONT><FONT face=宋体
lang=ZH-CN size=3>装载位图</P></FONT><FONT size=3>
<P align=justify>cBitmap.LoadBitmap(MaskBitmapID);</P>
<P align=justify>memDC.CreateCompatibleDC(pDC);</P>
<P align=justify>pOldMemBmp = memDC.SelectObject(&cBitmap);</P>
<P align=justify></P>
<P align=justify>//</FONT><FONT face=宋体 lang=ZH-CN
size=3>首先创建默认的完整区域为完整的窗口区域</P>
<P align=justify></FONT><FONT size=3>wndRgn.CreateRectRgn(0, 0,
cRect.Width(), cRect.Height());</P></FONT><FONT face=宋体 lang=ZH-CN
size=3>
<P align=justify></P>
<P align=justify></FONT><FONT size=3>//</FONT><FONT face=宋体
lang=ZH-CN size=3>下面的两层循环为检查背景位图象素颜色,进行透明区域处理;</P>
<P align=justify></FONT><FONT size=3>//</FONT><FONT face=宋体
lang=ZH-CN size=3>当象素颜色为指定的透明值时,即将该点从区域中剪裁掉。</P>
<P align=justify></FONT><FONT size=3>//</FONT><FONT face=宋体
lang=ZH-CN size=3>其中用到的几个成员变量</FONT><FONT
size=3>m_MaskLeftOff</FONT><FONT face=宋体 lang=ZH-CN
size=3>、</FONT><FONT size=3>m_MaskTopOff</FONT><FONT face=宋体
lang=ZH-CN size=3>、</P>
<DIR></FONT><FONT size=3>
<P align=justify>//m_MaskRightOff</FONT><FONT face=宋体 lang=ZH-CN
size=3>、</FONT><FONT size=3>m_MaskBottomOff</FONT><FONT face=宋体
lang=ZH-CN size=3>、</FONT><FONT size=3>m_FrameWidth</P>
<P align=justify>//</FONT><FONT face=宋体 lang=ZH-CN
size=3>和</FONT><FONT size=3>m_CaptionHeight</FONT><FONT face=宋体
lang=ZH-CN size=3>,其作用后面再作说明,此时可全部当作</FONT><FONT
size=3>0</FONT><FONT face=宋体 lang=ZH-CN
size=3>来处理。</P></DIR></FONT><FONT size=3>
<P align=justify>for(x= m_FrameWidth+m_MaskLeftOff;</P>
<DIR>
<P align=justify>x<=cRect.Width() - m_FrameWidth-m_MaskRightOff;
x++){</P>
<DIR>
<DIR>
<DIR>
<P align=justify>for(y = m_CaptionHeight+m_MaskTopOff; </FONT><FONT
face=宋体 lang=ZH-CN size=3><BR></FONT><FONT
size=3>y<=cRect.Height() - m_FrameWidth-m_MaskBottomOff;
y++){</P></DIR></DIR></DIR></DIR></FONT><FONT face=宋体 lang=ZH-CN
size=3>
<P align=justify></FONT><FONT size=3>//</FONT><FONT face=宋体
lang=ZH-CN size=3>取得坐标处象素的颜色值</P></FONT><FONT size=3>
<P align=justify>cl = memDC.GetPixel(x -
m_FrameWidth-m_MaskLeftOff,</P>
<DIR>
<DIR>
<DIR>
<DIR>
<DIR>
<DIR>
<DIR>
<DIR>
<DIR>
<P align=justify>y -
m_CaptionHeight-m_MaskTopOff);</P></DIR></DIR></DIR></DIR></DIR></DIR></DIR></DIR></DIR>
<P align=justify>if(col == TransColor)</P>
<P align=justify>{</P>
<P align=justify>//</FONT><FONT face=宋体 lang=ZH-CN
size=3>象素颜色为指定的透明色,创建透明“微区域”</P></FONT><FONT size=3>
<P align=justify>rgnTemp.CreateRectRgn(x, y, x+1, y+1);</P>
<P align=justify>//</FONT><FONT face=宋体 lang=ZH-CN
size=3>“扣像”,从完整的区域中“扣除”透明的“微区域”</P></FONT><FONT size=3>
<P align=justify>wndRgn.CombineRgn(&wndRgn, &rgnTemp,
RGN_XOR);</P>
<P align=justify>//</FONT><FONT face=宋体 lang=ZH-CN
size=3>删除刚创建的透明“微区域”,释放系统资源</P></FONT><FONT size=3>
<P align=justify>rgnTemp.DeleteObject(); </P>
<P align=justify>}</P>
<P align=justify>}</P>
<P align=justify>}</P>
<P align=justify>if (pOldMemBmp)
memDC.SelectObject(pOldMemBmp);</P></FONT><FONT face=宋体 lang=ZH-CN
size=3>
<P align=justify></P>
<P align=justify></FONT><FONT size=3>//</FONT><FONT face=宋体
lang=ZH-CN size=3>用设定窗口为指定的区域</P></FONT><FONT size=3>
<P align=justify>SetWindowRgn((HRGN)wndRgn, TRUE);</P>
<P align=justify>}</P>
<P align=justify></P></FONT><FONT face=宋体 lang=ZH-CN size=3>
<P align=justify>重置系统默认的背景擦除操作,即添加</FONT><FONT
size=3>WM_ERASEBKGND</FONT><FONT face=宋体 lang=ZH-CN
size=3>消息处理过程,这一步可以借助</FONT><FONT size=3>ClassWizard</FONT><FONT
face=宋体 lang=ZH-CN size=3>来简化操作。</P></FONT><FONT size=3>
<P align=justify>BOOL CTransDlg::OnEraseBkgnd(CDC* pDC) </P>
<P align=justify>{</P>
<P align=justify>// TODO: Add your message handler code here and/or
call default</P>
<P align=justify>CRect rect;</P>
<P align=justify>CDC memDC;</P>
<P align=justify>CBitmap cBitmap;</P>
<P align=justify>CBitmap* pOldMemBmp = NULL;</P>
<P align=justify></P>
<P align=justify>GetWindowRect(&rect);</P>
<P align=justify></P>
<P align=justify>//</FONT><FONT face=宋体 lang=ZH-CN size=3>装载背景位图</P>
<P align=justify></FONT><FONT
size=3>cBitmap.LoadBitmap(m_BackBitmapID);</P>
<P align=justify>memDC.CreateCompatibleDC(pDC);</P>
<P align=justify>pOldMemBmp = memDC.SelectObject(&cBitmap);</P>
<P align=justify></P></FONT><FONT face=宋体 lang=ZH-CN size=3>
<P align=justify></FONT><FONT size=3>//</FONT><FONT face=宋体
lang=ZH-CN size=3>将背景位图复制到窗口客户区</P>
<P align=justify></FONT><FONT size=3>pDC->BitBlt(0, 0,
rect.Width(), rect.Height(), </P>
<DIR>
<DIR>
<DIR>
<DIR>
<DIR>
<P align=justify>&memDC, 0, 0, SRCCOPY);</P></FONT><FONT face=宋体
lang=ZH-CN size=3>
<P align=justify></P></DIR></DIR></DIR></DIR></DIR>
<P align=justify></FONT><FONT size=3>if (pOldMemBmp)
memDC.SelectObject( pOldMemBmp );</P>
<P align=justify></P>
<P align=justify>//</FONT><FONT face=宋体 lang=ZH-CN
size=3>删除系统却省的</FONT><FONT size=3>OnEraseBkgnd</FONT><FONT face=宋体
lang=ZH-CN size=3>功能</P>
<P align=justify></FONT><FONT size=3>//return
CDialog::OnEraseBkgnd(pDC);</P>
<P align=justify>return TRUE;</P>
<P align=justify>}</P>
<P align=justify></P></FONT><FONT face=宋体 lang=ZH-CN size=3>
<P align=justify>接下来是在</FONT><FONT size=3>WM_PAINT</FONT><FONT
face=宋体 lang=ZH-CN size=3>的消息处理函数</FONT><FONT
size=3>OnPaint()</FONT><FONT face=宋体 lang=ZH-CN
size=3>中添加代码。由于当背景位图比较大时,进行区域处理比较耗时,所以只在启动时进行一次处理。一种方法是</FONT><FONT
size=3>OnInitDialog()</FONT><FONT face=宋体 lang=ZH-CN
size=3>处理,但这样会在从启动程序到窗口出现有相当的延迟,易引起程序尚未启动的误解。再一种方法就是在</FONT><FONT
size=3>OnPaint()</FONT><FONT face=宋体 lang=ZH-CN
size=3>处理,但为了避免重复处理,可以加上一个判断标志。以下是</FONT><FONT
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -