制作酷炫的图片按钮
本文介绍如何在对话框中创建酷炫的按钮。
更新于:2010年6月8日
我知道第一次我写这篇文章的时候,你们并不喜欢它,因为我的非母语和对英语语言以及 ON_MESSAGE 宏实现的生疏,这导致在发布模式下崩溃。我已更新了这篇文章,希望这次你们会喜欢。我单独添加了源代码文件和示例项目供下载,并且示例项目中的解决方案已转换为 Visual Studio 2008。
介绍
CP 和互联网上有许多关于创建酷炫按钮的文章,但如果你正在寻找一个10分钟就能解决问题的方案,而无需阅读那些精美、庞大且花哨的文章,那么这篇文章就是为你准备的。
它的工作原理是,它假设每个按钮都有三种状态,即 1) 正常,2) 悬停,3) 按下。
正常:当按钮在屏幕上对用户可见,并且鼠标尚未进入按钮区域时。
悬停:当用户将鼠标指针移到按钮上方时,按钮会亮起。
按下:这是按钮被按下(或单击)的状态,或者当按下鼠标左键但尚未释放时。
对于按钮的每种状态,都需要一个来自资源的图像,并且所有三个图像的大小必须相同。
这是三个状态外观的快照。
快照
如何使用?
在你的对话框中创建一个按钮,并将其设置为 Owner-Drawn。正如你们中的许多人可能已经知道的那样,这可以在对话框资源编辑器中设置,也可以在运行时设置。
有一个派生自 CButton 的 CCoolButton 类。你需要为你的对话框类中的每个按钮创建一个 CCoolButton 类型的成员,并在 DoDataExchange 中使用 DDX_Control 进行子类化。
以下是你可能使用的唯一构造函数
CCoolButton(int nIDNormal, int nIDHover, int nIDDown);
这三个参数是资源 ID,你应该指定位图资源的 ID。。
默认构造函数是私有的,你在创建对象时必须从资源中指定三个位图。
10分钟实现
步骤 1:从顶部的链接下载源文件。
步骤 2:将 Fcool.h 和 Fcool.cpp 添加到你的项目中。
步骤 3:对于每个按钮
a) 添加三个(正常、悬停和按下)图像,除非某些按钮共享外观。
b) 在你的 CDialog 派生类中添加一个 CCoolButton 成员
c) 将你的按钮更改为 Owner-Drawn。
d) 在 DoDataExchange() 中,使用你的 CDialog 派生类中的 CCoolButton 成员对象对你的按钮资源 ID 进行 DDX_Control。
步骤 4:告诉你的老板,你这周的工作完成了 :)
它是如何工作的?
它所做的就是捕获这三个状态:1) 鼠标指针尚未进入区域,2) 鼠标指针已进入区域,3) 鼠标指针在按钮区域内,并且用户按下了左键。
在构造函数中,位图已从资源加载到 CCoolButtons 聚合的三个 CBitmap 对象中。
_TrackMouseEvent() 被用来捕获鼠标指针离开按钮区域的事件,我称之为“OnLeave”,并在消息映射中定义,使用 OnMessage。
当用户将鼠标指针移到按钮区域时,按钮的状态会变为悬停,并且自定义(重写的)DrawItem 被调用,所以我们从 m_bmpHover 成员绘制悬停图像。它会调用 _TrackMouseEvent() 来尝试查看指针是否已离开该区域。
以下是 OnMouseMove 的代码,
void CCoolButton::OnMouseMove(UINT nFlags, CPoint point) { CRect ButtonRect; TRACKMOUSEEVENT tme; GetWindowRect(&ButtonRect); if (m_Status == DOWN) { if (IsInRect(ButtonRect,point)) { } else { SetStatus(HOVER); Invalidate(FALSE); } } else if (m_PrevStatus == DOWN && m_Status == HOVER) { SetStatus(DOWN); } else { if (IsInRect(ButtonRect,point)) { SetStatus(HOVER); Invalidate(FALSE); } else { SetStatus(NORMAL); } } CButton::OnMouseMove(nFlags, point); tme.cbSize = sizeof(TRACKMOUSEEVENT); tme.dwFlags = TME_LEAVE; tme.hwndTrack = m_hWnd; _TrackMouseEvent(&tme); }
通常,在 Windows 中,如果你看普通的按钮,当你按住鼠标左键在其上按下,而不释放就将指针移出该区域,它不会“放过”按钮,虽然它会再次绘制正常图片,但当你将指针移回该区域(鼠标左键仍然按下)时,它会再次绘制“按下”图像,如果你在指针在该区域内时释放按钮,它会发送命令。为了模拟这种行为,我在 OnLButtonDown() 和 OnLButtonUp() 中分别使用了 SetCapture() 和 ReleaseCapture() 的帮助。
以下是 DrawItem。
void CCoolButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { CDC *pthisDC; CDC bmpDC; CBitmap *pOldBitmap; pthisDC = CDC::FromHandle(lpDrawItemStruct->hDC); bmpDC.CreateCompatibleDC(pthisDC); switch (m_Status) { case NORMAL: pOldBitmap = bmpDC.SelectObject(&m_bmpNormal); break; case HOVER: pOldBitmap = bmpDC.SelectObject(&m_bmpHover); break; case DOWN: pOldBitmap = bmpDC.SelectObject(&m_bmpDown); break; } pthisDC->BitBlt(0,0,lpDrawItemStruct->rcItem.right-lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top,&bmpDC,0,0,SRCCOPY); bmpDC.SelectObject(pOldBitmap); bmpDC.DeleteDC(); }
好了,你的按钮准备好了。我很想听听你对这篇文章的反馈。
好的!:)
我知道它不是性能优化的,并且可以在很多方面进行改进,而且我还未处理“禁用”按钮状态。 但再次强调,这是为那些正在寻找一个10分钟解决方案来将他们表单上的所有按钮变成酷炫按钮的人准备的。