天天看点

WTL 自绘控件库 (CQSListView)

概述:

代码实现如下:

#pragma once
#pragma warning(disable : 4995)

#include "QsInclude.h"
/
#define QS_LVS_SINGLINE             0x00000001          //ITEM显示单行
#define QS_LVS_MULLINES             0x00000002          //ITEM显示多行
#define QS_LVS_HORIZONTAL           0X00000010          //显示自绘横线
#define QS_LVS_VERTICAL             0X00000100          //显示自绘竖线
#define QS_LVS_IMAGE                0X00001000          //显示自绘图片 图片大小16X16
#define QS_LVS_COLLAPSE             0X00010000          //是否可以折叠

enum enImage
{
    IMAGE_ROOT = 0,
    IMAGE_CHILD,
};

#define  OFFSET_LEFTTREE    18          //为绘制+-号而设置的偏移量
#define  IMAGE_SIZE  16                     //图片的大小为16X16
#define  OFFSET_ROUNDRECT 3          //实现圆角选中

class CQSListView : public CWindowImpl< CQSListView, CListViewCtrl >,
    public CCustomDraw< CQSListView >
{
    typedef CWindowImpl<CQSListView, CListViewCtrl > theClass;

private:
    int m_nItemHeight;          //ITEM 的高度
    int m_nColumnWidth;       //ITEM  的宽度
    int m_nLineNum;               //Item行数
    Color    m_ItemSelCol;        //ITEM选 中的颜色
    Color    m_ItemCol;            //Item 项未选中的颜色
    Color    m_lineCol;              //Item线的颜色
    Color    m_ItemSelTxtCol;   //选中后字体的颜色
    Color    m_ItemTxtCol;       // 未选中字体的颜色 
    DWORD m_QsStyle;           //QS的自绘的属性
    int        m_nWidthEx;         //扩展宽度
    DWORD dwAddStyle;
    CFont   font;
    //子列所处于的行号
    typedef struct _SUBITEMLINE
    {
        int nCol;
        int nLinePos;
        int nFormat;
    }SUBITEMLINE;
    std::vector<Image*> m_vtImage;             // 选中和没选中的图标 目前只会在子结点会显示

public:
    std::vector< SUBITEMLINE > m_vtSubItem;    // ITEM行号
    std::vector< float > m_SubItemWidth;           //用来保存各个Item占整个区域的百分比
    ///
    COLORREF m_rgbSelectOuter;
    COLORREF m_rgbSelectInner;
    COLORREF m_rgbSelectTop;
    COLORREF m_rgbSelectBottom;
    COLORREF m_rgbNoFocusTop;
    COLORREF m_rgbNoFocusBottom;
    COLORREF m_rgbNoFocusOuter;
    COLORREF m_rgbNoFocusInner;
    COLORREF m_rgbBackground;
    //
public:
    BEGIN_MSG_MAP(CQSListView)
        CHAIN_MSG_MAP_ALT( CCustomDraw< CQSListView >, 1 )
        MESSAGE_HANDLER( WM_ERASEBKGND, OnEraseBkgnd )
        MESSAGE_HANDLER(WM_DROPFILES, OnDropFiles)
        MESSAGE_HANDLER( OCM_MEASUREITEM, OnMeasureItem )
        REFLECTED_NOTIFY_CODE_HANDLER( LVN_ENDSCROLL, OnEndScroll );
        //CHAIN_MSG_MAP( theClass )
        DEFAULT_REFLECTION_HANDLER()
    END_MSG_MAP()

    /**
    *@method   CQSListView
    *@brief    CQSListView类构造函数
    *    
    *@return   
    */
    CQSListView():
        m_nItemHeight( 50 ), m_nLineNum( 1 )
    {
        m_ItemSelCol = Color( 255, 255, 255); //刷成白色
        m_lineCol = Color( 206, 210, 214 );
        m_ItemSelTxtCol = Color(0,0,0);
        m_ItemTxtCol = Color(0,0,0);
        m_ItemCol = Color(255,255,255);
        m_QsStyle = QS_LVS_SINGLINE;
        dwAddStyle = LVS_OWNERDRAWFIXED;
        m_nColumnWidth =0;
        m_nWidthEx = 0;
        m_vtSubItem.clear();
        m_SubItemWidth.clear();
        SetQSFont(_T("宋体"),14,FW_NORMAL,DEFAULT_CHARSET);               //设置默认字体
        dwAddStyle =0;
        ::DragAcceptFiles(m_hWnd,TRUE);
         InitSelBackColor();
         m_vtImage.resize(IMAGE_CHILD+1, 0);
    }

    void  InitSelBackColor()
    {
        m_rgbBackground = GetSysColor( COLOR_WINDOW );
        m_rgbSelectOuter = RGB( 170, 200, 245 );
        m_rgbSelectInner = RGB( 230, 250, 250 );
        m_rgbSelectTop = RGB( 210, 240, 250 );
        m_rgbSelectBottom = RGB( 185, 215, 250 );
        m_rgbNoFocusTop = RGB( 250, 250, 250 );
        m_rgbNoFocusBottom = RGB( 235, 235, 235 );
        m_rgbNoFocusOuter = RGB( 220, 220, 220 );
        m_rgbNoFocusInner = RGB( 245, 245, 245 );
    }

    /**
    *@method   ~CQSListView
    *@brief    CQSListView析构造函数
    *    
    *@return   
    */
    virtual ~CQSListView()
    {
        FreeMemoy();
    }

private:
    
    /**
    *@method   DeleteQSFont
    *@brief    删除创建多余的字体
    *    
    *@return   void
    */
    void DeleteQSFont()
    {
        if (NULL != font.m_hFont)
        {
            DeleteObject(&font);
        }
    }
public:

    /**
    *@method   FreeMemoy
    *@brief    删除所有的Image对象
    *    
    *@return   void
    */
    void FreeMemoy()
    {
        DeleteQSFont();
        for(UINT i =0;i<m_vtImage.size();i++) //删除所有的Image对象
        {
            Image * pImage = (Image*)m_vtImage[i];
            if(pImage !=NULL)
            {
                delete  pImage;
                pImage = NULL;
            }
        }
    }
    
    /**
    *@method   SetItemHeight
    *@brief    设置ITEM的高度 ,这个只对设置属性为LVS_OWNERDRAWFIXED才有用
    *    
    *@param    int nItemHeight
    *@return   void
    */
    void SetItemHeight(int nItemHeight)
    {
        m_nItemHeight = nItemHeight;
    }
    
    /**
    *@method   SetItemSelCol
    *@brief    设置选中背景颜色
    *    
    *@param    Color ItemSelCol
    *@return   void
    */
    void SetItemSelCol(Color ItemSelCol)
    {
        m_ItemSelCol= ItemSelCol;
    }

    /**
    *@method   SetItemSelTxtCol
    *@brief    设置选中时字体的颜色
    *    
    *@param    Color temSelTxtCol
    *@return   void
    */
    void SetItemSelTxtCol(Color temSelTxtCol )
    {
        m_ItemSelTxtCol =  temSelTxtCol;
    }
    
    /**
    *@method   SetItemTxtCol
    *@brief    设置字体的颜色
    *    
    *@param    Color ItemTxtCol
    *@return   void
    */
    void SetItemTxtCol(Color ItemTxtCol)
    {
        m_ItemTxtCol = ItemTxtCol;
    }

    /**
    *@method   SetlineCol
    *@brief    设置自绘时的线条的颜色
    *    
    *@param    Color lineCol 自绘时的线条的颜色
    *@return   void
    */
    void SetlineCol(Color lineCol)
    {
        m_lineCol= lineCol;
    }
public:

    /**
    *@method   AddImage
    *@brief    设置图标
    *    
    *@param    Image* pImage
    *@param    enImage enImag
    *@return   void
    */
    void AddImage(Image* pImage, enImage enImag)
    {
        if(pImage!=NULL)
        {
            m_vtImage[enImag] = pImage->Clone();
        }
    }
    
    /**
    *@method   SetQSWindowsStyle
    *@brief    设置自绘时的窗口的属性
    *    
    *@param    DWORD QsStyle
    *@return   void
    */
    void SetQSWindowsStyle(DWORD QsStyle)
    {
        m_QsStyle = QsStyle;
    }
    
    /**
    *@method   SubclassWindow
    *@brief    类对象关联
    *    
    *@param    HWND hWnd
    *@param    int nLineNum = 1
    *@param    int nItemHeight = 20 
    *@return   BOOL
    */
    BOOL SubclassWindow( HWND hWnd, int nLineNum = 1, int nItemHeight = 20 )
    {
        m_nLineNum = nLineNum;
        m_nItemHeight = nItemHeight;

        BOOL bRet = CWindowImpl< CQSListView, CListViewCtrl >::SubclassWindow( hWnd );
        // ModifyStyle( 0, dwAddStyle );
        return bRet;
    }
    
    /**
    *@method   SetLineAndHeight
    *@brief    设置每行的行数和每一行的高度
    *    
    *@param    int nLineNum = 1
    *@param    int nItemHeight = 20
    *@return   void
    */
    void SetLineAndHeight(int nLineNum = 1, int nItemHeight = 20)
    {
        m_vtSubItem.clear();
        m_SubItemWidth.clear();
        m_nLineNum = nLineNum;
        m_nItemHeight = nItemHeight;
    }

    /**
    *@method   Create
    *@brief    
    *    
    *@param    HWND hWndParent
    *@param    ATL::_U_RECT rect = NULL
    *@param    LPCTSTR szWindowName = NULL
    *@param    DWORD dwStyle = 0
    *@param    DWORD dwExStyle = 0
    *@param    ATL::_U_MENUorID MenuOrID = 0U
    *@param    LPVOID lpCreateParam = NULL
    *@return   HWND
    */
    HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
        DWORD dwStyle = 0, DWORD dwExStyle = 0, 
        ATL::_U_MENUorID MenuOrID = 0U, LPVOID lpCreateParam = NULL)
    {       
        return theClass::Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, MenuOrID, lpCreateParam);
    }

    /**
    *@method   OnEraseBkgnd
    *@brief    控件背景绘制消息
    *    
    *@param    UINT uMsg
    *@param    WPARAM wParam
    *@param    LPARAM lParam
    *@param    BOOL& bHandled
    *@return   LRESULT
    */
    LRESULT OnEraseBkgnd( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
    {
        if(!(dwAddStyle&LVS_OWNERDRAWFIXED))
        {
            return DefWindowProc(uMsg, wParam, lParam);
        }
        else
        {
            return TRUE;
        }
    }

    /**
    *@method   SetListViewCtrlStyle
    *@brief    设置ListviewCtrlStyle的基本属性
    *    
    *@param    DWORD dwRemove
    *@param    DWORD dwAdd = LVS_REPORT|LVS_OWNERDRAWFIXED | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS
    *@return   void
    */
    void SetListViewCtrlStyle(DWORD dwRemove, DWORD dwAdd= LVS_REPORT|LVS_OWNERDRAWFIXED | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS)
    {
        dwAddStyle = dwAdd;
         ModifyStyle( dwRemove, dwAddStyle );
    }

    /**
    *@method   SetListViewCtrlStyleEx
    *@brief    设置CQSListView的扩展属性
    *    
    *@param    DWORD dwAdd =LVS_EX_GRIDLINES | LVS_EX_UNDERLINEHOT | LVS_EX_FULLROWSELECT 
    *@return   void
    */
    void SetListViewCtrlStyleEx(DWORD dwAdd =LVS_EX_GRIDLINES | LVS_EX_UNDERLINEHOT | LVS_EX_FULLROWSELECT  )
    {
        ListView_SetExtendedListViewStyle(m_hWnd, dwAdd);

    }
    
protected:
    /*****************************************************
    函数名:    OnEraseBkgnd
    函数描述:   重画控件背景函数(虚函数)
    入参:     IN Graphics graph 用于作图的对象
    IN int cx 宽度
    IN int cy 高度
    出参:     NA
    返回值:    详见MSDN
    其他说明:   详见MSDN
    ******************************************************/
    //virtual void OnEraseBkgnd( HDC hDC, int /*cx*/, int /*cy*/ )
    //{
    //  //获得控件背景
    //  ::SendMessage( GetParent(), WM_DRAWBKGNDUI, ( WPARAM )hDC, ( LPARAM )m_hWnd );
    //}
public:
    
    /**
    *@method   OnDropFiles
    *@brief    列表窗口鼠标左键被按下消息响应函数
    *    
    *@param    UINT uMsg
    *@param    WPARAM wParam
    *@param    LPARAM lParam
    *@param    BOOL& bHandled
    *@return   LRESULT
    */
    LRESULT  OnDropFiles(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
    {
        ::SendMessage(GetParent(),uMsg,wParam,lParam);

        return TRUE;
    }

    /**
    *@method   InsertColumn
    *@brief    插入新列
    *    
    *@param    int nCol
    *@param    const LVCOLUMN* pColumn
    *@param    float fwith
    *@param    int nLinePos = 0
    *@return   int
    */
    int InsertColumn(int nCol, const LVCOLUMN* pColumn,float fwith, int nLinePos = 0)
    {
        SetSubItemLine(nCol,nLinePos,fwith,pColumn->fmt);
        int wth = pColumn->cx;
        if( nLinePos > 0 )
        {
            wth = 0;
        }
        return CWindowImpl< CQSListView, CListViewCtrl >::InsertColumn( nCol, pColumn );
    }

    /**
    *@method   SetSubItemLine
    *@brief    设置多行还是单行
    *    
    *@param    int& nCol
    *@param    int& nLinePos
    *@param    float fwith
    *@param    int nFormat
    *@return   void
    */
    void SetSubItemLine(int& nCol,int& nLinePos,float fwith,int nFormat)
    {
        SUBITEMLINE sil;
        if((m_QsStyle&QS_LVS_SINGLINE))  //单行还是多行只能有一种
        {
            sil.nCol = nCol;
            sil.nLinePos = 0;
            sil.nFormat = nFormat;
            nLinePos = 0;
        }
        else if((m_QsStyle&QS_LVS_MULLINES))
        {
            sil.nCol = nCol;
            sil.nLinePos = nLinePos;
            sil.nFormat = nFormat;
        }
        m_vtSubItem.push_back( sil );
        m_SubItemWidth.push_back(fwith);
    }

    /**
    *@method   InsertColumn
    *@brief    插入新列
    *    
    *@param    int nCol
    *@param    LPCTSTR lpszColumnHeading
    *@param    int nFormat 
    *@param    float fwith
    *@param    int nLinePos = 0
    *@param    int nWidth = -1
    *@param    int nSubItem = -1
    *@param    int iImage = -1
    *@param    int iOrder = -1
    *@return   int
    */
    int InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat ,float fwith,int nLinePos = 0,
        int nWidth = -1, int nSubItem = -1, int iImage = -1, int iOrder = -1)
    {
        SetSubItemLine(nCol,nLinePos,fwith,nFormat);
        int wth = nWidth;
        if( nLinePos > 0 )
        {
            wth = 0;
        }
        return CWindowImpl< CQSListView, CListViewCtrl >::InsertColumn( nCol, lpszColumnHeading,
            nFormat, wth, nSubItem, iImage, iOrder );
    }

    /**
    *@method   InsertItem
    *@brief    插入新的行
    *    
    *@param    UINT nMask
    *@param    int nItem
    *@param    LPCTSTR lpszItem
    *@param    UINT nState
    *@param    UINT nStateMask
    *@param    int nImage
    *@param    LPARAM lParam
    *@return   int
    */
    int InsertItem(UINT nMask, int nItem, LPCTSTR lpszItem, UINT nState, UINT nStateMask, int nImage, LPARAM lParam)
    {
        ATLASSERT(::IsWindow(m_hWnd));
        LVITEM item = { 0 };
        item.mask = nMask;
        item.iItem = nItem;
        item.iSubItem = 0;
        item.pszText = (LPTSTR)lpszItem;
        item.state = nState;
        item.stateMask = nStateMask;
        item.iImage = nImage;
        item.lParam = lParam;
        return InsertItem(&item);
    }

    /**
    *@method   InsertItem
    *@brief    插入新的行
    *    
    *@param    const LVITEM* pItem
    *@return   int
    */
    int InsertItem(const LVITEM* pItem)
    {
        ATLASSERT(::IsWindow(m_hWnd));
        int nIndex = (int)::SendMessage(m_hWnd, LVM_INSERTITEM, 0, (LPARAM)pItem);

        SetColumnWindth();
        return nIndex;
    }

    /**
    *@method   InsertItem
    *@brief    插入新的ITEM项
    *    
    *@param    int nItem
    *@param    LPCTSTR lpszItem
    *@return   int
    */
    int InsertItem(int nItem, LPCTSTR lpszItem)
    {
        ATLASSERT(::IsWindow(m_hWnd));
        return InsertItem(LVIF_TEXT, nItem, lpszItem, 0, 0, 0, 0);
    }

    /**
    *@method   InsertItem
    *@brief    插入新的ITEM项
    *    
    *@param    int nItem
    *@param    LPCTSTR lpszItem
    *@param    int nImage
    *@return   int
    */
    int InsertItem(int nItem, LPCTSTR lpszItem, int nImage)
    {
        ATLASSERT(::IsWindow(m_hWnd));
        return InsertItem(LVIF_TEXT|LVIF_IMAGE, nItem, lpszItem, 0, 0, nImage, 0);
    }

    /**
    *@method   DeleteAllItems
    *@brief    删除所有ITEMS
    *    
    *@param    void
    *@return   BOOL
    */
    BOOL DeleteAllItems( void )
    {
        BOOL bRet = theClass::DeleteAllItems( );

        SetColumnWindth();
        return bRet;
    }

    /**
    *@method   DeleteItem
    *@brief    删除指定的ITEMS
    *    
    *@param    int nItem
    *@return   BOOL
    */
    BOOL DeleteItem( int nItem )
    {
        BOOL bRet = theClass::DeleteItem( nItem );

        SetColumnWindth();
        return bRet;
    }

    /**
    *@method   OnMeasureItem
    *@brief    控件属性设置消息响应函数
    *    
    *@param    UINT uMsg
    *@param    WPARAM wParam
    *@param    LPARAM lParam
    *@param    BOOL& bHandled
    *@return   LRESULT
    */
    LRESULT OnMeasureItem( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/ )
    {
        _ASSERT( lParam != NULL );
        LPMEASUREITEMSTRUCT lpmis = ( LPMEASUREITEMSTRUCT ) lParam;
        
        lpmis->itemHeight = m_nItemHeight;

        return DefWindowProc( uMsg, wParam, ( LPARAM ) lpmis );
    }

    /**
    *@method   OnEndScroll
    *@brief    滚动条停止
    *    
    *@param    int idCtrl
    *@param    LPNMHDR pnmh
    *@param    BOOL& bHandled
    *@return   LRESULT
    */
    LRESULT OnEndScroll( int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/ )
    {
        Invalidate( TRUE );

        return 0;
    }
private:

    /**
    *@method   SetColumnWindth
    *@brief    设置列的宽度
    *    
    *@return   void
    */
    void SetColumnWindth()
    {   
        RECT rect;
        GetClientRect( &rect ); 
        m_nColumnWidth = rect.right - rect.left; 
        size_t nCount = m_SubItemWidth.size();

        for (UINT i =0;i<nCount;i++)
        {
            SetColumnWidth( i, (int)(m_nColumnWidth/nCount));
        }
    }
public:
    
    /**
    *@method   OnPrePaint
    *@brief    重画Item函数
    *    
    *@param    int idCtrl
    *@param    LPNMCUSTOMDRAW nmcd
    *@return   DWORD
    */
    DWORD OnPrePaint( int /*idCtrl*/, LPNMCUSTOMDRAW nmcd )
    {
        if(!(dwAddStyle&LVS_OWNERDRAWFIXED))  //是否有自绘属性
        {
             return CDRF_DODEFAULT;
        }
        CRect rc;
        GetClientRect( rc );
        WTL::CDCHandle dc( nmcd->hdc );
        HDC hdc = dc.m_hDC;

        //创建一个临时作图对象
        WTL::CDC memDC;
        memDC.CreateCompatibleDC( hdc );
        WTL::CBitmap memBitmap;
        memBitmap.CreateCompatibleBitmap( hdc, rc.Width()-1, rc.Height() );  //减1是为了消除锯齿

        HBITMAP hOldBmp = memDC.SelectBitmap( memBitmap.m_hBitmap );

        //重画Item
        for( int y = 0; y < rc.Height(); y += m_nItemHeight )   //使用双缓存机制
        {
            LVHITTESTINFO lvHitTest;
            lvHitTest.pt.x = 1;
            lvHitTest.pt.y = y+1;
            HitTest( &lvHitTest );

            CRect itemRC(0, y, rc.right, y + m_nItemHeight);
            int iItem = lvHitTest.iItem;
            
            //为需要显示的Item创建一个作图设备
            WTL::CDC itemDC;
            itemDC.CreateCompatibleDC( hdc );
            WTL::CBitmap itemBitmap;
             itemBitmap.CreateCompatibleBitmap( hdc, itemRC.Width(), itemRC.Height() );
    
            HBITMAP hOld = itemDC.SelectBitmap( itemBitmap.m_hBitmap );

           Graphics graph( itemDC.m_hDC );

            //绘制Item背景
            OnDrawItemEraseBkgnd( iItem, graph, itemRC.Width(), itemRC.Height() );

            //绘制Item前景
            OnCustomDrawItem( iItem, graph, itemRC.Width(), itemRC.Height(), TRUE);

            //复制图像
            memDC.BitBlt( itemRC.left, itemRC.top, itemRC.Width(),itemRC.Height(), itemDC.m_hDC, 0, 0, SRCCOPY ); 
            
            itemDC.SelectBitmap( hOld );
            itemBitmap.DeleteObject();
            itemDC.DeleteDC();
        }

        dc.BitBlt( 0, 0, rc.Width(), rc.Height(), memDC.m_hDC, 0, 0, SRCCOPY );

        memDC.SelectBitmap( hOldBmp );
        memBitmap.DeleteObject();
        memDC.DeleteDC();

        return CDRF_DODEFAULT;
    }

    /**
    *@method   GetColLinePos
    *@brief    获得列所处于的行号
    *    
    *@param    int nCol
    *@return   int
    */
    int GetColLinePos( int nCol )
    {
        for( size_t i = 0; i < m_vtSubItem.size(); i++ )
        {
            if( m_vtSubItem[i].nCol == nCol )
            {
                return m_vtSubItem[i].nLinePos;
            }
        }

        return -1;
    }
protected:

    /**
    *@method   QSGetSubItemRect
    *@brief    获得列所占用的位置
    *    
    *@param    int nItem
    *@param    int nSubItem
    *@param    int nFlag
    *@param    LPRECT lpRect
    *@return   BOOL
    */
    BOOL QSGetSubItemRect(int nItem, int nSubItem, int nFlag, LPRECT lpRect)
    {
        if(nItem==-1)
        {
            return TRUE;
        }

        BOOL bRet = CWindowImpl< CQSListView, CListViewCtrl >::
            GetSubItemRect( nItem, nSubItem, nFlag, lpRect );

        if( m_nLineNum <= 1 )
        {
            return bRet;
        }

        CRect rc;
        GetItemRect( nItem, rc, LVIR_BOUNDS );

        //如果有多行,则计算出单位行高
        int nHeigh = rc.Height() / m_nLineNum;

        int nLinePos = GetColLinePos( nSubItem );

        lpRect->top = rc.top + nLinePos * nHeigh;
        lpRect->bottom = lpRect->top + nHeigh;
        //如果不是第一行
        if( nLinePos > 0 )
        {
            lpRect->left = rc.left;
            lpRect->right = rc.right;
        }

        return TRUE;
    }
   
    /**
    *@method   OnCustomDrawItem
    *@brief    重画Item函数(虚函数)
    *    
    *@param    int itemIndex
    *@param    Graphics &graph
    *@param    int cx
    *@param    int cy
    *@param    BOOL bDrawLine = TRUE 
    *@return   void
    */
    void OnCustomDrawItem( int itemIndex, Graphics &graph, int cx, int cy, BOOL bDrawLine = TRUE )
    {
        CRect rc;
        GetItemRect( itemIndex, rc, LVIR_BOUNDS );
        //int iColumn = GetHeader().GetItemCount();
        size_t iColumn = m_vtSubItem.size();
        
        int nwidth  = rc.Width();
        int nAddWidth =0;
        int nLine =0;
        for( UINT i = 0; i < iColumn; i++ )
        {
            CRect labelRect;
            int wth =0;
            QSGetSubItemRect( itemIndex, i, LVIR_LABEL, labelRect );
            if((m_QsStyle&QS_LVS_SINGLINE))  //单行还是多行只能有一种
            {
                 wth = labelRect.Width();
                 labelRect.left -= rc.left;
            }
            if((m_QsStyle&QS_LVS_MULLINES))  //多行只能有一种
            {
                labelRect.left = 0;
                 wth = (int)(m_SubItemWidth[i]*nwidth);
                 if(nLine!=m_vtSubItem[i].nLinePos)
                 {
                     nLine = m_vtSubItem[i].nLinePos;
                     nAddWidth =0;
                 }
                  labelRect.left -= labelRect.left -nAddWidth;
            }

            int heigh = labelRect.Height();
            labelRect.top -= rc.top;
            labelRect.right = labelRect.left + wth;
            labelRect.bottom = labelRect.top + heigh;
            OnCustomDrawSubItem( itemIndex, i, labelRect, graph );
            nAddWidth  = nAddWidth+wth;
        }

        if( bDrawLine )    //绘制横线
        {
            Pen pen(Color(255,200,200));
            pen.SetColor(m_lineCol);
            pen.SetDashStyle( DashStyleSolid );
            if(m_QsStyle&QS_LVS_HORIZONTAL)
            {
                graph.DrawLine( &pen, 0, cy-1, cx, cy-1 );     //横线条
            }
            
            if(m_QsStyle&QS_LVS_VERTICAL)
            {
                size_t iCount = m_SubItemWidth.size();
                int  nAddWidth =0;
                for (size_t i =0;i<iCount-1;i++)                 // 绘制竖线条
                {
                    int nWidth = int (cx*m_SubItemWidth[i]);
                    graph.DrawLine( &pen, nWidth+nAddWidth-2, cy, nWidth+nAddWidth-2, cy-m_nItemHeight);
                    nAddWidth  = nAddWidth+nWidth;
                }
            }
        }
    }

    /**
    *@method   OnDrawItemEraseBkgnd
    *@brief    重画Item背景函数(虚函数)
    *    
    *@param    int itemIndex
    *@param    Graphics &graph
    *@param    int cx
    *@param    int cy
    *@return   void
    */
    void OnDrawItemEraseBkgnd( int itemIndex, Graphics &graph, int cx, int cy )
    {
        SolidBrush sb(Color(255, 255, 255));

        if (-1 == itemIndex)
        {
            sb.SetColor(m_ItemCol);
            graph.FillRectangle( &sb, 0, 0, cx, cy );
        }
        else
        {
            //判断当前记录是否被选中
            const UINT itemState = GetItemState(itemIndex, LVIS_SELECTED);
            if( itemState & LVIS_SELECTED )
            {
                sb.SetColor(m_ItemSelCol);
                graph.FillRectangle( &sb, 0, 0, cx, cy );

                //Pen pen1( Color( 255, 176, 151, 113 ), 1.0 );
                //graph.DrawLine( &pen1, 0, 0, cx, 0 );
                //Pen pen2( Color( 255, 255, 195, 123 ), 1.0 );
                //graph.DrawLine( &pen2, 0, 1, cx, 1 );
                //Pen pen3( Color( 255, 130, 44, 0 ), 1.0 );
                //graph.DrawLine( &pen3, 0, cy, cx, cy ); */ 
                CDCHandle dcPaint( graph.GetHDC() );
                int nContextState = dcPaint.SaveDC();

                dcPaint.SetBkColor( m_rgbBackground );
                BOOL bControlFocus = TRUE;
                CRect rcSelect( 2, 0, cx-2, cy );

                CPen penBorder;
                penBorder.CreatePen( PS_SOLID, 1, bControlFocus ? m_rgbSelectOuter : m_rgbNoFocusOuter );
                CBrush bshInterior;
                bshInterior.CreateSolidBrush( m_rgbBackground );

                dcPaint.SelectPen( penBorder );
                dcPaint.SelectBrush( bshInterior );

                dcPaint.RoundRect( rcSelect, CPoint( 5, 5 ) );
                rcSelect.DeflateRect( 1, 1 );

                CPen penInnerBorder;
                penInnerBorder.CreatePen( PS_SOLID, 1, bControlFocus ? m_rgbSelectInner : m_rgbNoFocusInner );
                dcPaint.SelectPen( penInnerBorder );

                dcPaint.RoundRect( rcSelect, CPoint( 2, 2 ) );
                rcSelect.DeflateRect( 1, 1 );

                GRADIENT_RECT grdRect = { 0, 1 };
                TRIVERTEX triVertext[ 2 ] = {
                    rcSelect.left,
                    rcSelect.top,
                    GetRValue( bControlFocus ? m_rgbSelectTop : m_rgbNoFocusTop ) << 8,
                    GetGValue( bControlFocus ? m_rgbSelectTop : m_rgbNoFocusTop ) << 8,
                    GetBValue( bControlFocus ? m_rgbSelectTop : m_rgbNoFocusTop ) << 8,
                    0x0000,         
                    rcSelect.right,
                    rcSelect.bottom,
                    GetRValue( bControlFocus ? m_rgbSelectBottom : m_rgbNoFocusBottom ) << 8,
                    GetGValue( bControlFocus ? m_rgbSelectBottom : m_rgbNoFocusBottom ) << 8,
                    GetBValue( bControlFocus ? m_rgbSelectBottom : m_rgbNoFocusBottom ) << 8,
                    0x0000
                };

                dcPaint.GradientFill( triVertext, 2, &grdRect, 1, GRADIENT_FILL_RECT_V );
                dcPaint.RestoreDC( nContextState );
                graph.ReleaseHDC(dcPaint);
          }
            else
            {
                sb.SetColor(m_ItemCol);
                graph.FillRectangle( &sb, 0, 0, cx, cy);
            }
        }
    }

public:

    /**
    *@method   SetQSFont
    *@brief    设置文字的大小
    *    
    *@param    TCHAR*fontName
    *@param    int nFontSize
    *@param    int lfWeight = FW_NORMAL
    *@param    BYTE fCharSet = ANSI_CHARSET
    *@return   void
    */
    void SetQSFont(TCHAR*fontName,int nFontSize,int lfWeight = FW_NORMAL,BYTE fCharSet = DEFAULT_CHARSET)
    {
        LOGFONT itemFont;
        itemFont.lfCharSet = fCharSet;
        itemFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
        itemFont.lfEscapement = 0;
        memset(itemFont.lfFaceName, 0, LF_FACESIZE);
        memcpy_s(itemFont.lfFaceName, LF_FACESIZE, fontName, LF_FACESIZE);
        itemFont.lfHeight = nFontSize;
        itemFont.lfItalic = FALSE;
        itemFont.lfOrientation = 0;
        itemFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
        itemFont.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
        itemFont.lfQuality = CLEARTYPE_QUALITY;
        itemFont.lfStrikeOut = FALSE;
        itemFont.lfUnderline = FALSE;
        itemFont.lfWeight = lfWeight;
        itemFont.lfWidth = 0;
        font =  ::CreateFontIndirect( &itemFont );
        if(!(dwAddStyle&LVS_OWNERDRAWFIXED))  //是否有自绘属性
        {
            SetFont(font);
        }
    }
    
    /**
    *@method   GetTextFormat
    *@brief    自绘时有ColumnFormat 来得到字体的绘制的格式不同
    *    
    *@param    int nColumnFormat
    *@param    int& nFormat
    *@return   void
    */
    void GetTextFormat(int nColumnFormat,int& nFormat)
    {
        if( nColumnFormat==LVCFMT_LEFT)
        {
            nFormat = DT_LEFT;
        }
        else if(nColumnFormat ==LVCFMT_RIGHT)
        {
            nFormat = DT_RIGHT;
        }
        else
        {
            nFormat = DT_CENTER;
        }
    }

    /**
    *@method   OnCustomDrawSubItem
    *@brief    重画SubItem函数(虚函数)
    *    
    *@param    int nItem
    *@param    int nSubItem
    *@param    CRect rcSubItem
    *@param    Graphics &graph
    *@return   BOOL
    */
    virtual BOOL OnCustomDrawSubItem( int nItem, int nSubItem, CRect rcSubItem, Graphics &graph )
    {
        if( rcSubItem.Width() <= 0 )
        {
            return TRUE;
        }

        if(m_QsStyle&QS_LVS_IMAGE)
        {
            Image *pImage=NULL;
            if(nSubItem==0)
            {
                    pImage = m_vtImage[IMAGE_ROOT];
                    if(NULL != pImage)
                    {
                        graph.DrawImage(pImage, RectF((float)rcSubItem.left, (float)(m_nItemHeight/2-pImage->GetHeight()/2), (float)pImage->GetWidth(), (float)pImage->GetHeight() ));
                        rcSubItem.left = rcSubItem.left+pImage->GetWidth()+OFFSET_ROUNDRECT;
                    }
            }
            else
            {
                pImage = m_vtImage[IMAGE_ROOT];
                if(NULL != pImage)
                {
                    rcSubItem.left = rcSubItem.left+IMAGE_SIZE+OFFSET_ROUNDRECT; //为了实现圆角。
                    if(m_QsStyle&QS_LVS_SINGLINE)
                    {
                        rcSubItem.left = rcSubItem.left-IMAGE_SIZE; //为了实现圆角。
                    }
                }
            }
        }
        else
        {
            rcSubItem.left = rcSubItem.left+OFFSET_ROUNDRECT;       //为了实现圆角。
        }

        CString text = _T("");
        CDCHandle dc = graph.GetHDC();
        CFont fontOld =  dc.SelectFont(font);
        dc.SetBkMode(TRANSPARENT);

        GetItemText( nItem, nSubItem, text);
        int nFormat = DT_LEFT;
         GetTextFormat(m_vtSubItem[nSubItem].nFormat,nFormat);
        dc.SetTextColor(m_ItemTxtCol.GetValue());
         //rcSubItem.left = rcSubItem.left+3; //为了实现圆角。
        dc.DrawText( text, text.GetLength(), &rcSubItem, 
            DT_SINGLELINE | DT_WORD_ELLIPSIS | DT_PATH_ELLIPSIS | nFormat|DT_END_ELLIPSIS | DT_VCENTER);
        dc.SelectFont(fontOld);

        graph.ReleaseHDC(dc);
         
        return TRUE;
    }
    
};