自绘Tab控件

自绘tab按钮效果图如下:

 

使用例子:

MyTabControl *tabControl = NULL;

tabControl = new MyTabControl();
tabControl->Create(this, CRect(0,0,125,27), L"花生", ID_BTN_MYTAB);
tabControl->SetTabIndex(index);

tabControl->SetShowText(L"花生");

tabControl->SetTabState(TAB_STATE_DOWN);

tabControl->SetToolTipText(L"花生");

头文件:

[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. #pragma once  
  2. #include "LhsButton.h"  
  3.   
  4. // MyTabControl  
  5.   
  6. #define ID_BTN_MYTAB_CLOSE  2100            //关闭按钮的id  
  7. #define MYWM_BTN_TAB_CLOSE WM_USER+2001     //关闭按钮单击响应  
  8. #define MYWM_BTN_TAB_CLICK WM_USER+2002     //tab按钮单击  
  9.   
  10. //tab按钮的状态  
  11. enum TabState  
  12. {  
  13.     TAB_STATE_NOR           = 0,  
  14.     TAB_STATE_DOWN          = 1,  
  15. };  
  16. class MyTabControl : public CWnd  
  17. {  
  18.     DECLARE_DYNAMIC(MyTabControl)  
  19.   
  20. public:  
  21.     MyTabControl();  
  22.     virtual ~MyTabControl();  
  23.   
  24.      bool Create(CWnd* pParent,CRect rc,CString text,DWORD id = 0,DWORD style = WS_VISIBLE|WS_CHILD);    
  25.   
  26.     DECLARE_MESSAGE_MAP()  
  27.   
  28. public:  
  29.     void SetShowText(CString strShowText);  
  30.   
  31. protected:  
  32.     CString szClassName;    
  33.     bool m_isMouseHover;        //鼠标是否悬浮  
  34.     bool m_isMouseClicked;      //鼠标是否单击  
  35.     CString m_strShowText;      //要显示的文字  
  36.     CString m_strTabText;       //绘制在tab按钮下的文字  
  37.   
  38.     Image*                      m_pImgNor;          //正常时的图片  
  39.     Image*                      m_pImgHot;          //鼠标悬浮时的图片  
  40.     Image*                      m_pImgDown;         //单击按下时的图片  
  41.       
  42.     void PostClickEvent();  
  43.     afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);  
  44.     afx_msg void OnMouseMove(UINT nFlags, CPoint point);    
  45.     afx_msg void OnMouseHover(UINT nFlags, CPoint point);    
  46.     afx_msg void OnMouseLeave();    
  47.     afx_msg void OnLButtonDown(UINT nFlags, CPoint point);    
  48.     afx_msg void OnLButtonUp(UINT nFlags, CPoint point);    
  49.     afx_msg BOOL OnEraseBkgnd(CDC* pDC);    
  50.     afx_msg void OnPaint();    
  51.     afx_msg void OnSize(UINT nType, int cx, int cy);  
  52.     afx_msg LRESULT OnBtnClose(WPARAM wParam, LPARAM lParam);  
  53.     virtual BOOL PreTranslateMessage(MSG* pMsg);  
  54. public:  
  55.     void SetTabState(TabState state){m_tabState = state; Invalidate();} //设置tab状态  
  56.     TabState GetTabState(){return m_tabState;}  
  57.     void SetToolTipText(CString spText, BOOL bActivate = TRUE);  
  58.     void SetTabIndex(int idx){m_nIndex = idx;}  
  59.     int GetTabIndex(){return m_nIndex;}  
  60. private:  
  61.     DWORD GetComfortSize(HDC hdc, DWORD dwWidth, CString &strText);  
  62. private:  
  63.     TabState m_tabState;                            //tab的状态  
  64.     CLhsButton m_btnClose;                          //关闭按钮  
  65.     CToolTipCtrl*   m_pToolTip;  
  66.     CString m_tooltext;  
  67.     bool m_bCenterAlign;                            //是否居中对齐  
  68.     int m_nIndex;                                   //tab按钮的索引  
  69.   
  70. public:  
  71.     afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);  
  72. };  
