繪製一個TabCtrl

1.源代碼如下(頭文件)

 

//MKTabCtrl.h

#ifndef ZGTABCTRL_H
#define ZGTABCTRL_H

#
if _MSC_VER > 1000
#pragma once
#endif 
// _MSC_VER > 1000
// MKTabCtrl.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CMKTabCtrl window


class CMKTabCtrl : public CTabCtrl
{
// Construction
public:
    CMKTabCtrl();

// Attributes
public:

// Operations
public:

// Overrides
    
// ClassWizard generated virtual function overrides
    
//{{AFX_VIRTUAL(CMKTabCtrl)
    protected:
    
//}}AFX_VIRTUAL

// Implementation
public:
    virtual 
~CMKTabCtrl();

    
// Generated message map functions
protected:
    BOOL m_bFocus;
    
void DrawTabBorder(CDC *pDC, CRect rcClient, int nSel);
    
void DrawItem(CDC* pDC, CRect rcItem, int nIndex);
    
int GetMovePos();
    
int m_nOverItem;
    
void GetTabRect(CRect &rcTab);
    UINT m_nTimerTrack;
    BOOL m_bTracking;
    CSize GetTextSize(CDC 
*pDC, int nPos);
    CPen m_PenSelect;
    CPen m_PenBorderIn;
    CPen m_PenBorderOut;

    CPen m_PenBorderTab;

    CPen m_PenShade[
2];
    CPen m_PenTabTop[
3];
    
//{{AFX_MSG(CMKTabCtrl)
    afx_msg void OnPaint();
    afx_msg 
void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg 
void OnTimer(UINT nIDEvent);
    afx_msg 
void OnKillFocus(CWnd* pNewWnd);
    afx_msg 
void OnSetFocus(CWnd* pOldWnd);
    afx_msg 
void OnLButtonDown(UINT nFlags, CPoint point);
    
//}}AFX_MSG
    afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);

    DECLARE_MESSAGE_MAP()
}
;

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif 

 2.實現文件CPP

 

// MKTabCtrl.cpp : implementation file
//

#include 
"stdafx.h"
#include 
"MKTabCtrl.h"
#include 
"MKDraw.h"

#ifdef _DEBUG
#define 
new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


/////////////////////////////////////////////////////////////////////////////
// CMKTabCtrl

CMKTabCtrl::CMKTabCtrl()
{
    m_nTimerTrack 
= 0;
    m_bTracking 
= FALSE;
    m_nOverItem 
= -1;
    m_bFocus 
= FALSE;

    m_PenBorderOut.CreatePen(PS_SOLID, 
1, RGB(00255));
    m_PenBorderIn.CreatePen(PS_SOLID, 
1, RGB(00255));
    m_PenSelect.CreatePen(PS_SOLID, 
1, RGB(145155156));

    m_PenShade[
0].CreatePen(PS_SOLID, 1, RGB(208206191));
    m_PenShade[
1].CreatePen(PS_SOLID, 1, RGB(227224208));

    m_PenBorderTab.CreatePen(PS_SOLID, 
1, RGB(145167180));

    m_PenTabTop[
0].CreatePen(PS_SOLID, 1, RGB(23013944));
    m_PenTabTop[
1].CreatePen(PS_SOLID, 1, RGB(25520060));
    m_PenTabTop[
2].CreatePen(PS_SOLID, 1, RGB(25520020));
}


CMKTabCtrl::
~CMKTabCtrl()
{
    m_PenBorderOut.DeleteObject();
    m_PenBorderIn.DeleteObject();
    m_PenSelect.DeleteObject();

    m_PenShade[
0].DeleteObject();
    m_PenShade[
1].DeleteObject();

    m_PenBorderTab.DeleteObject();

    m_PenTabTop[
0].DeleteObject();
    m_PenTabTop[
1].DeleteObject();
    m_PenTabTop[
2].DeleteObject();
    
}



BEGIN_MESSAGE_MAP(CMKTabCtrl, CTabCtrl)
    
//{{AFX_MSG_MAP(CMKTabCtrl)
    ON_WM_PAINT()
    ON_WM_MOUSEMOVE()
    ON_WM_TIMER()
    ON_WM_KILLFOCUS()
    ON_WM_SETFOCUS()
    ON_WM_LBUTTONDOWN()
    
//}}AFX_MSG_MAP
    ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMKTabCtrl message handlers
