65.9K
CodeProject 正在变化。 阅读更多。
Home

制作酷炫的图片按钮

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.27/5 (16投票s)

2003年9月22日

CPOL

4分钟阅读

viewsIcon

135042

downloadIcon

5389

本文介绍如何在对话框中创建酷炫的按钮。

更新于:2010年6月8日  

我知道第一次我写这篇文章的时候,你们并不喜欢它,因为我的非母语和对英语语言以及 ON_MESSAGE 宏实现的生疏,这导致在发布模式下崩溃。我已更新了这篇文章,希望这次你们会喜欢。我单独添加了源代码文件和示例项目供下载,并且示例项目中的解决方案已转换为 Visual Studio 2008。 

介绍 

CP 和互联网上有许多关于创建酷炫按钮的文章,但如果你正在寻找一个10分钟就能解决问题的方案,而无需阅读那些精美、庞大且花哨的文章,那么这篇文章就是为你准备的。 

它的工作原理是,它假设每个按钮都有三种状态,即 1) 正常,2) 悬停,3) 按下。 

正常:当按钮在屏幕上对用户可见,并且鼠标尚未进入按钮区域时。 

悬停:当用户将鼠标指针移到按钮上方时,按钮会亮起。 

按下:这是按钮被按下(或单击)的状态,或者当按下鼠标左键但尚未释放时。 

 

对于按钮的每种状态,都需要一个来自资源的图像,并且所有三个图像的大小必须相同。 

这是三个状态外观的快照。 

快照 

Sample screenshot


如何使用? 

在你的对话框中创建一个按钮,并将其设置为 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分钟解决方案来将他们表单上的所有按钮变成酷炫按钮的人准备的。 

© . All rights reserved.