概述:

CQSListView 基础与 CListViewCtrl,主要实现控件列表的选中颜色和背景颜色,以及选中圆角等一些特性。

代码实现如下:

#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;
}

};