[cpp] view plain copy
 
 在CODE上查看代码片派生到我的代码片
  1. // MyTabControl.cpp : 实现文件  
  2. //  
  3.   
  4. #include "stdafx.h"  
  5. #include "../Lander_mini.h"  
  6. #include "MyTabControl.h"  
  7. #include "memdc.h"  
  8. #include "../Utility.h"  
  9. // MyTabControl  
  10.   
  11. IMPLEMENT_DYNAMIC(MyTabControl, CWnd)  
  12.   
  13. MyTabControl::MyTabControl()  
  14. {  
  15.     m_isMouseHover = false;    
  16.     m_isMouseClicked = false;    
  17.     // 注册控件类    
  18.     szClassName = AfxRegisterWndClass(0);   
  19.     m_pImgNor = NULL;  
  20.     m_pImgHot = NULL;  
  21.     m_pImgDown = NULL;  
  22.     m_tabState = TAB_STATE_NOR;  
  23.     m_pToolTip = NULL;  
  24.     m_bCenterAlign = false;  
  25.     m_nIndex = 0;  
  26. }  
  27.   
  28. MyTabControl::~MyTabControl()  
  29. {  
  30.     SAFE_RELEASE(m_pToolTip);  
  31.     SAFE_RELEASE(m_pImgNor);  
  32.     SAFE_RELEASE(m_pImgHot);  
  33.     SAFE_RELEASE(m_pImgDown);  
  34. }  
  35.   
  36.   
  37. BEGIN_MESSAGE_MAP(MyTabControl, CWnd)  
  38.     ON_WM_MOUSEMOVE()    
  39.     ON_WM_MOUSEHOVER()  // 此消息系统并不会给我们发送    
  40.     ON_WM_MOUSELEAVE()    
  41.     ON_WM_LBUTTONDOWN()    
  42.     ON_WM_LBUTTONUP()    
  43.     ON_WM_PAINT()    
  44.     ON_WM_SIZE()  
  45.     ON_WM_ERASEBKGND()    
  46.     ON_WM_CREATE()  
  47.     ON_MESSAGE(MYWM_BTN_CLICK, &MyTabControl::OnBtnClose)  
  48.     ON_WM_CTLCOLOR()  
  49. END_MESSAGE_MAP()  
  50.   
  51. // MyTabControl 消息处理程序  
  52. bool MyTabControl::Create(CWnd* pParent,CRect rc,CString text,DWORD id /* = 0 */,DWORD style /* = WS_VISIBLE|WS_CHILD */)    
  53. {    
  54.     // 动态创建控件     
  55.     BOOL ret = CWnd::CreateEx(0, szClassName, text, style, rc, pParent, id);  
  56.     return ret ? true : false;    
  57. }    
  58.   
  59. int MyTabControl::OnCreate(LPCREATESTRUCT lpCreateStruct)  
  60. {  
  61.       
  62.     //::SetWindowLong(m_hWnd, GWL_EXSTYLE, GetWindowLong(m_hWnd, GWL_EXSTYLE) ^ WS_EX_LAYERED);  
  63.     m_pImgNor = CQYUtility::LoadImgFromRes(_T("PNG"), IDB_PNG_TAB_NOR);  
  64.     m_pImgHot = CQYUtility::LoadImgFromRes(_T("PNG"), IDB_PNG_TAB_HOT);  
  65.     m_pImgDown = CQYUtility::LoadImgFromRes(_T("PNG"), IDB_PNG_TAB_DOWN);  
  66.       
  67.     RECT rc = {0, 0, 20, 20};  
  68.     m_btnClose.LoadBtnImg(_T("PNG"),IDB_PNG_TAB_CLOSE_NOR, IDB_PNG_TAB_CLOSE_HOT,IDB_PNG_TAB_CLOSE_HOT);  
  69.     m_btnClose.Create(this, rc, L"",ID_BTN_MYTAB_CLOSE);          
  70.     m_btnClose.SetToolTipText(_T("关闭"));          
  71.     EnableToolTips(TRUE);  
  72.     return 0;  
  73. }  
  74.   
  75. void MyTabControl::PostClickEvent()    
  76. {    
  77.     if (m_tabState == TAB_STATE_DOWN)  
  78.         return;     //选中的tab不响应单击了  
  79.     // 该函数用来向父窗口发送 单击 消息    
  80.     CWnd* parent = GetParent();    
  81.     if(parent)    
  82.         parent->SendMessage(MYWM_BTN_TAB_CLICK,m_nIndex,0);        
  83. }    
  84.   
  85. void MyTabControl::OnMouseHover(UINT nFlags, CPoint point)    
  86. {    
  87.     // 鼠标进入    
  88.     Invalidate();    
  89. }    
  90.   
  91. void MyTabControl::OnMouseMove(UINT nFlags, CPoint point)  
  92. {  
  93.     // 只处理鼠标第一次进入时的情况    
  94.     if(!m_isMouseHover)    
  95.     {    
  96.         m_isMouseHover = true;    
  97.   
  98.         TRACKMOUSEEVENT evt = { sizeof(evt), TME_LEAVE|TME_HOVER, m_hWnd, 0 };    
  99.         TrackMouseEvent(&evt);    
  100.   
  101.         OnMouseHover(0,CPoint());    
  102.     }    
  103. }  
  104.   
  105. void MyTabControl::OnMouseLeave()    
  106. {    
  107.     // 鼠标离开    
  108.     m_isMouseHover = false;    
  109.     m_isMouseClicked = false;    
  110.     Invalidate();    
  111. }    
  112.   
  113. void MyTabControl::OnLButtonDown(UINT nFlags, CPoint point)    
  114. {    
  115.     // 鼠标按下    
  116.     m_isMouseClicked = true;    
  117.     Invalidate();    
  118. }    
  119.   
  120. void MyTabControl::OnLButtonUp(UINT nFlags, CPoint point)    
  121. {    
  122.     // 鼠标松开    
  123.     if(m_isMouseClicked)    
  124.     {    
  125.         m_isMouseClicked = false;    
  126.         Invalidate();   
  127.         PostClickEvent();    
  128.     }    
  129. }    
  130.   
  131. BOOL MyTabControl::OnEraseBkgnd(CDC* pDC)    
  132. {    
  133. //  return CWnd::OnEraseBkgnd(pDC);  
  134.     return TRUE;    // 阻止擦除背景,防止闪烁    
  135. }    
  136.   
  137. void MyTabControl::OnPaint()    
  138. {    
  139.     CPaintDC dc(this);     
  140.     CRect rc;    
  141.     GetClientRect(&rc);   
  142.       
  143.     // 采用双缓存,防止闪烁    
  144.     CMemDC memdc(&dc,&rc,TRUE);  
  145.     Graphics graphic(memdc);  
  146.     if (!m_pImgNor || !m_pImgHot || !m_pImgDown)  
  147.     {//没有提供按钮图片就刷下背景  
  148.         // 刷背景    
  149.         COLORREF bkgnd = RGB(100,0,0);    
  150.         if(m_isMouseHover)    
  151.         {    
  152.             if(m_isMouseClicked)    
  153.                 bkgnd = RGB(250,0,0);    
  154.             else    
  155.                 bkgnd = RGB(180,0,0);    
  156.         }    
  157.         memdc.FillSolidRect(&rc,bkgnd);    
  158.     }  
  159.       
  160.     if (m_isMouseClicked || m_tabState == TAB_STATE_DOWN)  
  161.     {//单击一定画单击状态  
  162.         graphic.DrawImage(m_pImgDown, 0, 0, m_pImgDown->GetWidth(), m_pImgDown->GetHeight());  
  163.     }  
  164.     else if (m_isMouseHover && !m_isMouseClicked)  
  165.     {  
  166.         //悬浮,但是没单击  
  167.         graphic.DrawImage(m_pImgHot, 0, 0, m_pImgHot->GetWidth(), m_pImgHot->GetHeight());          
  168.     }  
  169.     else  
  170.     {  
  171.         graphic.DrawImage(m_pImgNor, 0, 0, m_pImgNor->GetWidth(), m_pImgNor->GetHeight());      
  172.     }  
  173.   
  174.     if (!m_strTabText.IsEmpty())  
  175.     {  
  176.         // 设置文字字体    
  177.         CFont font;    
  178.         font.CreatePointFont(100,L"宋体"); // 11号字体,该参数与实际字体号有10倍的关系    
  179.         CFont* poldFont = memdc.SelectObject(&font);    
  180.         // 设置文字属性    
  181.         memdc.SetBkMode(TRANSPARENT);    
  182.         if (m_tabState == TAB_STATE_DOWN)  
  183.             memdc.SetTextColor(RGB(136,76,25));    
  184.         else  
  185.             memdc.SetTextColor(RGB(255,245,190));    
  186.         // 绘制文本    
  187.         DWORD style = DT_SINGLELINE | DT_VCENTER ;   // 文本格式:单行+水平居中+垂直居中    
  188.         //if (m_bCenterAlign)  
  189.         //  style |= DT_CENTER;  
  190.         CRect fontRect(rc);  
  191.         fontRect.left += 13;  
  192.         fontRect.right -= 22;  
  193.         memdc.DrawText(m_strTabText, -1, &fontRect, style);    // 更多文本显示格式可参考百度百科DrawText说明   
  194.         memdc->SelectObject(poldFont);         
  195.     }  
  196.       
  197.     // 使绘制生效    
  198.     graphic.ReleaseHDC(memdc);            
  199. }    
  200.   
  201.   
  202. BOOL MyTabControl::PreTranslateMessage(MSG* pMsg)   
  203. {  
  204.     if (m_pToolTip)  
  205.     {  
  206.         if (::IsWindow(m_pToolTip->m_hWnd))  
  207.         {  
  208.             m_pToolTip->RelayEvent(pMsg);          
  209.         }  
  210.     }  
  211.   
  212.     return CWnd::PreTranslateMessage(pMsg);  
  213. }  
  214.   
  215.   
  216. void MyTabControl::OnSize(UINT nType, int cx, int cy)   
  217. {  
  218.     CRect rect;  
  219.     GetClientRect(&rect);     
  220.     m_btnClose.SetWindowPos(NULL, rect.right - 22, rect.top + 2, 20, 20, SWP_NOZORDER);  
  221. }  
  222.   
  223. LRESULT MyTabControl::OnBtnClose(WPARAM wParam, LPARAM lParam)  
  224. {  
  225.     // 该函数用来向父窗口发送 单击 消息    
  226.     CWnd* parent = GetParent();    
  227.     if(parent != NULL)    
  228.     {    
  229.         parent->SendMessage(MYWM_BTN_TAB_CLOSE, m_nIndex, 0);  
  230.     }    
  231.     return 0;  
  232. }  
  233.   
  234. void MyTabControl::SetToolTipText(CString spText, BOOL bActivate)  
  235. {  
  236.     if (m_pToolTip == NULL)  
  237.     {  
  238.         m_pToolTip = new CToolTipCtrl;  
  239.         // Create ToolTip control  
  240.         m_pToolTip->Create(this);  
  241.         m_pToolTip->Activate(TRUE);  
  242.     }  
  243.   
  244.     m_tooltext = spText;  
  245.   
  246.     // If there is no tooltip defined then add it  
  247.     if (m_pToolTip->GetToolCount() == 0)  
  248.     {  
  249.         CRect rectBtn;   
  250.         GetClientRect(rectBtn);  
  251.         m_pToolTip->AddTool(this, m_tooltext, rectBtn, 1);  
  252.     }  
  253.   
  254.     // Set text for tooltip  
  255.     m_pToolTip->UpdateTipText(m_tooltext, this, 1);  
  256.     m_pToolTip->SetDelayTime(2000);  
  257.     m_pToolTip->Activate(bActivate);  
  258. }  
  259.   
  260.   
  261. DWORD MyTabControl::GetComfortSize(HDC hdc,DWORD dwWidth,CString &strText)  
  262. {  
  263.     //二分法查找  
  264.     DWORD dwComfortSize = 0;  
  265.     DWORD dwBeginSize = 0;  
  266.     DWORD dwEndSize = strText.GetLength();  
  267.   
  268.     while(TRUE)  
  269.     {  
  270.         DWORD dwMiddleSize = (dwEndSize + dwBeginSize) / 2;  
  271.         if(dwMiddleSize == dwBeginSize || dwMiddleSize == dwEndSize)  
  272.         {  
  273.             //两个点之间已经没有数值可以检测,退出循环  
  274.             dwComfortSize = dwBeginSize;  
  275.             break;  
  276.         }  
  277.   
  278.         SIZE sizeChk = {0};  
  279.         ::GetTextExtentPoint(hdc, strText.GetBuffer(), dwMiddleSize, &sizeChk);  
  280.   
  281.         if(sizeChk.cx == dwWidth)  
  282.         {  
  283.             //数值刚好合适,跳出循环  
  284.             dwComfortSize = dwMiddleSize;  
  285.             break;  
  286.         }  
  287.         else if(static_cast<DWORD>(sizeChk.cx) > dwWidth)  
  288.         {  
  289.             //重新设置边界  
  290.             dwEndSize = dwMiddleSize;  
  291.         }  
  292.         else  
  293.         {  
  294.             //重新设置边界  
  295.             dwBeginSize = dwMiddleSize;  
  296.         }  
  297.   
  298.     }  
  299.   
  300.     return dwComfortSize;  
  301. }  
  302.   
  303. void MyTabControl::SetShowText(CString strShowText)  
  304. {  
  305.     m_strShowText = strShowText;  
  306.   
  307.     CRect rect;  
  308.     GetClientRect(&rect);  
  309.     SIZE sizeEllipsis = {0};  
  310.     ::GetTextExtentPoint(GetDC()->GetSafeHdc(), strShowText.GetBuffer(), lstrlen(strShowText.GetBuffer()), &sizeEllipsis);  
  311.     if (sizeEllipsis.cx  < rect.Width() - 40)  
  312.     {//显示区域够宽  
  313.         m_bCenterAlign = true;  
  314.         m_strTabText = strShowText;  
  315.         return;  
  316.     }  
  317.     memset(&sizeEllipsis,0, sizeof(sizeEllipsis));  
  318.     CString ellipsStr = _T("...");  
  319.     ::GetTextExtentPoint(GetDC()->GetSafeHdc(), ellipsStr.GetBuffer(), lstrlen(ellipsStr.GetBuffer()), &sizeEllipsis);  
  320.     DWORD dwMaxDisp = GetComfortSize(GetDC()->GetSafeHdc(), rect.Width() - sizeEllipsis.cx - 20, strShowText);  
  321.     if (dwMaxDisp >= strShowText.GetLength())  
  322.     {  
  323.         m_strTabText = strShowText;  
  324.     }  
  325.     else  
  326.     {  
  327.         m_strTabText = m_strShowText.Left(dwMaxDisp);  
  328.         m_strTabText += ellipsStr;        
  329.     }     
  330.   
  331. }  
  332.   
  333.   
  334.   
  335. HBRUSH MyTabControl::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)  
  336. {  
  337.     HBRUSH hbr = CWnd::OnCtlColor(pDC, pWnd, nCtlColor);  
  338.   
  339.     // TODO:  在此更改 DC 的任何属性  
  340. //  m_btnClose.SetBkGnd(pDC);  
  341.     // TODO:  如果默认的不是所需画笔,则返回另一个画笔  
  342.     return hbr;  
  343. }  


//内存DC类和按钮类见链接:点击打开链接

http://blog.csdn.net/huasonl88/article/details/43227291

原文地址:https://www.cnblogs.com/findumars/p/5625143.html