ListCtrlEx.cpp
上传用户:jsxglz
上传日期:2007-01-03
资源大小:117k
文件大小:12k
源码类别:

SQL Server

开发平台:

Visual C++

  1. // ListCtrlEx.cpp : implementation of the CListCtrlEx class
  2. #include "stdafx.h"
  3. #include "ListCtrlEx.h"
  4. #ifdef _DEBUG
  5. #define new DEBUG_NEW
  6. #undef THIS_FILE
  7. static char THIS_FILE[] = __FILE__;
  8. #endif
  9. /////////////////////////////////////////////////////////////////////////////
  10. // CListCtrlEx
  11. IMPLEMENT_DYNCREATE(CListCtrlEx, CListCtrl)
  12. BEGIN_MESSAGE_MAP(CListCtrlEx, CListCtrl)
  13. //{{AFX_MSG_MAP(CListCtrlEx)
  14. ON_WM_SIZE()
  15. ON_WM_PAINT()
  16. ON_WM_SETFOCUS()
  17. ON_WM_KILLFOCUS()
  18. //}}AFX_MSG_MAP
  19. ON_MESSAGE(LVM_SETIMAGELIST, OnSetImageList)
  20. ON_MESSAGE(LVM_SETTEXTCOLOR, OnSetTextColor)
  21. ON_MESSAGE(LVM_SETTEXTBKCOLOR, OnSetTextBkColor)
  22. ON_MESSAGE(LVM_SETBKCOLOR, OnSetBkColor)
  23. ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)
  24. ON_NOTIFY_EX_RANGE(TTN_NEEDTEXTA, 0, 0xFFFF, OnToolTipText)
  25. END_MESSAGE_MAP()
  26. /////////////////////////////////////////////////////////////////////////////
  27. // CListCtrlEx construction/destruction
  28. CListCtrlEx::CListCtrlEx()
  29. {
  30. m_bFullRowSel=FALSE;
  31. m_bClientWidthSel=TRUE;
  32. m_cxClient=0;
  33. m_cxStateImageOffset=0;
  34. m_clrText=::GetSysColor(COLOR_WINDOWTEXT);
  35. m_clrTextBk=::GetSysColor(COLOR_WINDOW);
  36. m_clrBkgnd=::GetSysColor(COLOR_WINDOW);
  37. }
  38. CListCtrlEx::~CListCtrlEx()
  39. {
  40. }
  41. BOOL CListCtrlEx::PreCreateWindow(CREATESTRUCT& cs)
  42. {
  43. // default is report view and full row selection
  44. cs.style &= ~LVS_TYPEMASK;
  45. cs.style |= LVS_REPORT | LVS_OWNERDRAWFIXED;
  46. m_bFullRowSel=TRUE;
  47. return(CListCtrl::PreCreateWindow(cs));
  48. }
  49. BOOL CListCtrlEx::SetFullRowSel(BOOL bFullRowSel)
  50. {
  51. // no painting during change
  52. LockWindowUpdate();
  53. m_bFullRowSel=bFullRowSel;
  54. BOOL bRet;
  55. if(m_bFullRowSel)
  56. bRet=ModifyStyle(0L,LVS_OWNERDRAWFIXED);
  57. else
  58. bRet=ModifyStyle(LVS_OWNERDRAWFIXED,0L);
  59. // repaint window if we are not changing view type
  60. if(bRet && (GetStyle() & LVS_TYPEMASK)==LVS_REPORT)
  61. Invalidate();
  62. // repaint changes
  63. UnlockWindowUpdate();
  64. return(bRet);
  65. }
  66. BOOL CListCtrlEx::GetFullRowSel()
  67. {
  68. return(m_bFullRowSel);
  69. }
  70. /////////////////////////////////////////////////////////////////////////////
  71. // CListCtrlEx drawing
  72. // offsets for first and other columns
  73. #define OFFSET_FIRST 2
  74. #define OFFSET_OTHER 6
  75. void CListCtrlEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  76. {
  77. CDC* pDC=CDC::FromHandle(lpDrawItemStruct->hDC);
  78. CRect rcItem(lpDrawItemStruct->rcItem);
  79. UINT uiFlags=ILD_TRANSPARENT;
  80. CImageList* pImageList;
  81. int nItem=lpDrawItemStruct->itemID;
  82. BOOL bFocus=(GetFocus()==this);
  83. COLORREF clrTextSave, clrBkSave;
  84. COLORREF clrImage=m_clrBkgnd;
  85. static _TCHAR szBuff[MAX_PATH];
  86. LPCTSTR pszText;
  87. // get item data
  88. LV_ITEM lvi;
  89. lvi.mask=LVIF_TEXT | LVIF_IMAGE | LVIF_STATE;
  90. lvi.iItem=nItem;
  91. lvi.iSubItem=0;
  92. lvi.pszText=szBuff;
  93. lvi.cchTextMax=sizeof(szBuff);
  94. lvi.stateMask=0xFFFF; // get all state flags
  95. GetItem(&lvi);
  96. BOOL bSelected=(bFocus || (GetStyle() /*& LVS_SHOWSELALWAYS*/)) && lvi.state & LVIS_SELECTED;
  97. bSelected=bSelected || (lvi.state & LVIS_DROPHILITED);
  98. // set colors if item is selected
  99. CRect rcAllLabels;
  100. GetItemRect(nItem,rcAllLabels,LVIR_BOUNDS);
  101. CRect rcLabel;
  102. GetItemRect(nItem,rcLabel,LVIR_LABEL);
  103. rcAllLabels.left=rcLabel.left;
  104. if(m_bClientWidthSel && rcAllLabels.right<m_cxClient)
  105. rcAllLabels.right=m_cxClient;
  106. if(bSelected)
  107. {
  108. clrTextSave=pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
  109. clrBkSave=pDC->SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
  110. pDC->FillRect(rcAllLabels,&CBrush(::GetSysColor(COLOR_HIGHLIGHT)));
  111. }
  112. else
  113. pDC->FillRect(rcAllLabels,&CBrush(m_clrTextBk));
  114. // set color and mask for the icon
  115. if(lvi.state & LVIS_CUT)
  116. {
  117. clrImage=m_clrBkgnd;
  118. uiFlags|=ILD_BLEND50;
  119. }
  120. else if(bSelected)
  121. {
  122. clrImage=::GetSysColor(COLOR_HIGHLIGHT);
  123. uiFlags|=ILD_BLEND50;
  124. }
  125. // draw state icon
  126. UINT nStateImageMask=lvi.state & LVIS_STATEIMAGEMASK;
  127. if(nStateImageMask)
  128. {
  129. int nImage=(nStateImageMask>>12)-1;
  130. pImageList=GetImageList(LVSIL_STATE);
  131. if(pImageList)
  132. pImageList->Draw(pDC,nImage,CPoint(rcItem.left,rcItem.top),ILD_TRANSPARENT);
  133. }
  134. // draw normal and overlay icon
  135. CRect rcIcon;
  136. GetItemRect(nItem,rcIcon,LVIR_ICON);
  137. pImageList=GetImageList(LVSIL_SMALL);
  138. if(pImageList)
  139. {
  140. UINT nOvlImageMask=lvi.state & LVIS_OVERLAYMASK;
  141. if(rcItem.left<rcItem.right-1)
  142. ImageList_DrawEx(pImageList->m_hImageList,lvi.iImage,pDC->m_hDC,rcIcon.left,rcIcon.top,16,16,m_clrBkgnd,clrImage,uiFlags | nOvlImageMask);
  143. }
  144. // draw item label
  145. GetItemRect(nItem,rcItem,LVIR_LABEL);
  146. rcItem.right-=m_cxStateImageOffset;
  147. pszText=MakeShortString(pDC,szBuff,rcItem.right-rcItem.left,2*OFFSET_FIRST);
  148. rcLabel=rcItem;
  149. rcLabel.left+=OFFSET_FIRST;
  150. rcLabel.right-=OFFSET_FIRST;
  151. pDC->DrawText(pszText,-1,rcLabel,DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
  152. // draw labels for extra columns
  153. LV_COLUMN lvc;
  154. lvc.mask=LVCF_FMT | LVCF_WIDTH;
  155. for(int nColumn=1; GetColumn(nColumn,&lvc); nColumn++)
  156. {
  157. rcItem.left=rcItem.right;
  158. rcItem.right+=lvc.cx;
  159.   int nRetLen=GetItemText(nItem,nColumn,szBuff,sizeof(szBuff));
  160. if(nRetLen==0) continue;
  161. pszText=MakeShortString(pDC,szBuff,rcItem.right-rcItem.left,2*OFFSET_OTHER);
  162. UINT nJustify=DT_LEFT;
  163. if(pszText==szBuff)
  164. {
  165. switch(lvc.fmt & LVCFMT_JUSTIFYMASK)
  166. {
  167. case LVCFMT_RIGHT:
  168. nJustify=DT_RIGHT;
  169. break;
  170. case LVCFMT_CENTER:
  171. nJustify=DT_CENTER;
  172. break;
  173. default:
  174. break;
  175. }
  176. }
  177. rcLabel=rcItem;
  178. rcLabel.left+=OFFSET_OTHER;
  179. rcLabel.right-=OFFSET_OTHER;
  180. pDC->DrawText(pszText,-1,rcLabel,nJustify | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
  181. }
  182. // draw focus rectangle if item has focus
  183. if(lvi.state & LVIS_FOCUSED && bFocus)
  184. pDC->DrawFocusRect(rcAllLabels);
  185. // set original colors if item was selected
  186. if(bSelected)
  187. {
  188.         pDC->SetTextColor(clrTextSave);
  189. pDC->SetBkColor(clrBkSave);
  190. }
  191. }
  192. LPCTSTR CListCtrlEx::MakeShortString(CDC* pDC, LPCTSTR lpszLong, int nColumnLen, int nOffset)
  193. {
  194. static const _TCHAR szThreeDots[]=_T("...");
  195. int nStringLen=lstrlen(lpszLong);
  196. if(nStringLen==0 || pDC->GetTextExtent(lpszLong,nStringLen).cx+nOffset<=nColumnLen)
  197. return(lpszLong);
  198. static _TCHAR szShort[MAX_PATH];
  199. lstrcpy(szShort,lpszLong);
  200. int nAddLen=pDC->GetTextExtent(szThreeDots,sizeof(szThreeDots)).cx;
  201. for(int i=nStringLen-1; i>0; i--)
  202. {
  203. szShort[i]=0;
  204. if(pDC->GetTextExtent(szShort,i).cx+nOffset+nAddLen<=nColumnLen)
  205. break;
  206. }
  207. lstrcat(szShort,szThreeDots);
  208. return(szShort);
  209. }
  210. void CListCtrlEx::RepaintSelectedItems()
  211. {
  212. CRect rcItem, rcLabel;
  213. // invalidate focused item so it can repaint properly
  214. int nItem=GetNextItem(-1,LVNI_FOCUSED);
  215. if(nItem!=-1)
  216. {
  217. GetItemRect(nItem,rcItem,LVIR_BOUNDS);
  218. GetItemRect(nItem,rcLabel,LVIR_LABEL);
  219. rcItem.left=rcLabel.left;
  220. InvalidateRect(rcItem,FALSE);
  221. }
  222. // if selected items should not be preserved, invalidate them
  223. if(!(GetStyle() & LVS_SHOWSELALWAYS))
  224. {
  225. for(nItem=GetNextItem(-1,LVNI_SELECTED);
  226. nItem!=-1; nItem=GetNextItem(nItem,LVNI_SELECTED))
  227. {
  228. GetItemRect(nItem,rcItem,LVIR_BOUNDS);
  229. GetItemRect(nItem,rcLabel,LVIR_LABEL);
  230. rcItem.left=rcLabel.left;
  231. InvalidateRect(rcItem,FALSE);
  232. }
  233. }
  234. // update changes 
  235. UpdateWindow();
  236. }
  237. /////////////////////////////////////////////////////////////////////////////
  238. // CListCtrlEx diagnostics
  239. #ifdef _DEBUG
  240. void CListCtrlEx::Dump(CDumpContext& dc) const
  241. {
  242. CListCtrl::Dump(dc);
  243. dc << "m_bFullRowSel = " << (UINT)m_bFullRowSel;
  244. dc << "n";
  245. dc << "m_cxStateImageOffset = " << m_cxStateImageOffset;
  246. dc << "n";
  247. }
  248. #endif //_DEBUG
  249. /////////////////////////////////////////////////////////////////////////////
  250. // CListCtrlEx message handlers
  251. LRESULT CListCtrlEx::OnSetImageList(WPARAM wParam, LPARAM lParam)
  252. {
  253. if((int)wParam==LVSIL_STATE)
  254. {
  255. int cx, cy;
  256. if(::ImageList_GetIconSize((HIMAGELIST)lParam,&cx,&cy))
  257. m_cxStateImageOffset=cx;
  258. else
  259. m_cxStateImageOffset=0;
  260. }
  261. return(Default());
  262. }
  263. LRESULT CListCtrlEx::OnSetTextColor(WPARAM wParam, LPARAM lParam)
  264. {
  265. m_clrText=(COLORREF)lParam;
  266. return(Default());
  267. }
  268. LRESULT CListCtrlEx::OnSetTextBkColor(WPARAM wParam, LPARAM lParam)
  269. {
  270. m_clrTextBk=(COLORREF)lParam;
  271. return(Default());
  272. }
  273. LRESULT CListCtrlEx::OnSetBkColor(WPARAM wParam, LPARAM lParam)
  274. {
  275. m_clrBkgnd=(COLORREF)lParam;
  276. return(Default());
  277. }
  278. void CListCtrlEx::OnSize(UINT nType, int cx, int cy) 
  279. {
  280. m_cxClient=cx;
  281. CListCtrl::OnSize(nType, cx, cy);
  282. }
  283. void CListCtrlEx::OnPaint() 
  284. {
  285. // in full row select mode, we need to extend the clipping region
  286. // so we can paint a selection all the way to the right
  287. if(m_bClientWidthSel && (GetStyle() & LVS_TYPEMASK)==LVS_REPORT && GetFullRowSel())
  288. {
  289. CRect rcAllLabels;
  290. GetItemRect(0,rcAllLabels,LVIR_BOUNDS);
  291. if(rcAllLabels.right<m_cxClient)
  292. {
  293. // need to call BeginPaint (in CPaintDC c-tor)
  294. // to get correct clipping rect
  295. CPaintDC dc(this);
  296. CRect rcClip;
  297. dc.GetClipBox(rcClip);
  298. rcClip.left=min(rcAllLabels.right-1,rcClip.left);
  299. rcClip.right=m_cxClient;
  300. InvalidateRect(rcClip,FALSE);
  301. // EndPaint will be called in CPaintDC d-tor
  302. }
  303. }
  304. CListCtrl::OnPaint();
  305. }
  306. void CListCtrlEx::OnSetFocus(CWnd* pOldWnd) 
  307. {
  308. CListCtrl::OnSetFocus(pOldWnd);
  309. // check if we are getting focus from label edit box
  310. if(pOldWnd!=NULL && pOldWnd->GetParent()==this)
  311. return;
  312. // repaint items that should change appearance
  313. if(m_bFullRowSel && (GetStyle() & LVS_TYPEMASK)==LVS_REPORT)
  314. RepaintSelectedItems();
  315. }
  316. void CListCtrlEx::OnKillFocus(CWnd* pNewWnd) 
  317. {
  318. CListCtrl::OnKillFocus(pNewWnd);
  319. // check if we are losing focus to label edit box
  320. if(pNewWnd!=NULL && pNewWnd->GetParent()==this)
  321. return;
  322. // repaint items that should change appearance
  323. if(m_bFullRowSel && (GetStyle() & LVS_TYPEMASK)==LVS_REPORT)
  324. RepaintSelectedItems();
  325. }
  326. void CListCtrlEx::PreSubclassWindow() 
  327. {
  328. CListCtrl::PreSubclassWindow();
  329. EnableToolTips(TRUE);
  330. }
  331. int CListCtrlEx::CellRectFromPoint(CPoint& point, CRect* pRectCell, int* pCol) const
  332. {
  333.     if((::GetWindowLong(m_hWnd, GWL_STYLE) & LVS_TYPEMASK) != LVS_REPORT )
  334.    return -1;
  335.     int nRow = GetTopIndex();
  336.     int nBottom = nRow + GetCountPerPage();
  337.     if(nBottom > GetItemCount())
  338. nBottom = GetItemCount();
  339.         
  340.     CHeaderCtrl* pHeader = (CHeaderCtrl*)GetDlgItem(0);
  341.     int nColumnCount = pHeader->GetItemCount();
  342.     for(; nRow <= nBottom; nRow++)
  343.     {
  344.         CRect rect;
  345.         GetItemRect(nRow, &rect, LVIR_BOUNDS);
  346.         if(rect.PtInRect(point))
  347.         {
  348. for(int nColumn = 0; nColumn < nColumnCount; nColumn++)
  349. {
  350. int nColWidth = GetColumnWidth(nColumn);
  351. if(point.x >= rect.left && point.x <= (rect.left + nColWidth))
  352. {
  353. CRect rectClient;
  354. GetClientRect(&rectClient);
  355. if(pCol)
  356. *pCol = nColumn;
  357. rect.right = rect.left + nColWidth;
  358. if(rect.right > rectClient.right) 
  359. rect.right = rectClient.right;
  360. *pRectCell = rect;
  361. return nRow;
  362. }
  363. rect.left += nColWidth;
  364. }
  365. }
  366. }
  367. return -1;
  368. }
  369. BOOL CListCtrlEx::OnToolTipText(UINT /*uID*/, NMHDR* pNMHDR, LRESULT* pResult)
  370. {
  371.     BOOL bRet = TRUE;
  372. #ifdef _TOOL_TIP_ENABLE
  373. TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
  374.     TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
  375.     UINT nID = pNMHDR->idFrom;
  376.     if(!nID)
  377.      bRet = FALSE;
  378. if(bRet)
  379. {
  380. int nRow = ((nID-1) >> 10) & 0x3fffff ;
  381. int nCol = (nID-1) & 0x3ff;
  382. CString strTipText = GetItemText(nRow, nCol);
  383. strTipText.TrimRight();
  384. strTipText.TrimLeft();
  385. #ifndef _UNICODE
  386. if (pNMHDR->code == TTN_NEEDTEXTA)
  387. lstrcpyn(pTTTA->szText, strTipText, 80);
  388. else
  389. _mbstowcsz(pTTTW->szText, strTipText, 80);
  390. #else
  391. if(pNMHDR->code == TTN_NEEDTEXTA)
  392. _wcstombsz(pTTTA->szText, strTipText, 80);
  393. else
  394. lstrcpyn(pTTTW->szText, strTipText, 80);
  395. #endif
  396. }
  397.     
  398. *pResult = 0;
  399. #endif
  400.     return bRet;
  401. }
  402. int CListCtrlEx::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
  403. {
  404. int nID = -1;
  405. #ifdef _TOOL_TIP_ENABLE
  406. int nCol;
  407. CRect rect;
  408. int nRow = CellRectFromPoint(point, &rect, &nCol);
  409. if(nRow == -1 ) 
  410. return -1;
  411. pTI->hwnd = m_hWnd;
  412. pTI->uId = (UINT)((nRow << 10) + (nCol & 0x3ff) + 1);
  413. nID = pTI->uId
  414. pTI->lpszText = LPSTR_TEXTCALLBACK;
  415. pTI->rect = rect;
  416. #endif
  417. return nID;
  418. }