void CMKTabCtrl::OnPaint() 
{
    CPaintDC dc(
this); // device context for painting

    
// TODO: Add your message handler code here
    CMKClientRect rcClient(this);

    CRect rcShade 
= rcClient;
    
int nSel = GetCurSel();
    CSize sz 
= GetTextSize(&dc, nSel);

    CRect rcItem;
    GetItemRect(nSel, 
&rcItem);

    rcShade.bottom 
= rcItem.Height()/2 ;
    CMKDraw::MKFillGradient(
&dc,rcShade,RGB(255,255,255),RGB(28,93,253)/*RGB(121,184,249)*/,TRUE) ;

    rcShade.top    
= rcShade.bottom ;
    rcShade.bottom 
= rcItem.Height() + 2 ;

    CMKDraw::MKFillGradient(
&dc,rcShade,RGB(28,93,253) , RGB(255,255,255)/*RGB(121,184,249)*/,TRUE) ;

    rcShade.top    
= rcShade.bottom ;
    rcShade.bottom 
= rcClient.bottom ;
    dc.FillSolidRect(
&rcShade , RGB(198,211,247) ) ;

    
//rcClient.DeflateRect(1,1);
    
//rcClient.bottom-=2;
    
//rcClient.right-=2;

    DrawTabBorder(
&dc, rcClient, nSel);
    
    dc.SetBkMode(TRANSPARENT);
    CFont 
*pOldFont = dc.SelectObject(GetFont());

    
for(int i=0; i<GetItemCount(); i++)
    
{
        
        GetItemRect(i, 
&rcItem);
        rcItem.OffsetRect(
01);

        
if (i==nSel)
            rcItem.OffsetRect(
0-1);
        DrawItem(
&dc, rcItem, i);

        
if (i==nSel && m_bFocus)
        
{
            CRect rcFocus 
= rcItem;
            rcFocus.DeflateRect(
1200);
            dc.DrawFocusRect(rcFocus);
        }

    }


    dc.SelectObject(pOldFont);
    
// Do not call CTabCtrl::OnPaint() for painting messages
}


CSize CMKTabCtrl::GetTextSize(CDC 
*pDC, int nPos)
{
    TCHAR szText[MAX_PATH];

    TCITEM tc;
    tc.mask 
= TCIF_TEXT;
    tc.pszText 
= szText;
    tc.cchTextMax 
= sizeof(szText);

    GetItem(nPos, 
&tc);

    
return pDC->GetTextExtent(tc.pszText);
}


void CMKTabCtrl::OnMouseMove(UINT nFlags, CPoint point) 
{
    
// TODO: Add your message handler code here and/or call default
    if (!m_bTracking)
    
{
        
int nCount = GetItemCount();

        
if (nCount<=0)
            
return;

        CRect rcTab;
        GetTabRect(rcTab);

        
if (rcTab.PtInRect(point))
        
{
            TRACKMOUSEEVENT tms;
            tms.cbSize 
= sizeof(TRACKMOUSEEVENT);
            tms.dwFlags 
= TME_LEAVE;;
            tms.dwHoverTime 
= 1;
            tms.hwndTrack 
= m_hWnd;
            m_bTracking 
= ::_TrackMouseEvent(&tms);

            m_nTimerTrack 
= SetTimer(150, NULL);
        }

    }

    CTabCtrl::OnMouseMove(nFlags, point);
}


LRESULT CMKTabCtrl::OnMouseLeave(WPARAM wParam, LPARAM lParam)
{
    CRect rcItem;
    GetItemRect(m_nOverItem, rcItem);
    InvalidateRect(rcItem);

    m_bTracking 
= FALSE;
    m_nOverItem 
= -1;

    KillTimer(m_nTimerTrack);
    m_nTimerTrack 
= 0;

    
return m_bTracking;
}


void CMKTabCtrl::OnTimer(UINT nIDEvent) 
{
    
// TODO: Add your message handler code here and/or call default
    if (m_nTimerTrack == nIDEvent)
    
{
        
int nCurItem = GetMovePos();

        
if (nCurItem != m_nOverItem)
        
{
            CRect rcItem;
            GetItemRect(m_nOverItem, rcItem);
            InvalidateRect(rcItem);
            CRect rcTab;
            m_nOverItem 
= nCurItem;
            GetItemRect(m_nOverItem, rcItem);
            InvalidateRect(rcItem);
        }

    }

    CTabCtrl::OnTimer(nIDEvent);
}


void CMKTabCtrl::GetTabRect(CRect &rcTab)
{
    
int nCount = GetItemCount();

    
if (nCount<=0)
        
return;

    GetClientRect(
&rcTab);

    CRect rcItem;
    GetItemRect(nCount
-1&rcItem);

    rcTab.bottom 
= rcItem.bottom;
    rcTab.right 
= rcItem.right;
}


