`
mqttb32q
  • 浏览: 14072 次
社区版块
存档分类
最新评论

Button图片按钮

 
阅读更多

Button图片按钮
2011年11月11日
  VC自定义图片按钮控件的实现  ――转载自百度文档
  以前编写过五子棋程序的框架,整个程序的背景都是我用photoshop画的,当然也包括几个按钮。
  说是按钮,其实就是图片上的按钮,跟vc的按钮控件是完全不同,但是当时我想让画的按钮也响应鼠标动作比如鼠标移动到按钮上,鼠标单击等,方法很笨,就是在主对话框中对鼠标的移动和单击动作进行检测,如果发生位置位于按钮区,就在“按钮”区另贴一幅图,以实现鼠标在其上的效果,单击类似。
  对于多个按钮,就要检测多个区域,程序十分复杂,而且性能很差。
  于是想改写vc的CButton类,来实现我的功能。在网上查了很多资料,都是说怎么在按钮上显示一副图片,能显示但是还有着原来按钮的边框,虚线。还得自己动手写。
  要求:
  1.动态生成一个图片按钮,函数输入两幅图片的ID,及按钮坐标和大小,最为重要的是指定单击它要向父窗口传递的消息值(自定义)
  2.当鼠标在经过按钮上时图片按钮变为另外一幅图,跟正常状态下的图像形成对比
  3.当鼠标单击这个按钮,父窗口得到初始化时给这个窗口指定的消息值,以便在有多个按钮存在时进行区分响应
  过程:
  1.从CButton类派生CMyBtn类,增加如下变量:
  enum {STATE_MOUSEON, STATE_NORMAL}; // 定义按钮状态
  CBitmap m_pBmp1, m_pBmp2;//Load两幅图片
  CRect m_Rc; //保存按钮客户区
  int m_State; // 按钮所处状态 为enum的两个值,代表鼠标在按钮上和正常情况下
  BOOL m_IsTimerOn; // 定时器开否,用于判断鼠标跟按钮的相对位置
  POINT m_CursorPos; // 鼠标位置
  2.因为在动态创建自定义按钮的时候,要指定图片ID、及按钮坐标大小、消息值,所以重载CButton类的Create函数。
  BOOL CMyBtn::Create(UINT IDBITMAPNOMAL, UINT IDBITMAPMOUSEON, UINT msg,
  LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
  // 重载Create,指定按钮所处两种状态应显示的图片,及单击时向父窗口传递的消息
  {
  // TODO: Add your specialized code here and/or call the base class
  m_pBmp1.LoadBitmap(IDBITMAPNOMAL);
  m_pBmp2.LoadBitmap(IDBITMAPMOUSEON);
  // 变量初始化
  m_IsTimerOn = FALSE;
  m_State = STATE_NORMAL;
  m_message = msg;
  return CButton::Create(lpszCaption, dwStyle, rect, pParentWnd, nID);
  }
  3.要想重绘按钮要设定按钮类型为BS_OWNERDRAW,重载PreSubclassWindow函数
  void CMyBtn::PreSubclassWindow()
  {
  // TODO: Add your specialized code here and/or call the base class
  ModifyStyle(0, BS_OWNERDRAW|BS_PUSHBUTTON);
  CButton::PreSubclassWindow();
  }
  4.然后对按钮进行重绘,重载DrawItem函数
  void CMyBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  {
  // TODO: Add your code to draw the specified item
  GetClientRect(&m_Rc); // 得到按钮窗口的有效矩形区域
  CDC *pDc = CDC::FromHandle(lpDrawItemStruct->hDC); // 取得按钮控件客户区域的设备变量指针
  CDC MemDc;
  MemDc.CreateCompatibleDC(pDc);
  CBitmap * pBmp = NULL;
  if(STATE_NORMAL == m_State)
  {
  pBmp = MemDc.SelectObject(&m_pBmp1);
  }
  if(STATE_MOUSEON == m_State)
  {
  pBmp = MemDc.SelectObject(&m_pBmp2);
  }
  pDc->BitBlt(m_Rc.left, m_Rc.top, m_Rc.right, m_Rc.bottom, &MemDc, 0, 0, SRCCOPY);
  pBmp = MemDc.SelectObject(pBmp);
  }
  5.判断鼠标是否在按钮区域内的方法是,如果鼠标在按钮区域移动,则设定一个计时器,对鼠标位置进行跟踪检测,如果在则设定m_State为STATE_MOUSEON,否则设为STATE_NORMAL。然后无效整个客户区进行重绘。
  void CMyBtn::OnMouseMove(UINT nFlags, CPoint point)
  {
  // TODO: Add your message handler code here and/or call default
  if(!m_IsTimerOn)
  {
  SetTimer(10000, 100, NULL);
  m_IsTimerOn = TRUE;
  }
  CButton::OnMouseMove(nFlags, point);
  }
  void CMyBtn::OnTimer(UINT nIDEvent)
  {
  // TODO: Add your message handler code here and/or call default
  CRect rect;
  GetWindowRect(&rect); // 得到按钮客户区域的屏幕坐标位置
  GetCursorPos(&m_CursorPos); // 得到鼠标的屏幕坐标位置
  if(rect.PtInRect(m_CursorPos)) // 如果鼠标在按钮的客户区内
  {
  if(STATE_MOUSEON != m_State)
  {
  m_State = STATE_MOUSEON;
  Invalidate();
  }
  }
  else  // 鼠标离开按钮客户区
  {
  if(STATE_NORMAL != m_State)
  {
  m_State = STATE_NORMAL;
  Invalidate();
  }
  KillTimer(nIDEvent);
  m_IsTimerOn = FALSE;
  }
  CButton::OnTimer(nIDEvent);
  }
  6.响应单击操作,向父窗口传递m_message消息,其值在Create时由父窗口指定。
  void CMyBtn::OnLButtonUp(UINT nFlags, CPoint point)
  {
  // TODO: Add your message handler code here and/or call default
  GetParent()->PostMessage(m_message);
  CButton::OnLButtonUp(nFlags, point);
  }
  附:VC自定义消息响应的实现
  第一步:定义消息。开发Windows95应用程序时,Microsoft推荐用户自定义消息至少是WM_USER+100,因为很多新控件也要使用WM_USER消息。
  第二步:实现消息处理函数。该函数使用WPRAM和LPARAM参数并返回LPESULT。
  LPESULT CMainFrame::OnMyMessage(WPARAM wParam, LPARAM lParam)
  {
  // TODO: 处理用户自定义消息
  ...
  return 0;
  }
  第三步:在类头文件的AFX_MSG块中说明消息处理函数:
  class CMainFrame:public CMDIFrameWnd
  {
  ...
  // 一般消息映射函数
  protected:
  // {{AFX_MSG(CMainFrame)
  afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
  afx_msg void OnTimer(UINT nIDEvent);
  afx_msg LRESULT OnMyMessage(WPARAM wParam, LPARAM lParam);
  //}}AFX_MSG
  DECLARE_MESSAGE_MAP()
  }
  第四步:在用户类的消息块中,使用ON_MESSAGE宏指令将消息映射到消息处理函数中。
  BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWnd)
  //{{AFX_MSG_MAP(CMainFrame)
  ON_WM_CREATE()
  ON_WM_TIMER()
  ON_MESSAGE(WM_MY_MESSAGE, OnMyMessage)
  //}}AFX_MSG_MAP
  END_MESSAGE_MAP()
  如果用户需要一个整个系统唯一的消息,可以调用SDK函数RegisterWindowMessage并使用ON_REGISTER_MESSAGE宏指令取代ON_MESSAGE宏指令,其余步骤同上。
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics