自行绘制 ClistCtrl 的列表项,可以利用列表框的 NM_CUSTOMDRAW 消息,该消息由控件向它的父窗口发送,告诉父窗口它的绘图操作。
如果绘图操作不需要父窗口参与,可以使用该控件的 ON_NOTIFY_REFLECT 宏处理它的 NM_CUSTOMDRAW 消息。
它的处理函数的参数中包含 NMHDR,在 CUSTOMDRAW 的通知下 NMHDR 可以被转换成为 NMLVCUSTOMDRAW
结构,该结构包含了列表控件中需要自绘区域的全部信息:
typedef struct tagNMLVCUSTOMDRAW
{
NMCUSTOMDRAW
nmcd; // 包含客户自绘控件信息的结构
COLORREF
clrText; // 列表视图显示文字的颜色
COLORREF
clrTextBk; // 列表视图显示文字的背景色
} NMLVCUSTOMDRAW, *LPNMLVCUSTOMDRAW;
typedef struct
tagNMLVCUSTOMDRAW
{
NMCUSTOMDRAW nmcd;
COLORREF
clrText; //列表视图显示文字的颜色
COLORREF
clrTextBk; //列表视图显示文字的背景色
#if (_WIN32_IE >=
0x0400)
int iSubItem; //子项编号
#endif
#if
(_WIN32_WINNT >= 0x501)
DWORD dwItemType; //
// Item custom draw
COLORREF
clrFace; //
int iIconEffect;
int iIconPhase;
int
iPartId;
int iStateId;
// Group Custom Draw
RECT
rcText;
UINT uAlign; // Alignment. Use LVGA_HEADER_CENTER,
LVGA_HEADER_RIGHT, LVGA_HEADER_LEFT
#endif
} NMLVCUSTOMDRAW,
*LPNMLVCUSTOMDRAW;
NMCUSTOMDRAW 结构定义如下:
typedef struct tagNMCUSTOMDRAWINFO
{
NMHDR
hdr; // 含有通知信息的 NMHDR 结构
DWORD dwDrawStage; //
目前绘制的步骤
HDC hdc; // 设备上下文句柄
RECT
rc; // 绘制的区域
DWORD dwItemSpec; // 绘制项的说明
UINT uItemState; // 当前项的状态
LPARAM
lItemlParam // 应用程序定义的数据
} NMCUSTOMDRAW, FAR * LPNMCUSTOMDRAW;
NMLVCUSTOMDRAW.nmcd.dwDrawStage 字段,它主要包含以下几个枚举值:
- CDDS_PREPAINT:表示在绘画前阶段。
- CDDS_ITEMPREPAINT:表示在列表项的绘画前阶段。
- CDDS_SUBITEM:表示绘制子项。
- CDDS_ITEM:表示要绘制项的信息已经可用。
自绘时,可以通过处理以上几个绘画阶段的通知来实现。
例子详细步骤:
- 利用 MFC AppWizard( exe ) 创建一个新工程 TestCListCtrl。在向导的第 ( 1 )
步选择单文档模式,而后使用默认值来创建,最后获得一个支持文档视图的应用程序。
- 在 ClassView 中添加新的类 CCoolListCtrl,类型为 MFC Class,基类为CListCtrl。获得两个新文件
CCoolListCtrl.cpp 和 CCoolListCtrl.h。
- 在类 CCoolListCtrl 中添加成员变量 m_imagelist 用于存储图像列表。
- 添加 NM_CUSTOMDRAW 消息的处理函数 OnCustomDraw。
CCoolListCtrl.h 文件中:
afx_msg void OnCustomDraw(NMHDR* pNMHDR, LRESULT*
pResult);//消息函数声明
CCoolListCtrl.cpp 文件中:
// 消息映射宏中添加:ON_NOTIFY_REFLECT(NM_CUSTOMDRAW,
OnCustomDraw)
BEGIN_MESSAGE_MAP(CCoolListCtrl, CListCtrl)
//{{AFX_MSG_MAP(CCoolListCtrl)
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW,
OnCustomDraw)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
// 消息处理函数实现:
/////////////////////////////////////////////////////////////////////////////
// CCoolListCtrl message handlers
void CCoolListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
NMLVCUSTOMDRAW*
pLVCD = reinterpret_cast <NMLVCUSTOMDRAW*> ( pNMHDR );
*pResult = 0;
// Request item-specific notifications if this is the
// beginning of the paint cycle.
if ( CDDS_PREPAINT == pLVCD-> nmcd.dwDrawStage )
{
*pResult =
CDRF_NOTIFYITEMDRAW;
}
else if ( CDDS_ITEMPREPAINT == pLVCD->
nmcd.dwDrawStage )
{
// This is the beginning of an item 's paint cycle.
LVITEM rItem;
int nItem = static_cast <int> ( pLVCD->
nmcd.dwItemSpec );
CDC* pDC = CDC::FromHandle ( pLVCD-> nmcd.hdc );
COLORREF crBkgnd;
BOOL bListHasFocus;
CRect rcItem;
CRect
rcText;
CString sText;
UINT uFormat;
bListHasFocus = ( this->GetSafeHwnd() == ::GetFocus() );
// Get the image index and selected/focused state of the
// item
being drawn.
ZeroMemory ( &rItem, sizeof(LVITEM) );
rItem.mask =
LVIF_IMAGE | LVIF_STATE;
rItem.iItem = nItem;
rItem.stateMask =
LVIS_SELECTED | LVIS_FOCUSED;
this->GetItem ( &rItem );
// Get the rect that holds the item 's icon.
this->GetItemRect
( nItem, &rcItem, LVIR_ICON );
// Draw the icon.
uFormat = ILD_TRANSPARENT;
if ( ( rItem.state & LVIS_SELECTED ) && bListHasFocus )
uFormat |= ILD_FOCUS;
m_imagelist.Draw ( pDC, rItem.iImage, rcItem.TopLeft(), uFormat
);
// Get the rect that bounds the text label.
this->GetItemRect
( nItem, rcItem, LVIR_LABEL ); //把这行去掉就没有文字.
// Draw the background of the list item. Colors are selected
//
according to the item 's state.
if ( rItem.state & LVIS_SELECTED )
{
if ( bListHasFocus )
{
crBkgnd = GetSysColor ( COLOR_HIGHLIGHT );
pDC-> SetTextColor (
GetSysColor ( COLOR_HIGHLIGHTTEXT ));
}
else
{
crBkgnd =
GetSysColor ( COLOR_BTNFACE );
pDC-> SetTextColor ( GetSysColor (
COLOR_BTNTEXT ));
}
}
else
{
crBkgnd = GetSysColor (
COLOR_WINDOW );
pDC-> SetTextColor ( GetSysColor ( COLOR_BTNTEXT ));
}
// Draw the background & prep the DC for the text drawing. Note
// that the entire item RECT is filled in, so this emulates the full-
//
row selection style of normal lists.
pDC-> FillSolidRect ( rcItem,
crBkgnd );
pDC-> SetBkMode ( TRANSPARENT );
// Tweak the rect a bit for nicer-looking text alignment.
rcText
= rcItem;
// Draw the text.
sText = this->GetItemText ( nItem, 0
);
pDC-> DrawText ( sText,
CRect::CRect(rcText.left+3,rcText.top,rcText.right,rcText.bottom+60), DT_VCENTER
);
// Draw a focus rect around the item if necessary.
if (
bListHasFocus && ( rItem.state & LVIS_FOCUSED ))
{
pDC->
DrawFocusRect ( rcItem );
}
*pResult = CDRF_SKIPDEFAULT; // We 've painted everything.
}
}
- 在视图类 CTestCListCtrlView 中添加成员变量 m_ListCtrl,类型为 CCoolListCtrl。
- 定义 WM_CREATE 消息的处理函数 CTestCListCtrlView ::Create,用于创建 CCoolListCtrl 控件,代码如下:
//创建列表控件:自绘样式、没有列头部、处理通知
m_ListCtrl.Create(LVS_OWNERDRAWFIXED |
LVS_NOCOLUMNHEADER | LBS_NOTIFY, CRect(0,0,400,200), this, IDC_LISTCTRL );
// 可以使用 m_ListCtrl.SetExtendedStyle 设置扩展样式
// 用自己编写的函数设置图像列表
m_ListCtrl.SetImagelist(IDB_IMAGE);
// 用自己编写的函数设置列表项的行高,方法见文章《CListCtrl行高的修改》
m_ListCtrl.SetItemHeight(36);
// 插入项
m_ListCtrl.InsertItem(0, "Monroeville", 0);
m_ListCtrl.InsertItem(1,
"Hartford", 1);
m_ListCtrl.InsertItem(2, "Redmond", 2);
- 设置图像列表的函数:首先将作为图像列表的bmp文件导入到工程资源中,uBitmap是其资源ID
BOOL CCoolListCtrl::SetImagelist(UINT uBitmap)
{
m_imagelist.DeleteImageList();
m_imagelist.Create(32, 32,
ILC_COLOR24|ILC_MASK, 8, 1);
CBitmap bitmap;
bitmap.LoadBitmap(uBitmap);
m_imagelist.Add(&bitmap, RGB(255,0,255));
return TRUE;
}
-
采用添加 NM_CUSTOMDRAW 消息的处理函数 OnCustomDraw 的方式来自绘,遇到了一点问题:
创建 ClistCtrl 时使用 LVS_OWNERDRAWFIXED 样式的话,在OnCustomDraw 函数中:
switch(pLVCD-> nmcd.dwDrawStage) //绘画阶段
{
case CDDS_PREPAINT: //在绘画前阶段
*pResult =
CDRF_NOTIFYSUBITEMDRAW; //返回列表项绘画通知
break;
case
CDDS_ITEMPREPAINT: //在列表项的绘画前阶段
*pResult = CDRF_NOTIFYSUBITEMDRAW;
//返回子列表项绘画通知
break;
case CDDS_ITEMPREPAINT|CDDS_SUBITEM:
//绘画列表项或子项
{
int iCol = lplvcd->iSubItem;
int iRow =
lplvcd->nmcd.dwItemSpec;
CString sItem = GetItemText(iRow, iCol);
CRect rc;
GetCellRect(iRow, iCol, LVIR_BOUNDS, rc);
// get the
device context.
CDC *pDC= CDC::FromHandle(lplvcd->nmcd.hdc);
// paint
the text centered.
pDC->DrawText(sItem , rc, DT_CENTER);
*pResult=
CDRF_SKIPDEFAULT;
break;
}
default:
*pResult = CDRF_DODEFAULT;//
控件完成自绘,不再发送 NM_CUSTOMDRAW 消息
return ;
}
*pResult = CDRF_NOTIFYSUBITEMDRAW; 返回子列表项绘画通知时,弹出了错误:
debug assertion failed
program .....exe
file :winctrl2.cpp
line :547
而且似乎进不了case CDDS_ITEMPREPAINT|CDDS_SUBITEM,不知何故。
原来 CListCtrl 的派生类,使用 LVS_OWNERDRAWFIXED 的样式的话,必须重载 DrawItem 函数来绘制各项,否则就取消
LVS_OWNERDRAWFIXED 的样式。
但取消 LVS_OWNERDRAWFIXED 的样式的话,就无法自行设置列表项的行高了。
所以将 OnCustomDraw 换成重载 DrawItem 的方式。
例如:
void CCoolListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{
LVITEM
rItem;
int nItem = lpDIS->itemID;
CDC* pDC = CDC::FromHandle
(lpDIS->hDC);
// COLORREF crBkgnd;
BOOL bListHasFocus;
CRect rcItem;
CRect rcCell;
CRect rcText;
CString
sText;
UINT uFormat;
LV_COLUMN lvc;
::ZeroMemory(&lvc, sizeof(lvc));
lvc.mask =
LVCF_WIDTH | LVCF_FMT;
int intColumnCount;
for (intColumnCount=0;
GetColumn(intColumnCount, &lvc); intColumnCount++)
{
bListHasFocus =
( GetSafeHwnd() == ::GetFocus() );
// Get the image index and selected/focused state of the
// item
being drawn.
ZeroMemory ( &rItem, sizeof(LVITEM) );
rItem.iSubItem =
intColumnCount;
rItem.mask = LVIF_IMAGE | LVIF_STATE;
rItem.iItem =
nItem;
rItem.stateMask = LVIS_SELECTED | LVIS_FOCUSED;
VERIFY(GetItem(&rItem));
GetSubItemRect(lpDIS->itemID, intColumnCount,LVIR_BOUNDS,
rcCell);
if (intColumnCount == 0)
{
rcItem = rcCell;
rcCell.right = GetColumnWidth(0);
}
// Draw the icon.
uFormat =
ILD_TRANSPARENT;
if ( ( rItem.state & LVIS_SELECTED ) &&
bListHasFocus )
uFormat |= ILD_FOCUS;
// 居中绘画图标
CPoint picPt;
picPt.x =
rcCell.left+(rcCell.Width()-32)/2;
picPt.y =
rcCell.top+(rcCell.Height()-32)/2;
m_imagelist.Draw ( pDC, rItem.iImage,
picPt, uFormat );
// Tweak the rect a bit for nicer-looking text alignment.
rcText
= rcItem;
// Draw the text.
sText = this->GetItemText ( nItem, 0 );
pDC-> DrawText ( sText,
CRect::CRect(rcText.left+3,rcText.top,rcText.right,rcText.bottom+60), DT_VCENTER
);
}
return ;
}
以下是Ownerdraw方式的
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx window
class CListCtrlEx : public CListCtrl
{
public:
CListCtrlEx();
virtual ~CListCtrlEx();
protected:
//当前是否为整行选择
BOOL m_bFullRowSel;
BOOL
m_bClientWidthSel;
int m_cxClient;
int m_cxStateImageOffset;
COLORREF m_clrText;
COLORREF m_clrTextBk;
COLORREF m_clrBkgnd;
public:
//设定当前是否为整行选择状态
BOOL SetFullRowSel(BOOL
bFillRowSel);
//获取当前是否为整行选择状态
BOOL GetFullRowSel();
//{{AFX_VIRTUAL(CListCtrlEx)
public:
virtual BOOL
PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual void
DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
//}}AFX_VIRTUAL
protected:
static LPCTSTR MakeShortString(CDC* pDC, LPCTSTR
lpszLong, int nColumnLen, int nOffset);
void
RepaintSelectedItems();
#ifdef _DEBUG
virtual void
Dump(CDumpContext& dc) const;
#endif
//{{AFX_MSG(CListCtrlEx)
afx_msg LRESULT OnSetImageList(WPARAM
wParam, LPARAM lParam);
afx_msg LRESULT OnSetTextColor(WPARAM
wParam, LPARAM lParam);
afx_msg LRESULT OnSetTextBkColor(WPARAM
wParam, LPARAM lParam);
afx_msg LRESULT OnSetBkColor(WPARAM
wParam, LPARAM lParam);
afx_msg void OnSize(UINT nType, int
cx, int cy);
afx_msg void OnPaint();
afx_msg void
OnSetFocus(CWnd* pOldWnd);
afx_msg void OnKillFocus(CWnd* pNewWnd);
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
// ListCtrlEx.cpp : implementation file
//
#include
"stdafx.h "
#include "ListCtrlEx.h "
#ifdef _DEBUG
#define
new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] =
__FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx
CListCtrlEx::CListCtrlEx()
{
m_bFullRowSel =
FALSE;
m_bClientWidthSel = TRUE;
m_cxClient = 0;
m_cxStateImageOffset = 0;
m_clrText =
::GetSysColor(COLOR_WINDOWTEXT);
m_clrTextBk =
::GetSysColor(COLOR_WINDOW);
m_clrBkgnd = ::GetSysColor(COLOR_WINDOW);
}
CListCtrlEx::~CListCtrlEx()
{
}
BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
//{{AFX_MSG_MAP(CListCtrlEx)
ON_WM_SIZE()
ON_WM_PAINT()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
ON_MESSAGE(LVM_SETIMAGELIST,
OnSetImageList)
ON_MESSAGE(LVM_SETTEXTCOLOR, OnSetTextColor)
ON_MESSAGE(LVM_SETTEXTBKCOLOR, OnSetTextBkColor)
ON_MESSAGE(LVM_SETBKCOLOR, OnSetBkColor)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
#ifdef _DEBUG
void
CListCtrlEx::Dump(CDumpContext& dc) const
{
CListCtrl::Dump(dc);
dc < < "m_bFullRowSel = " < <
(UINT)m_bFullRowSel;
dc < < "/n ";
dc < <
"m_cxStateImageOffset = " < < m_cxStateImageOffset;
dc <
< "/n ";
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CListCtrlEx message handlers
BOOL
CListCtrlEx::PreCreateWindow(CREATESTRUCT& cs)
{
//默认当前为整行选择
cs.style &= ~LVS_TYPEMASK;
cs.style |= LVS_REPORT |
LVS_OWNERDRAWFIXED;
m_bFullRowSel = TRUE;
return(CListCtrl::PreCreateWindow(cs));
}
BOOL
CListCtrlEx::SetFullRowSel(BOOL bFullRowSel)
{
//在此函数执行期间,锁定当前窗口使其不充许刷新
LockWindowUpdate();
m_bFullRowSel =
bFullRowSel;
BOOL bRet;
if(m_bFullRowSel)
bRet =
ModifyStyle(0L, LVS_OWNERDRAWFIXED);
else
bRet =
ModifyStyle(LVS_OWNERDRAWFIXED, 0L);
//如果当前没有改变窗口控件的类型,重刷当前窗口
if(bRet && (GetStyle() & LVS_TYPEMASK) ==
LVS_REPORT)
Invalidate();
//取消当前窗口不充许刷新的锁定
UnlockWindowUpdate();
return bRet;
}
BOOL CListCtrlEx::GetFullRowSel()
{
return m_bFullRowSel;
}
// offsets for first and
other columns
#define OFFSET_FIRST 2
#define
OFFSET_OTHER 6
void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT
lpDrawItemStruct)
{
CDC* pDC =
CDC::FromHandle(lpDrawItemStruct-> hDC);
CRect
rcItem(lpDrawItemStruct-> rcItem);
UINT uiFlags = ILD_TRANSPARENT;
CImageList* pImageList;
int nItem = lpDrawItemStruct->
itemID;
BOOL bFocus = (GetFocus() == this);
COLORREF
clrTextSave, clrBkSave;
COLORREF clrImage = m_clrBkgnd;
static
_TCHAR szBuff[MAX_PATH];
LPCTSTR pszText;
//获取项数据
LV_ITEM
lvi;
lvi.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
lvi.iItem = nItem;
lvi.iSubItem = 0;
lvi.pszText =
szBuff;
lvi.cchTextMax = sizeof(szBuff);
lvi.stateMask =
0xFFFF;//获取所有的状态标志
this-> GetItem(&lvi);
BOOL bSelected =
(bFocus || (GetStyle() & LVS_SHOWSELALWAYS)) &&
lvi.state & LVIS_SELECTED;
bSelected = bSelected ||
(lvi.state & LVIS_DROPHILITED);
//设定选中项的颜色
CRect
rcAllLabels;
this-> GetItemRect(nItem, rcAllLabels, LVIR_BOUNDS);
CRect rcLabel;
this-> GetItemRect(nItem, rcLabel,
LVIR_LABEL);
rcAllLabels.left = rcLabel.left;
if
(m_bClientWidthSel && rcAllLabels.right <m_cxClient)
rcAllLabels.right = m_cxClient;
if (bSelected)
{
clrTextSave = pDC-> SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
clrBkSave = pDC-> SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
pDC-> FillRect(rcAllLabels,
&CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
}
else
pDC->
FillRect(rcAllLabels, &CBrush(m_clrTextBk));
//设定图标的颜色和标志
if
(lvi.state & LVIS_CUT)
{
clrImage = m_clrBkgnd;
uiFlags
|= ILD_BLEND50;
}
else if(bSelected)
{
clrImage =
::GetSysColor(COLOR_HIGHLIGHT);
uiFlags |= ILD_BLEND50;
}
//绘制状态图标
UINT nStateImageMask = lvi.state &
LVIS_STATEIMAGEMASK;
if (nStateImageMask)
{
int nImage =
(nStateImageMask> > 12) - 1;
pImageList = this->
GetImageList(LVSIL_STATE);
if (pImageList)
{
pImageList->
Draw(pDC, nImage,
CPoint(rcItem.left, rcItem.top), ILD_TRANSPARENT);
}
}
//绘制默认的覆盖图标
CRect rcIcon;
this->
GetItemRect(nItem, rcIcon, LVIR_ICON);
pImageList = this->
GetImageList(LVSIL_SMALL);
if (pImageList)
{
UINT
nOvlImageMask=lvi.state & LVIS_OVERLAYMASK;
if (rcItem.left
<rcItem.right-1)
{
ImageList_DrawEx(pImageList-> m_hImageList,
lvi.iImage,
pDC-> m_hDC,rcIcon.left,rcIcon.top, 16, 16,
m_clrBkgnd, clrImage, uiFlags | nOvlImageMask);
}
}
//绘制项标签
this-> GetItemRect(nItem, rcItem, LVIR_LABEL);
rcItem.right -= m_cxStateImageOffset;
pszText =
MakeShortString(pDC, szBuff,
rcItem.right-rcItem.left, 2*OFFSET_FIRST);
rcLabel = rcItem;
rcLabel.left += OFFSET_FIRST;
rcLabel.right -= OFFSET_FIRST;
pDC->
DrawText(pszText,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX |
DT_NOCLIP | DT_VCENTER);
//绘制标签扩展列
LV_COLUMN lvc;
lvc.mask
= LVCF_FMT | LVCF_WIDTH;
for(int nColumn = 1; this->
GetColumn(nColumn, &lvc); nColumn++)
{
rcItem.left =
rcItem.right;
rcItem.right += lvc.cx;
int nRetLen =
this-> GetItemText(nItem, nColumn,
szBuff, sizeof(szBuff));
if
(nRetLen == 0)
continue;
pszText = MakeShortString(pDC,
szBuff,
rcItem.right - rcItem.left, 2*OFFSET_OTHER);
UINT
nJustify = DT_LEFT;
if(pszText == szBuff)
{
switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
{
case LVCFMT_RIGHT:
nJustify = DT_RIGHT;
break;
case LVCFMT_CENTER:
nJustify
= DT_CENTER;
break;
default:
break;
}
}
rcLabel
= rcItem;
rcLabel.left += OFFSET_OTHER;
rcLabel.right -=
OFFSET_OTHER;
pDC-> DrawText(pszText, -1, rcLabel,
nJustify
| DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
}
//绘制焦点框矩形
if (lvi.state & LVIS_FOCUSED &&
bFocus)
pDC-> DrawFocusRect(rcAllLabels);
//设定选中项的颜色
if
(bSelected)
{
pDC-> SetTextColor(clrTextSave);
pDC->
SetBkColor(clrBkSave);
}
}
LPCTSTR
CListCtrlEx::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int
nColumnLen, int nOffset)
{
static const _TCHAR szThreeDots[]
= _T( "... ");
int nStringLen = lstrlen(lpszLong);
if(nStringLen == 0 ||
(pDC-> GetTextExtent(lpszLong,
nStringLen).cx + nOffset) <= nColumnLen)
{
return(lpszLong);
}
static _TCHAR szShort[MAX_PATH];
lstrcpy(szShort,lpszLong);
int nAddLen = pDC->
GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx;
for(int i =
nStringLen-1; i > 0; i--)
{
szShort[i] = 0;
if((pDC-> GetTextExtent(szShort, i).cx + nOffset + nAddLen)
<= nColumnLen)
{
break;
}
}
lstrcat(szShort,
szThreeDots);
return(szShort);
}
void CListCtrlEx::RepaintSelectedItems()
{
CRect rcItem,
rcLabel;
int nItem = this-> GetNextItem(-1, LVNI_FOCUSED);
//当前没被选择项
if(nItem != -1)
{
this-> GetItemRect(nItem,
rcItem, LVIR_BOUNDS);
this-> GetItemRect(nItem, rcLabel,
LVIR_LABEL);
rcItem.left = rcLabel.left;
InvalidateRect(rcItem,
FALSE);
}
//当前选择项是永远选择
if(!(GetStyle() &
LVS_SHOWSELALWAYS))
{
for(nItem = this-> GetNextItem(-1,
LVNI_SELECTED);
nItem != -1; nItem = this-> GetNextItem(nItem,
LVNI_SELECTED))
{
this-> GetItemRect(nItem, rcItem,
LVIR_BOUNDS);
this-> GetItemRect(nItem, rcLabel, LVIR_LABEL);
rcItem.left = rcLabel.left;
InvalidateRect(rcItem, FALSE);
}
}
//刷新当前窗口
UpdateWindow();
}
LRESULT
CListCtrlEx::OnSetImageList(WPARAM wParam, LPARAM lParam)
{
//
if we 're running Windows 4, there 's no need to offset the
// item text location
OSVERSIONINFO info;
info.dwOSVersionInfoSize = sizeof(info);
VERIFY(::GetVersionEx(&info));
if( (int) wParam ==
LVSIL_STATE && info.dwMajorVersion < 4)
{
int cx,
cy;
if(::ImageList_GetIconSize((HIMAGELIST)lParam, &cx,
&cy))
m_cxStateImageOffset = cx;
else
m_cxStateImageOffset
= 0;
}
return(Default());
}
LRESULT
CListCtrlEx::OnSetTextColor(WPARAM wParam, LPARAM lParam)
{
m_clrText = (COLORREF)lParam;
return(Default());
}
LRESULT CListCtrlEx::OnSetTextBkColor(WPARAM wParam, LPARAM
lParam)
{
m_clrTextBk = (COLORREF)lParam;
return(Default());
}
LRESULT CListCtrlEx::OnSetBkColor(WPARAM wParam, LPARAM
lParam)
{
m_clrBkgnd = (COLORREF)lParam;
return(Default());
}
void CListCtrlEx::OnSize(UINT nType, int cx, int cy)
{
m_cxClient = cx;
CListCtrl::OnSize(nType, cx, cy);
}
void CListCtrlEx::OnPaint()
{
// in full row select
mode, we need to extend the clipping region
// so we can
paint a selection all the way to the right
if
(m_bClientWidthSel &&
(GetStyle() & LVS_TYPEMASK) ==
LVS_REPORT &&
GetFullRowSel())
{
CRect rcAllLabels;
this-> GetItemRect(0, rcAllLabels, LVIR_BOUNDS);
if(rcAllLabels.right < m_cxClient)
{
// need to
call BeginPaint (in CPaintDC c-tor)
// to get correct
clipping rect
CPaintDC dc(this);
CRect rcClip;
dc.GetClipBox(rcClip);
rcClip.left = min(rcAllLabels.right-1,
rcClip.left);
rcClip.right = m_cxClient;
InvalidateRect(rcClip,
FALSE);
// EndPaint will be called in CPaintDC d-tor
}
}
CListCtrl::OnPaint();
}
void
CListCtrlEx::OnSetFocus(CWnd* pOldWnd)
{
CListCtrl::OnSetFocus(pOldWnd);
// check if we are getting
focus from label edit box
if(pOldWnd!=NULL &&
pOldWnd-> GetParent()==this)
return;
// repaint items that
should change appearance
if(m_bFullRowSel && (GetStyle()
& LVS_TYPEMASK)==LVS_REPORT)
RepaintSelectedItems();
}
void CListCtrlEx::OnKillFocus(CWnd* pNewWnd)
{
CListCtrl::OnKillFocus(pNewWnd);
// check if we are losing
focus to label edit box
if(pNewWnd != NULL &&
pNewWnd-> GetParent() == this)
return;
// repaint items
that should change appearance
if(m_bFullRowSel &&
(GetStyle() & LVS_TYPEMASK) == LVS_REPORT)
RepaintSelectedItems();
}