1。要重绘listctrl表头,则listctrl表现选择为report风格
2。其表头(CHeaderCtrl)可以通过GetHeaderCtrl获取
3。继承CHeaderCtrl类,重绘表头。
有两种方式重绘:
a。重载OnPaint方法,事例代码如下:
void CSkinHeaderCtrl::OnPaint()
{
TRACE("CSkinHeaderCtrl::OnPaint()/n");
CPaintDC dc(this); // device context for painting
CRect rect, rectItem, clientRect;
GetClientRect(&rect);
GetClientRect(&clientRect);
CMemDC memDC(&dc, rect);
CDC bitmapDC;
bitmapDC.CreateCompatibleDC(&dc);
memDC.FillSolidRect(&rect, RGB(76,85,118));
CBitmap bitmapSpan;
bitmapSpan.LoadBitmap(IDB_COLUMNHEADER_SPAN);
CBitmap* pOldBitmapSpan = bitmapDC.SelectObject(&bitmapSpan);
memDC.StretchBlt(rect.left+2, 0, rect.Width(), 12, &bitmapDC, 0, 0, 1, 12, SRCCOPY);
bitmapDC.SelectObject(pOldBitmapSpan);
bitmapSpan.DeleteObject();
int nItems = GetItemCount();
CBitmap bitmap;
CBitmap bitmap2;
CBitmap bitmap3;
bitmap.LoadBitmap(IDB_COLUMNHEADER_START);
bitmap2.LoadBitmap(IDB_COLUMNHEADER_SPAN);
bitmap3.LoadBitmap(IDB_COLUMNHEADER_END);
for(int i = 0; i <nItems; i++)
{
TCHAR buf1[256];
HD_ITEM hditem1;
hditem1.mask = HDI_TEXT | HDI_FORMAT | HDI_ORDER;
hditem1.pszText = buf1;
hditem1.cchTextMax = 255;
GetItem( i, &hditem1 );
GetItemRect(i, &rect);
CBitmap* pOldBitmap = NULL;
//make sure we draw the start piece
//on the first item so it has a left border
//For the following items we will just use the
//right border of the previous items as the left
//border
if(hditem1.iOrder==0)
{
pOldBitmap = bitmapDC.SelectObject(&bitmap);
memDC.BitBlt(rect.left,rect.top,2,12,&bitmapDC,0,0,SRCCOPY);
}
else
{
memDC.BitBlt(rect.left-1,rect.top,2,12,&bitmapDC,0,0,SRCCOPY);
pOldBitmap = bitmapDC.SelectObject(&bitmap2);
memDC.BitBlt(rect.left+1,rect.top,1,12,&bitmapDC,0,0,SRCCOPY);
}
bitmapDC.SelectObject(pOldBitmap);
//span the bitmap for the width of the column header item
int nWidth = rect.Width() - 4;
CBitmap* pOldBitmap2 = bitmapDC.SelectObject(&bitmap2);
memDC.StretchBlt(rect.left+2, 0, nWidth, 1, &bitmapDC, 0,0, 1, 12, SRCCOPY);
bitmapDC.SelectObject(pOldBitmap2);
//draw the end piece of the column header
CBitmap* pOldBitmap3 = bitmapDC.SelectObject(&bitmap3);
memDC.BitBlt((rect.right-2), 0, 2, 12, &bitmapDC,0,0,SRCCOPY);
bitmapDC.SelectObject(pOldBitmap3);
//Get all the info for the current
//item so we can draw the text to it
//in the desired font and style
DRAWITEMSTRUCT DrawItemStruct;
GetItemRect(i, &rectItem);
DrawItemStruct.CtlType = 100;
DrawItemStruct.hDC = dc.GetSafeHdc();
DrawItemStruct.itemAction = ODA_DRAWENTIRE;
DrawItemStruct.hwndItem = GetSafeHwnd();
DrawItemStruct.rcItem = rectItem;
DrawItemStruct.itemID = i;
DrawItem(&DrawItemStruct);
UINT uFormat = DT_SINGLELINE | DT_NOPREFIX | DT_TOP |DT_CENTER | DT_END_ELLIPSIS ;
CFont font;
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
lf.lfHeight = 8;
strcpy(lf.lfFaceName, "Sevenet 7");
font.CreateFontIndirect(&lf);
CFont* def_font = memDC.SelectObject(&font);
memDC.SetBkMode(TRANSPARENT);
rectItem.DeflateRect(2,2,2,2);
TCHAR buf[256];
HD_ITEM hditem;
hditem.mask = HDI_TEXT | HDI_FORMAT | HDI_ORDER;
hditem.pszText = buf;
hditem.cchTextMax = 255;
GetItem( DrawItemStruct.itemID, &hditem );
memDC.DrawText(buf, &rectItem, uFormat);
memDC.SelectObject(def_font);
font.DeleteObject();
}
}
b。重载DrawItem方法,事例代码如下:
ASSERT(lpDrawItemStruct-> CtlType == ODT_HEADER);
HDITEM hdi;
TCHAR lpBuffer[256];
hdi.mask = HDI_TEXT;
hdi.pszText = lpBuffer;
hdi.cchTextMax = 256;
GetItem(lpDrawItemStruct-> itemID,&hdi);
CDC* pDC;
pDC = CDC::FromHandle(lpDrawItemStruct-> hDC);
pDC-> SetTextColor(RGB(0,0,0));
pDC-> SetBkColor(RGB(222,213,242));
CBrush brush;
brush.CreateSolidBrush(RGB(222,213,242));
CRect rect = lpDrawItemStruct-> rcItem;
//THIS FONT IS ONLY FOR DRAWING AS LONG AS WE DON'T DO A SetFont(...)
CBrush *pOldBrush=pDC-> SelectObject(&brush);
pDC-> FillRect(&rect,&brush);
pDC-> SelectObject(pOldBrush);
pDC-> SelectObject(GetStockObject(DEFAULT_GUI_FONT));
//DRAW THE TEXT
lpDrawItemStruct-> rcItem.top += 6;
::DrawText(lpDrawItemStruct->hDC,lpBuffer,strlen(lpBuffer), &lpDrawItemStruct->rcItem,DT_VCENTER);
pDC-> SelectStockObject(SYSTEM_FONT);
注:重载DrawItem时,必须要设置CHeaderCtrl为HDF_OWNERDRAW,我设置的方法如下:
调用了InsertColumn之后,用下面的方法设置表头可以自绘。
CHeaderCtrl *pHeader = NULL;
pHeader = m_SkinList.GetHeaderCtrl();
if(pHeader)
{
TRACE("header item count:%d/n", pHeader->GetItemCount());
int iColumn=pHeader->GetItemCount();
for (int i=0; i<iColumn; i++)
{
HDITEM hdItem;
BOOL bResult = FALSE;
bResult=pHeader->GetItem(i, &hdItem);
hdItem.fmt |= HDF_OWNERDRAW;
bResult=pHeader->SetItem(i, &hdItem);
}
}
本来我想在CHeaderCtrl的InsertItem上做文章的,但是无法在其被调用时改变其属性,且用SPY++也抓不到HDM_INSERTITEM消息(奇怪),只能作罢。
4。继承CListCtrl类,并重载
void CSkinListCtrl::PreSubclassWindow()
{
//use our custom CHeaderCtrl as long as there
//is a headerctrl object to subclass
if(GetHeaderCtrl())
{
m_SkinHeaderCtrl.SubclassWindow(GetHeaderCtrl()->m_hWnd);
}
CListCtrl::PreSubclassWindow();
}
这样就可以使用自己的表头了
本来我想在CHeaderCtrl的InsertItem上做文章的,但是无法在其被调用时改变其属性,且用SPY++也抓不到HDM_INSERTITEM消息(奇怪).
ListCtrl默认插入列时,使用的HDM_ITEMINSERTW消息,而你程序可能使用HDM_INSERTITEM做的消息映射,如果以非UNICODE方式编译,则只会捕捉到HDM_INSERTITEMA消息,不会捕捉HDM_INSERTITEMW消息。
所以要2个消息均做映射。
ON_MESSAGE(HDM_INSERTITEMA,OnInsertItem)
ON_MESSAGE(HDM_INSERTITEMW,OnInsertItem)