自定义的列表控件必须是自绘制的,因此需要在资源编辑器中设置LVS_OWNERDRAWFIXED标志,而且还必须在自定义的控件类中实现DrawItem函数。
200781701.jpg
代码如下:
class CListCtrlEx : public CListCtrl
{
// Construction
public:
CListCtrlEx();
public:
CPalette m_pal;//调色板
CBitmap m_bitmap;//背景位图
int m_cxBitmap, m_cyBitmap;//背景位图高度,宽度信息
int m_nHighlight;//高亮方式
BOOL SetBkImage(LPCTSTR lpszResourceName);//设置背景图片
BOOL SetBkImage(UINT nIDResource);
int GetColumnCount();//获取列数目
void AdjustColumnWidth();//调整列宽
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CListCtrlEx)
//}}AFX_VIRTUAL
// Implementation
public:
virtual ~CListCtrlEx();
// Generated message map functions
protected:
//{{AFX_MSG(CListCtrlEx)
afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);//水平滚动
afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar);//垂直滚动
afx_msg BOOL OnEraseBkgnd(CDC* pDC);//擦除背景
afx_msg void OnPaletteChanged(CWnd* pFocusWnd);//调色板更改
afx_msg BOOL OnQueryNewPalette();//查询新调色板
afx_msg BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
//}}AFX_MSG
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);//画每一行
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx
CListCtrlEx::CListCtrlEx()
{
m_nHighlight=0;
}
CListCtrlEx::~CListCtrlEx()
{
}
BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
//{{AFX_MSG_MAP(CListCtrlEx)
ON_WM_HSCROLL()
ON_WM_VSCROLL()
ON_WM_ERASEBKGND()
ON_WM_PALETTECHANGED()
ON_WM_QUERYNEWPALETTE() //}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx message handlers
BOOL CListCtrlEx::SetBkImage(UINT nIDResource)
{
return SetBkImage((LPCTSTR)nIDResource);
}
BOOL CListCtrlEx::SetBkImage(LPCTSTR lpszResourceName)
{
// If this is not the first call then Delete GDI objects
if( m_bitmap.m_hObject != NULL )
m_bitmap.DeleteObject();
if( m_pal.m_hObject != NULL )
m_pal.DeleteObject();
HBITMAP hBmp = (HBITMAP)::LoadImage( AfxGetInstanceHandle(),
lpszResourceName, IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION );
if( hBmp == NULL )
return FALSE;
m_bitmap.Attach( hBmp );
BITMAP bm;
m_bitmap.GetBitmap( &bm );
m_cxBitmap = bm.bmWidth;
m_cyBitmap = bm.bmHeight;
// Create a logical palette for the bitmap
DIBSECTION ds;
BITMAPINFOHEADER &bmInfo = ds.dsBmih;
m_bitmap.GetObject( sizeof(ds), &ds );
int nColors = bmInfo.biClrUsed ? bmInfo.biClrUsed : 1 << bmInfo.biBitCount;
// Create a halftone palette if colors > 256.
CClientDC dc(NULL); // Desktop DC
if( nColors > 256 )
m_pal.CreateHalftonePalette( &dc );
else
{
// Create the palette
RGBQUAD *pRGB = new RGBQUAD[nColors];
CDC memDC;
memDC.CreateCompatibleDC(&dc);
memDC.SelectObject( &m_bitmap );
::GetDIBColorTable( memDC, 0, nColors, pRGB );
UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);
LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize];
pLP->palVersion = 0x300;
pLP->palNumEntries = nColors;
for( int i=0; i < nColors; i++)
{
pLP->palPalEntry[i].peRed = pRGB[i].rgbRed;
pLP->palPalEntry[i].peGreen = pRGB[i].rgbGreen;
pLP->palPalEntry[i].peBlue = pRGB[i].rgbBlue;
pLP->palPalEntry[i].peFlags = 0;
}
m_pal.CreatePalette( pLP );
delete[] pLP;
delete[] pRGB;
}
Invalidate();
return TRUE;
}
void CListCtrlEx::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
if( m_bitmap.m_hObject != NULL )
InvalidateRect(NULL);
CListCtrl::OnHScroll(nSBCode, nPos, pScrollBar);
}
void CListCtrlEx::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
if( m_bitmap.m_hObject != NULL )
InvalidateRect(NULL);
CListCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
}
BOOL CListCtrlEx::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
if( m_bitmap.m_hObject != NULL )
return TRUE;
return CListCtrl::OnEraseBkgnd(pDC);
}
void CListCtrlEx::OnPaletteChanged(CWnd* pFocusWnd)
{
CListCtrl::OnPaletteChanged(pFocusWnd);
// TODO: Add your message handler code here
if( pFocusWnd == this )
return;
OnQueryNewPalette();
}
BOOL CListCtrlEx::OnQueryNewPalette()
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL )
{
dc.SelectPalette( &m_pal, FALSE );
BOOL result = dc.RealizePalette();
if( result )
Invalidate();
return result;
}
return CListCtrl::OnQueryNewPalette();
}
void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
CRect rcItem(lpDrawItemStruct->rcItem);
int nItem = lpDrawItemStruct->itemID;
CImageList* pImageList;
// Save dc state
int nSavedDC = pDC->SaveDC();
// Get item image and state info
LV_ITEM lvi;
lvi.mask = LVIF_IMAGE | LVIF_STATE;
lvi.iItem = nItem;
lvi.iSubItem = 0;
lvi.stateMask = 0xFFFF; // get all state flags
GetItem(&lvi);
// Should the item be highlighted
BOOL bHighlight =((lvi.state & LVIS_DROPHILITED)||((lvi.state & LVIS_SELECTED)&&((GetFocus() == this)||
(GetStyle() & LVS_SHOWSELALWAYS))));
// Get rectangles for drawing
CRect rcBounds, rcLabel, rcIcon;
GetItemRect(nItem, rcBounds, LVIR_BOUNDS);
GetItemRect(nItem, rcLabel, LVIR_LABEL);
GetItemRect(nItem, rcIcon, LVIR_ICON);
CRect rcCol( rcBounds );
CString sLabel = GetItemText(nItem, 0 );
// Labels are offset by a certain amount
// This offset is related to the width of a space character
int offset = pDC->GetTextExtent(_T(" "), 1 ).cx*2;
CRect rcHighlight;
CRect rcClient;
int nExt;
switch(m_nHighlight)
{
case 0:
nExt=pDC->GetOutputTextExtent(sLabel).cx + offset;
rcHighlight = rcLabel;
// if( rcLabel.left + nExt
if( m_bitmap.m_hObject != NULL )
{
CDC tempDC;
tempDC.CreateCompatibleDC(pDC);
tempDC.SelectObject( &m_bitmap );
GetClientRect(&rcClient);
CRgn rgnBitmap;
CRect rcTmpBmp( rcItem );
rcTmpBmp.right = rcClient.right;
// We also need to check whether it is the last item
// The update region has to be extended to the bottom if it is
if( nItem == GetItemCount() - 1 )
rcTmpBmp.bottom = rcClient.bottom;
rgnBitmap.CreateRectRgnIndirect(&rcTmpBmp);
pDC->SelectClipRgn(&rgnBitmap);
rgnBitmap.DeleteObject();
if( pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL )
{
pDC->SelectPalette( &m_pal, FALSE );
pDC->RealizePalette();
}
CRect rcFirstItem;
GetItemRect(0, rcFirstItem, LVIR_BOUNDS);
for (int i = rcFirstItem.left; i < rcTmpBmp.right; i += m_cxBitmap)
for (int j = rcFirstItem.top; j < rcTmpBmp.bottom; j += m_cyBitmap)
pDC->BitBlt(i, j, m_cxBitmap, m_cyBitmap, &tempDC, 0, 0, SRCCOPY);
}
}
// Draw the background color
if( bHighlight )
{
pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
pDC->FillRect(rcHighlight, &CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
}
else if( m_bitmap.m_hObject == NULL )
pDC->FillRect(rcHighlight, &CBrush(::GetSysColor(COLOR_WINDOW)));
// Set clip region
rcCol.right = rcCol.left + GetColumnWidth(0);
CRgn rgn;
rgn.CreateRectRgnIndirect(&rcCol);
pDC->SelectClipRgn(&rgn);
rgn.DeleteObject();
// Draw state icon
if (lvi.state & LVIS_STATEIMAGEMASK)
{
int nImage = ((lvi.state & LVIS_STATEIMAGEMASK)>>12) - 1;
pImageList = GetImageList(LVSIL_STATE);
if (pImageList)
{
pImageList->Draw(pDC, nImage,
CPoint(rcCol.left, rcCol.top), ILD_TRANSPARENT);
}
}
// Draw normal and overlay icon
pImageList = GetImageList(LVSIL_SMALL);
if (pImageList)
{
UINT nOvlImageMask=lvi.state & LVIS_OVERLAYMASK;
pImageList->Draw(pDC, lvi.iImage,
CPoint(rcIcon.left, rcIcon.top),
(bHighlight?ILD_BLEND50:0) | ILD_TRANSPARENT | nOvlImageMask );
}
// Draw item label - Column 0
rcLabel.left += offset/2;
rcLabel.right -= offset;
pDC->DrawText(sLabel,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP
| DT_VCENTER | DT_END_ELLIPSIS);
// Draw labels for remaining columns
LV_COLUMN lvc;
lvc.mask = LVCF_FMT | LVCF_WIDTH;
if( m_nHighlight == 0 ) // Highlight only first column
{
pDC->SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
pDC->SetBkColor(::GetSysColor(COLOR_WINDOW));
}
rcBounds.right = rcHighlight.right > rcBounds.right ? rcHighlight.right :
rcBounds.right;
rgn.CreateRectRgnIndirect(&rcBounds);
pDC->SelectClipRgn(&rgn);
for(int nColumn = 1; GetColumn(nColumn, &lvc); nColumn++)
{
rcCol.left = rcCol.right;
rcCol.right += lvc.cx;
// Draw the background if needed&& m_nHighlight == HIGHLIGHT_NORMAL
if( m_bitmap.m_hObject == NULL )
pDC->FillRect(rcCol, &CBrush(::GetSysColor(COLOR_WINDOW)));
sLabel = GetItemText(nItem, nColumn);
if (sLabel.GetLength() == 0)
continue;
// Get the text justification
UINT nJustify = DT_LEFT;
switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
{
case LVCFMT_RIGHT:
nJustify = DT_RIGHT;
break;
case LVCFMT_CENTER:
nJustify = DT_CENTER;
break;
default:
break;
}
rcLabel = rcCol;
rcLabel.left += offset;
rcLabel.right -= offset;
pDC->DrawText(sLabel, -1, rcLabel, nJustify | DT_SINGLELINE
| DT_NOPREFIX | DT_VCENTER | DT_END_ELLIPSIS);
}
// Draw focus rectangle if item has focus
if (lvi.state & LVIS_FOCUSED && (GetFocus() == this))
pDC->DrawFocusRect(rcHighlight);
// Restore dc
pDC->RestoreDC( nSavedDC );
}
void CListCtrlEx::AdjustColumnWidth()
{
SetRedraw(FALSE);
int nColumnCount = GetColumnCount();
for(int i = 0; i < nColumnCount; i++)
{
SetColumnWidth(i, LVSCW_AUTOSIZE);
int nColumnWidth = GetColumnWidth(i);
SetColumnWidth(i, LVSCW_AUTOSIZE_USEHEADER);
int nHeaderWidth = GetColumnWidth(i);
SetColumnWidth(i, max(nColumnWidth, nHeaderWidth));
}
SetRedraw(TRUE);
}
int CListCtrlEx::GetColumnCount()
{
CHeaderCtrl* pHeaderCtrl = GetHeaderCtrl();
return(pHeaderCtrl->GetItemCount());
}
BOOL CListCtrlEx::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
HD_NOTIFY *pHDN = (HD_NOTIFY*)lParam;
// This code is for using bitmap in the background
// Invalidate the right side of the control when a column is resized
if(pHDN->hdr.code == HDN_ITEMCHANGINGW || pHDN->hdr.code == HDN_ITEMCHANGINGA)
{
if( m_bitmap.m_hObject != NULL )
{
CRect rcClient;
GetClientRect( &rcClient );
DWORD dwPos = GetMessagePos();
CPoint pt( LOWORD(dwPos), HIWORD(dwPos) );
ScreenToClient( &pt );
rcClient.left = pt.x;
InvalidateRect( &rcClient );
}
}
return CListCtrl::OnNotify(wParam, lParam, pResult);
}
BOOL CCdDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About" menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
m_list.InsertColumn(0,_T("用户编号"));
m_list.InsertColumn(1,_T(" 用户名称 "));
m_list.InsertColumn(2, _T("年龄"));
m_list.InsertColumn(3, _T("性别"));
m_list.InsertColumn(4,_T(" 用户住址 "));
char ch[5];
for(int j=1;j<=200;j++)
{
m_list.InsertItem(j,itoa(j,ch,10));
}
for(int i = 0;i<200;i++)
{
m_list.SetItemText(i,1,strcat(itoa(i+1,ch,10),"号用户"));
m_list.SetItemText(i,2,itoa((i+100)%100,ch,10));
if(i%2==0)
{
m_list.SetItemText(i,3,"男");
}
else
{
m_list.SetItemText(i,3,"女");
}
m_list.SetItemText(i,4,strcat(itoa(i+1,ch,10),"号大街"));
}
ListView_SetExtendedListViewStyle(m_list.m_hWnd,LVS_EX_FULLROWSELECT|LVS_EX_FLATSB|LVS_EX_HEADERDRAGDROP );
m_list.SetBkImage(IDB_Bless);
m_list.AdjustColumnWidth();
return TRUE; // return TRUE unless you set the focus to a control
}
效果如图所示:
200781702.jpg
但是这里还有一个问题,就是当下拉滚动条的时候,如何让背景图片不动,而只是数据行变化,这是接下来要做的工作。
参考资料:
http://www.codeguru.com/Cpp/controls/listview/backgroundcolorandimage/article.php/c983/
本文转自Phinecos(洞庭散人)博客园博客,原文链接:http://www.cnblogs.com/phinecos/archive/2007/08/17/859410.html,如需转载请自行联系原作者