当我们开发WM程序的时候,BUTTON控件用得比较多,通常用BUTTON控件捕捉用户点击的消息,在这里我们可以使用GDI方式实现类似BUTTON控件的功能。
实现思路( 伪代码):
1. 建立两个文件: MyButton.h  MyButton.cpp
2. 在MyButton.h 中声明几个变量

  1. // 外部接口:  
  2. public:  
  3.     void AddButton(CString sDownImage, Cstring sUpImage);   // 设置一个BUTTON按下前后的图片路径  
  4.     void SetButtonRect(CRect rc);                                           // 设置该BUTTON的位置以及大小  
  5.     int OnClick(IN HWND hwnd, IN CPoint pt);                          // 返回选*能菜单  
  6.  
  7. // 内部函数:  
  8. protected:  
  9.     CRect rc[10]  // 这里假设定义的是10个button, 分别用来记录每个button的位置。  
  10.     HBITMAP hDownBitmap[10]  // 定义按下时图片  
  11.     HBITMAP hUpBitmap[10]     // 定义松开时图片  
  12.     void InitButtonImage(HWND hWnd);           // 初始化图标  
  13.     void SetDownButtonImage(HWND hWnd, int nPreSel);   // 声明按下图标方法  
  14.     void SetUpButtonImage(HWND hWnd, int nSel);   // 声明松开图标方法  
  15. protected:  
  16.     int m_nCurrentCount;    // 当前BUTTON数目  
  17.  
  18. protected:  
  19.     int m_nCurrentSel;       // 当前选中图标的索引  
  20.     int m_nPreSel;             // 上一级选中图标索引


3. MyButton.cpp 实现

  1. MyButton::MyButton()  
  2. {  
  3.    m_nCurrentCount = 0;  
  4.    // 初始化  
  5.    for(int n = 0; n < 10; n ++)  
  6.   {  
  7.     hDownBitmap[n] = NULL;  
  8.     hUpBitmap[n] = NULL;  
  9.   }  
  10. }      
  11. void MyButton::AddButton(CString sDownImage, CString sUpImage)  
  12. {  
  13.      hDownBitmap[m_nCurrentCount] = SHLoadImageFile(sDownImage);  
  14. // 这里应该加个断言防止加载失败  
  15.      ASSERT(NULL != hDownBitmap[m_nCurrentCount]);  
  16.      hUpBitmap[m_nCurrentCount] = SHLoadImageFile(sUpImage);  
  17. // 这里应该加个断言防止加载失败  
  18.      ASSERT(NULL != hUpBitmap[m_nCurrentCount]);  
  19.      m_nCurrentCount ++;  
  20. }  
  21. void MyButton::SetButtonRect(CRect rc)  
  22. {  
  23.      rc[m_nCurrentCount] = rc;  
  24. }  
  25.  
  26. void MyButton::InitButtonImage(HWND hWnd)  
  27. {  
  28.     HDC hdc = GetDC(hWnd);  
  29.     // 利用双缓冲绘图  
  30.     for(int n = 0; n < m_nCurrentCount; n ++)  
  31.    {  
  32.             HDC hMemDc = CreateCompatibleDC(hdc);  
  33.             HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDc, hDownBitmap[m_nCurrentCount]);  
  34.             BITMAP bm;  
  35.             GetObject(hDownBitmap[m_nCurrentCount], sizeof(bm), &bm);  
  36.             StretchBlt(hdc, rc[m_nCurrentCount].left, rc[m_nCurrentCount].top, rc[m_nCurrentCount].right - rc[m_nCurrentCount].left, rc[m_nCurrentCount].bottom - rc[m_nCurrentCount].top, &dcSrc, 0, 0, nWidthOld, nHeightOld, SRCCOPY);  
  37.             BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hMemDc, 0, 0, SRCCOPY);  
  38.             SelectObject(hMemDc, hOldBmp);  
  39.             DeleteDC(hMemDc);  
  40.    }  
  41. }  
  42.  
  43. void MyButton::InitButtonImage(HWND hWnd)  
  44. {  
  45.     HDC hdc = GetDC(hWnd);  
  46.     // 利用双缓冲绘图  
  47.     for(int n = 0; n < m_nCurrentCount; n ++)  
  48.    {  
  49.             HDC hMemDc = CreateCompatibleDC(hdc);  
  50.             HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDc, hDownBitmap[m_nCurrentCount]);  
  51.             BITMAP bm;  
  52.             GetObject(hDownBitmap[m_nCurrentCount], sizeof(bm), &bm);  
  53.             StretchBlt(hdc, rc[m_nCurrentCount].left, rc[m_nCurrentCount].top, rc[m_nCurrentCount].right - rc[m_nCurrentCount].left, rc[m_nCurrentCount].bottom - rc[m_nCurrentCount].top, &dcSrc, 0, 0, nWidthOld, nHeightOld, SRCCOPY);  
  54.             SelectObject(hMemDc, hOldBmp);  
  55.             DeleteDC(hMemDc);  
  56.    }  
  57. }  
  58. void MyButton::SetUpButtonImage(HWND hWnd, int nSel)  
  59. {  
  60.     HDC hdc = GetDC(hWnd);  
  61.     CRect rcSel;  
  62.     rcSel = rc[nSel];  
  63.  
  64.     m_nPreSel = nSel;  
  65.     // 利用双缓冲绘图  
  66.             HDC hMemDc = CreateCompatibleDC(hdc);  
  67.             HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDc,hUpBitmap[nSel]);  
  68.             BITMAP bm;  
  69.             GetObject(hDownBitmap[m_nCurrentCount], sizeof(bm), &bm);  
  70.             StretchBlt(hdc, rcSel.left, rcSel.top, rcSel.right - rcSel.left, rcSel.bottom - rcSel.top, &dcSrc, 0, 0, nWidthOld, nHeightOld, SRCCOPY);  
  71.             SelectObject(hMemDc, hOldBmp);  
  72.             DeleteDC(hMemDc);  
  73. }  
  74.  
  75. void MyButton::SetUpButtonImage(HWND hWnd, int nPreSel)  
  76. {  
  77.     HDC hdc = GetDC(hWnd);  
  78.     CRect rcSel;  
  79.     rcSel = rc[nSel];  
  80.  
  81.     // 利用双缓冲绘图  
  82.             HDC hMemDc = CreateCompatibleDC(hdc);  
  83.             HBITMAP hOldBmp = (HBITMAP)SelectObject(hMemDc,hUpBitmap[nSel]);  
  84.             BITMAP bm;  
  85.             GetObject(hDownBitmap[m_nCurrentCount], sizeof(bm), &bm);  
  86.             StretchBlt(hdc, rcSel.left, rcSel.top, rcSel.right - rcSel.left, rcSel.bottom - rcSel.top, &dcSrc, 0, 0, nWidthOld, nHeightOld, SRCCOPY);  
  87.             SelectObject(hMemDc, hOldBmp);  
  88.             DeleteDC(hMemDc);  
  89. }  
  90.  
  91. int MyButton::OnClick(IN HWND hwnd, IN CPoint pt)    // 捕捉点击消息  
  92. {  
  93.     int nClicked = -1;  // 选中的图标  
  94.     for ( int n = 0; n < m_nCountTool; n ++)  
  95.     {  
  96.         if ( m_Rect[n].PtInRect(pt))  
  97.         {  
  98.             nClicked = n;  
  99.             break;  
  100.         }          
  101.     }  
  102.     if ( -1 == nClicked )  
  103.     {  
  104.         return -1;  
  105.     }  
  106.     else 
  107.     {  
  108.         m_nCurrentSel = nClicked;  
  109.         SetDownImage(hwnd, m_nCurrentSel);   // 设置当前选中图标  
  110.         SetUpImage(hwnd, m_nCurrentSel);       // 恢复上一级选中图标的状态  
  111.         InvalidateRect(hwnd, rc[m_nCurrentSel], TRUE);    // 刷新选中范围  
  112.         InvalidateRect(hwnd, rc[m_nPreSel], TRUE);          // 刷新上一级选中范围  
  113.     }  
  114. }  

  
 以上思路实现的BUTTON效果,简单点来说,就是捕捉用户按下松开的消息,改变对应位置的图标,看起来有点像BUTTON的效果,但是相对BUTTON来说,这种方法比较简洁,同时可以增加更多的功能,例如,用户按下某个图标,图标产生旋转,缩放或者闪烁,发出声音等等效果。设计程序就更加灵活了。