int CMKTabCtrl::GetMovePos()
{
    CPoint ptCur;
    GetCursorPos(
&ptCur);
    ScreenToClient(
&ptCur);

    
int nCount = GetItemCount();
    CRect rcItem;
    
for(int i=0; i<nCount; i++)
    
{
        GetItemRect(i, 
&rcItem);

        
if (rcItem.PtInRect(ptCur))
            
return i;

    }


    
return -1;
}


void CMKTabCtrl::DrawItem(CDC *pDC, CRect rcItem, int nIndex)
{
    CPen 
*pOldPen = (CPen*)pDC->SelectObject(&m_PenBorderTab);
    
if (nIndex != GetCurSel())
        rcItem.DeflateRect(
1011);
    
else
        rcItem.InflateRect(
1010);

    CRect rcFill 
= rcItem;
    rcFill.DeflateRect(
1110);

    
if (nIndex == GetCurSel())
    
{
        rcFill.bottom 
+= 1;
        pDC
->FillSolidRect(&rcFill,RGB(198,211,247)) ;
    }

    
    CPoint pt[]
={CPoint(rcItem.left, rcItem.bottom), 
                 CPoint(rcItem.left, rcItem.top
+2),
                 CPoint(rcItem.left
+1, rcItem.top+1),
                 CPoint(rcItem.left
+2, rcItem.top),
                 CPoint(rcItem.right
-2, rcItem.top),
                 CPoint(rcItem.right
-1, rcItem.top+1),
                 CPoint(rcItem.right, rcItem.top
+2),
                 CPoint(rcItem.right, rcItem.bottom)}
;

    BYTE bt[]
={PT_MOVETO,
               PT_LINETO,
               PT_LINETO,
               PT_LINETO,
               PT_LINETO,
               PT_LINETO,
               PT_LINETO,
               PT_LINETO}
;

    pDC
->PolyDraw(pt, bt, 8);

    
if ((nIndex == m_nOverItem) || 
        (nIndex 
== GetCurSel()))
    
{
        pDC
->SelectObject(&m_PenTabTop[0]);
        pDC
->MoveTo(rcItem.left+3, rcItem.top);
        pDC
->LineTo(rcItem.right-2, rcItem.top);

        pDC
->SelectObject(&m_PenTabTop[1]);
        pDC
->MoveTo(rcItem.left+2, rcItem.top+1);
        pDC
->LineTo(rcItem.right-1, rcItem.top+1);

        pDC
->SelectObject(&m_PenTabTop[2]);
        pDC
->MoveTo(rcItem.left+1, rcItem.top+2);
        pDC
->LineTo(rcItem.right, rcItem.top+2);
    }


    TCHAR szText[MAX_PATH];
    TCITEM tc;
    tc.mask 
= TCIF_TEXT;
    tc.cchTextMax 
= MAX_PATH;
    tc.pszText 
= szText;
    GetItem(nIndex, 
&tc);

    rcItem.OffsetRect(
01);
    
if (nIndex==m_nOverItem)
        pDC
->SetTextColor(RGB(0,0,255));
    
else
        pDC
->SetTextColor(RGB(0,0,0));
    pDC
->DrawText(szText, rcItem, DT_VCENTER|DT_CENTER|DT_SINGLELINE);

    pDC
->SelectObject(pOldPen);

    

}


void CMKTabCtrl::DrawTabBorder(CDC *pDC, CRect rcClient, int nSel)
{
    CRect rcItem;
    GetItemRect(nSel, rcItem);
    CPen 
*pOldPen = pDC->SelectObject(&m_PenBorderOut);
    pDC
->MoveTo(rcClient.left ,rcClient.top) ;
    pDC
->LineTo(rcClient.left ,rcClient.bottom - 1 ) ;
    pDC
->LineTo(rcClient.right-1,rcClient.bottom - 1 ) ;
    pDC
->LineTo(rcClient.right-1,rcClient.top ) ;
    pDC
->SelectObject(pOldPen) ;
}


void CMKTabCtrl::OnKillFocus(CWnd* pNewWnd) 
{
    CTabCtrl::OnKillFocus(pNewWnd);
    
    
// TODO: Add your message handler code here
    m_bFocus = FALSE;
    CRect rcSel;
    GetItemRect(GetCurSel(), rcSel);

    InvalidateRect(rcSel);
}


void CMKTabCtrl::OnSetFocus(CWnd* pOldWnd) 
{
    CTabCtrl::OnSetFocus(pOldWnd);
    
    
// TODO: Add your message handler code here
    m_bFocus = TRUE;
    CRect rcSel;
    GetItemRect(GetCurSel(), rcSel);

    InvalidateRect(rcSel);
}


void CMKTabCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
    
// TODO: Add your message handler code here and/or call default
    SetFocus();
    CTabCtrl::OnLButtonDown(nFlags, point);
}

 

3.效果

見前一篇文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章