#if !defined(AFX_LISTCTRLEX_H__D6B18D30_CDA0_4C18_B4D5_2911EF371DE7__INCLUDED_) #define AFX_LISTCTRLEX_H__D6B18D30_CDA0_4C18_B4D5_2911EF371DE7__INCLUDED_ #if _MSC_VER>1000 #pragma once #endif //_MSC_VER>1000 // ListCtrlEx.h : header file // / // 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() }; / //{{AFX_INSERT_LOCATION}} // Microsoft Visual C++ will insert additional declarations immediately before the previous line. #endif // !defined(AFX_LISTCTRLEX_H__D6B18D30_CDA0_4C18_B4D5_2911EF371DE7__INCLUDED_) // 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; BOOLbRet; 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); } } //绘制默认的覆盖图标 CRectrcIcon; 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_COLUMNlvc; 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 selectmode, we need to extend the clipping region //so wecan 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(); }