SortListCtrl.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708
  1. #include "stdafx.h"
  2. #include "SortListCtrl.h"
  3. #ifdef _DEBUG
  4. #define new DEBUG_NEW
  5. #undef THIS_FILE
  6. static char THIS_FILE[] = __FILE__;
  7. #endif
  8. #define ID_LIST_PRINT 200
  9. #define ID_LIST_SAVE 201
  10. #define ID_LIST_DELETE 202
  11. #define ID_LIST_DELETEALL 203
  12. LPCTSTR g_pszSection = _T("ListCtrls");
  13. struct ItemData
  14. {
  15. public:
  16. ItemData() : arrpsz( NULL ), dwData( NULL ),crText ( NULL ),crBak (NULL) {}
  17. LPTSTR* arrpsz;
  18. DWORD dwData;
  19. //color
  20. COLORREF * crText;
  21. COLORREF * crBak;
  22. private:
  23. // ban copying.
  24. ItemData( const ItemData& );
  25. ItemData& operator=( const ItemData& );
  26. };
  27. CSortListCtrl::CSortListCtrl()
  28. : m_iNumColumns( 0 )
  29. , m_iSortColumn( -1 )
  30. , m_bSortAscending( TRUE )
  31. {
  32. crWindow = ::GetSysColor(COLOR_WINDOW);
  33. crWindowText = ::GetSysColor(COLOR_WINDOWFRAME);
  34. crHighLight = ::GetSysColor(COLOR_HIGHLIGHT);
  35. crHighLightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
  36. }
  37. CSortListCtrl::~CSortListCtrl()
  38. {
  39. }
  40. BEGIN_MESSAGE_MAP(CSortListCtrl, CListCtrl)
  41. //{{AFX_MSG_MAP(CSortListCtrl)
  42. ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
  43. ON_WM_DESTROY()
  44. ON_WM_RBUTTONDOWN()
  45. ON_WM_PAINT()
  46. ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
  47. ON_WM_SYSCOLORCHANGE()
  48. //}}AFX_MSG_MAP
  49. END_MESSAGE_MAP()
  50. /////////////////////////////////////////////////////////////////////////////
  51. // CSortListCtrl message handlers
  52. void CSortListCtrl::PreSubclassWindow()
  53. {
  54. // the list control must have the report style.
  55. ASSERT( GetStyle() & LVS_REPORT );
  56. CListCtrl::PreSubclassWindow();
  57. VERIFY( m_ctlHeader.SubclassWindow( GetHeaderCtrl()->GetSafeHwnd() ) );
  58. }
  59. BOOL CSortListCtrl::SetHeadings( UINT uiStringID )
  60. {
  61. CString strHeadings;
  62. VERIFY( strHeadings.LoadString( uiStringID ) );
  63. return SetHeadings( strHeadings );
  64. }
  65. // the heading text is in the format column 1 text,column 1 width;column 2 text,column 3 width;etc.
  66. BOOL CSortListCtrl::SetHeadings( const CString& strHeadings )
  67. {
  68. int iStart = 0;
  69. for( ;; )
  70. {
  71. const int iComma = strHeadings.Find( _T(','), iStart );
  72. if( iComma == -1 )
  73. break;
  74. const CString strHeading = strHeadings.Mid( iStart, iComma - iStart );
  75. iStart = iComma + 1;
  76. int iSemiColon = strHeadings.Find( _T(';'), iStart );
  77. if( iSemiColon == -1 )
  78. iSemiColon = strHeadings.GetLength();
  79. const int iWidth = atoi( strHeadings.Mid( iStart, iSemiColon - iStart ) );
  80. iStart = iSemiColon + 1;
  81. if( InsertColumn( m_iNumColumns++, strHeading, LVCFMT_LEFT, iWidth ) == -1 )
  82. return FALSE;
  83. }
  84. return TRUE;
  85. }
  86. int CSortListCtrl::AddItem( LPCTSTR pszText, ... )
  87. {
  88. int nItemCount = GetItemCount();
  89. const int iIndex = InsertItem( nItemCount, pszText );
  90. LPTSTR* arrpsz = new LPTSTR[ m_iNumColumns ];
  91. COLORREF * clrText = new COLORREF[ m_iNumColumns ];
  92. COLORREF * clrBak= new COLORREF[ m_iNumColumns ];
  93. arrpsz[ 0 ] = new TCHAR[ lstrlen( pszText ) + 1 ];
  94. clrText[ 0 ] = crWindowText;
  95. clrBak[ 0 ] = crWindow;
  96. (void)lstrcpy( arrpsz[ 0 ], pszText );
  97. va_list list;
  98. va_start( list, pszText );
  99. //insert sub item and set subitem data
  100. for( int iColumn = 1; iColumn < m_iNumColumns; iColumn++ )
  101. {
  102. pszText = va_arg( list, LPCTSTR );
  103. ASSERT_VALID_STRING( pszText );
  104. VERIFY( CListCtrl::SetItem( iIndex, iColumn, LVIF_TEXT, pszText, 0, 0, 0, 0 ) );
  105. arrpsz[ iColumn ] = new TCHAR[ lstrlen( pszText ) + 1 ];
  106. clrText[ iColumn ] = crWindowText;
  107. clrBak[ iColumn ] = crWindow;
  108. (void)lstrcpy( arrpsz[ iColumn ], pszText );
  109. }
  110. va_end( list );
  111. VERIFY( SetArray( iIndex, arrpsz,clrText,clrBak ) );
  112. return iIndex;
  113. }
  114. void CSortListCtrl::FreeItemMemory( const int iItem )
  115. {
  116. ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( iItem ) );
  117. LPTSTR* arrpsz = pid->arrpsz;
  118. for( int i = 0; i < m_iNumColumns; i++ )
  119. {
  120. delete[] arrpsz[ i ];
  121. }
  122. delete[] pid->crText;
  123. delete[] pid->crBak;
  124. delete[] arrpsz;
  125. delete pid;
  126. VERIFY( CListCtrl::SetItemData( iItem, NULL ) );
  127. }
  128. BOOL CSortListCtrl::DeleteItem( int iItem )
  129. {
  130. FreeItemMemory( iItem );
  131. return CListCtrl::DeleteItem( iItem );
  132. }
  133. BOOL CSortListCtrl::DeleteAllItems()
  134. {
  135. for( int iItem = 0; iItem < GetItemCount(); iItem ++ )
  136. FreeItemMemory( iItem );
  137. return CListCtrl::DeleteAllItems();
  138. }
  139. bool IsNumber( LPCTSTR pszText )
  140. {
  141. ASSERT_VALID_STRING( pszText );
  142. for( int i = 0; i < lstrlen( pszText ); i++ )
  143. if( !_istdigit( pszText[ i ] ) )
  144. return false;
  145. return true;
  146. }
  147. int NumberCompare( LPCTSTR pszNumber1, LPCTSTR pszNumber2 )
  148. {
  149. ASSERT_VALID_STRING( pszNumber1 );
  150. ASSERT_VALID_STRING( pszNumber2 );
  151. const int iNumber1 = atoi( pszNumber1 );
  152. const int iNumber2 = atoi( pszNumber2 );
  153. if( iNumber1 < iNumber2 )
  154. return -1;
  155. if( iNumber1 > iNumber2 )
  156. return 1;
  157. return 0;
  158. }
  159. bool IsDate( LPCTSTR pszText )
  160. {
  161. ASSERT_VALID_STRING( pszText );
  162. // format should be 99/99/9999.
  163. if( lstrlen( pszText ) != 10 )
  164. return false;
  165. return _istdigit( pszText[ 0 ] )
  166. && _istdigit( pszText[ 1 ] )
  167. && pszText[ 2 ] == _T('/')
  168. && _istdigit( pszText[ 3 ] )
  169. && _istdigit( pszText[ 4 ] )
  170. && pszText[ 5 ] == _T('/')
  171. && _istdigit( pszText[ 6 ] )
  172. && _istdigit( pszText[ 7 ] )
  173. && _istdigit( pszText[ 8 ] )
  174. && _istdigit( pszText[ 9 ] );
  175. }
  176. int DateCompare( const CString& strDate1, const CString& strDate2 )
  177. {
  178. const int iYear1 = atoi( strDate1.Mid( 6, 4 ) );
  179. const int iYear2 = atoi( strDate2.Mid( 6, 4 ) );
  180. if( iYear1 < iYear2 )
  181. return -1;
  182. if( iYear1 > iYear2 )
  183. return 1;
  184. const int iMonth1 = atoi( strDate1.Mid( 3, 2 ) );
  185. const int iMonth2 = atoi( strDate2.Mid( 3, 2 ) );
  186. if( iMonth1 < iMonth2 )
  187. return -1;
  188. if( iMonth1 > iMonth2 )
  189. return 1;
  190. const int iDay1 = atoi( strDate1.Mid( 0, 2 ) );
  191. const int iDay2 = atoi( strDate2.Mid( 0, 2 ) );
  192. if( iDay1 < iDay2 )
  193. return -1;
  194. if( iDay1 > iDay2 )
  195. return 1;
  196. return 0;
  197. }
  198. int CALLBACK CSortListCtrl::CompareFunction( LPARAM lParam1, LPARAM lParam2, LPARAM lParamData )
  199. {
  200. CSortListCtrl* pListCtrl = reinterpret_cast<CSortListCtrl*>( lParamData );
  201. ASSERT( pListCtrl->IsKindOf( RUNTIME_CLASS( CListCtrl ) ) );
  202. ItemData* pid1 = reinterpret_cast<ItemData*>( lParam1 );
  203. ItemData* pid2 = reinterpret_cast<ItemData*>( lParam2 );
  204. ASSERT( pid1 );
  205. ASSERT( pid2 );
  206. LPCTSTR pszText1 = pid1->arrpsz[ pListCtrl->m_iSortColumn ];
  207. LPCTSTR pszText2 = pid2->arrpsz[ pListCtrl->m_iSortColumn ];
  208. ASSERT_VALID_STRING( pszText1 );
  209. ASSERT_VALID_STRING( pszText2 );
  210. if( IsNumber( pszText1 ) )
  211. return pListCtrl->m_bSortAscending ? NumberCompare( pszText1, pszText2 ) : NumberCompare( pszText2, pszText1 );
  212. else if( IsDate( pszText1 ) )
  213. return pListCtrl->m_bSortAscending ? DateCompare( pszText1, pszText2 ) : DateCompare( pszText2, pszText1 );
  214. else
  215. // text.
  216. return pListCtrl->m_bSortAscending ? lstrcmp( pszText1, pszText2 ) : lstrcmp( pszText2, pszText1 );
  217. }
  218. void CSortListCtrl::OnColumnClick( NMHDR* pNMHDR, LRESULT* pResult )
  219. {
  220. NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
  221. const int iColumn = pNMListView->iSubItem;
  222. // if it's a second click on the same column then reverse the sort order,
  223. // otherwise sort the new column in ascending order.
  224. Sort( iColumn, iColumn == m_iSortColumn ? !m_bSortAscending : TRUE );
  225. *pResult = 0;
  226. }
  227. void CSortListCtrl::Sort( int iColumn, BOOL bAscending )
  228. {
  229. m_iSortColumn = iColumn;
  230. m_bSortAscending = bAscending;
  231. // show the appropriate arrow in the header control.
  232. m_ctlHeader.SetSortArrow( m_iSortColumn, m_bSortAscending );
  233. VERIFY( SortItems( CompareFunction, reinterpret_cast<DWORD>( this ) ) );
  234. }
  235. void CSortListCtrl::LoadColumnInfo()
  236. {
  237. // you must call this after setting the column headings.
  238. ASSERT( m_iNumColumns > 0 );
  239. CString strKey;
  240. strKey.Format( _T("%d"), GetDlgCtrlID() );
  241. UINT nBytes = 0;
  242. BYTE* buf = NULL;
  243. if( AfxGetApp()->GetProfileBinary( g_pszSection, strKey, &buf, &nBytes ) )
  244. {
  245. if( nBytes > 0 )
  246. {
  247. CMemFile memFile( buf, nBytes );
  248. CArchive ar( &memFile, CArchive::load );
  249. m_ctlHeader.Serialize( ar );
  250. ar.Close();
  251. m_ctlHeader.Invalidate();
  252. }
  253. delete[] buf;
  254. }
  255. }
  256. void CSortListCtrl::SaveColumnInfo()
  257. {
  258. ASSERT( m_iNumColumns > 0 );
  259. CString strKey;
  260. strKey.Format( _T("%d"), GetDlgCtrlID() );
  261. CMemFile memFile;
  262. CArchive ar( &memFile, CArchive::store );
  263. m_ctlHeader.Serialize( ar );
  264. ar.Close();
  265. DWORD dwLen = (DWORD)memFile.GetLength();
  266. BYTE* buf = memFile.Detach();
  267. VERIFY( AfxGetApp()->WriteProfileBinary( g_pszSection, strKey, buf, dwLen ) );
  268. free( buf );
  269. }
  270. void CSortListCtrl::OnDestroy()
  271. {
  272. for( int iItem = 0; iItem < GetItemCount(); iItem ++ )
  273. FreeItemMemory( iItem );
  274. CListCtrl::OnDestroy();
  275. }
  276. BOOL CSortListCtrl::SetItemText( int nItem, int nSubItem, LPCTSTR lpszText )
  277. {
  278. SetRedraw(FALSE);
  279. if( !CListCtrl::SetItemText( nItem, nSubItem, lpszText ) )
  280. return FALSE;
  281. LPTSTR* arrpsz = GetTextArray( nItem );
  282. LPTSTR pszText = arrpsz[ nSubItem ];
  283. delete[] pszText;
  284. pszText = new TCHAR[ lstrlen( lpszText ) + 1 ];
  285. (void)lstrcpy( pszText, lpszText );
  286. arrpsz[ nSubItem ] = pszText;
  287. SetRedraw(TRUE);
  288. return TRUE;
  289. }
  290. BOOL CSortListCtrl::SetItemData( int nItem, DWORD dwData )
  291. {
  292. /*
  293. if( nItem >= GetItemCount() )
  294. return FALSE;
  295. ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( nItem ) );
  296. ASSERT( pid );
  297. pid->dwData = dwData;
  298. return TRUE;*/
  299. CListCtrl::SetItemData( nItem, dwData);
  300. return TRUE;
  301. }
  302. DWORD CSortListCtrl::GetItemData( int nItem ) const
  303. {
  304. ASSERT( nItem < GetItemCount() );
  305. ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( nItem ) );
  306. ASSERT( pid );
  307. return pid->dwData;
  308. }
  309. BOOL CSortListCtrl::SetArray( int iItem, LPTSTR* arrpsz,COLORREF * clrText,COLORREF * clrBak )
  310. {
  311. ASSERT( CListCtrl::GetItemData( iItem ) == NULL );
  312. ItemData* pid = new ItemData;
  313. pid->arrpsz = arrpsz;
  314. pid->crText = clrText;
  315. pid->crBak = clrBak;
  316. return CListCtrl::SetItemData( iItem, reinterpret_cast<DWORD>( pid ) );//set item data /
  317. }
  318. LPTSTR* CSortListCtrl::GetTextArray( int iItem ) const
  319. {
  320. ASSERT( iItem < GetItemCount() );
  321. ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( iItem ) );
  322. return pid->arrpsz;
  323. }
  324. void CSortListCtrl::OnPaint()
  325. {
  326. Default();
  327. // TODO: Add your message handler code here
  328. // Do not call CListCtrl::OnPaint() for painting messages
  329. }
  330. void CSortListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
  331. {
  332. //draw each item.set txt color,bkcolor....
  333. SetRedraw(FALSE);
  334. NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
  335. // Take the default processing unless we set this to something else below.
  336. *pResult = CDRF_DODEFAULT;
  337. // First thing - check the draw stage. If it's the control's prepaint
  338. // stage, then tell Windows we want messages for every item.
  339. if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT)
  340. {
  341. *pResult = CDRF_NOTIFYITEMDRAW;
  342. }
  343. else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
  344. {
  345. // This is the notification message for an item. We'll request
  346. // notifications before each subitem's prepaint stage.
  347. *pResult = CDRF_NOTIFYSUBITEMDRAW;
  348. }
  349. else if (pLVCD->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM))
  350. {
  351. // This is the prepaint stage for a subitem. Here's where we set the
  352. // item's text and background colors. Our return value will tell
  353. // Windows to draw the subitem itself, but it will use the new colors
  354. // we set here.
  355. int nItem = static_cast<int> (pLVCD->nmcd.dwItemSpec);
  356. int nSubItem = pLVCD->iSubItem;
  357. ItemData *pXLCD = (ItemData *) pLVCD->nmcd.lItemlParam;
  358. #if 0 //增加下面语句出错用户断点异常,待改进
  359. ASSERT(pXLCD);
  360. #endif
  361. COLORREF crText = crWindowText;
  362. COLORREF crBkgnd = crWindow;
  363. if (pXLCD){
  364. crText = (pXLCD->crText)[nSubItem];
  365. crBkgnd = (pXLCD->crBak)[nSubItem];
  366. }
  367. // store the colors back in the NMLVCUSTOMDRAW struct
  368. pLVCD->clrText = crText;
  369. pLVCD->clrTextBk = crBkgnd;
  370. CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
  371. CRect rect;
  372. GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);
  373. if (GetItemState(nItem, LVIS_SELECTED))
  374. DrawText(nItem, nSubItem, pDC, crHighLightText, crHighLight , rect);
  375. else
  376. DrawText(nItem, nSubItem, pDC, crText, crBkgnd, rect);
  377. //2011-10-31 add
  378. //DeleteObject( pDC ); //?????
  379. *pResult = CDRF_SKIPDEFAULT; // We've painted everything.
  380. }
  381. SetRedraw(TRUE);
  382. }
  383. int CSortListCtrl::AddItemColor(LPCTSTR pszText, COLORREF crText, COLORREF crBak)
  384. {
  385. //insert item at the last
  386. const int iIndex = InsertItem( GetItemCount(), pszText );
  387. ItemData *m_pSortItemData=new ItemData[GetColumns()];
  388. /*
  389. m_pSortItemData[0].crText=crText;
  390. m_pSortItemData[0].crBak=crBak;
  391. */
  392. SetItemData(iIndex,(DWORD) m_pSortItemData);
  393. //no sort function
  394. return iIndex;
  395. }
  396. int CSortListCtrl::GetColumns()
  397. {
  398. return m_ctlHeader.GetItemCount();
  399. }
  400. BOOL CSortListCtrl::GetSubItemRect(int nItem, int nSubItem, int nArea, CRect &rect)
  401. {
  402. ASSERT(nItem >= 0);
  403. ASSERT(nItem < GetItemCount());
  404. if ((nItem < 0) || nItem >= GetItemCount())
  405. return FALSE;
  406. ASSERT(nSubItem >= 0);
  407. ASSERT(nSubItem < GetColumns());
  408. if ((nSubItem < 0) || nSubItem >= GetColumns())
  409. return FALSE;
  410. BOOL bRC = CListCtrl::GetSubItemRect(nItem, nSubItem, nArea, rect);
  411. // if nSubItem == 0, the rect returned by CListCtrl::GetSubItemRect
  412. // is the entire row, so use left edge of second subitem
  413. if (nSubItem == 0)
  414. {
  415. if (GetColumns() > 1)
  416. {
  417. CRect rect1;
  418. bRC = GetSubItemRect(nItem, 1, LVIR_BOUNDS, rect1);
  419. rect.right = rect1.left;
  420. }
  421. }
  422. return bRC;
  423. }
  424. void CSortListCtrl::DrawText(int nItem, int nSubItem, CDC *pDC, COLORREF crText, COLORREF crBkgnd, CRect &rect)
  425. {
  426. ASSERT(pDC);
  427. // GetDrawColors(nItem, nSubItem, crText, crBkgnd);
  428. pDC->FillSolidRect(&rect, crBkgnd);
  429. CString str;
  430. str = GetItemText(nItem, nSubItem);
  431. if (!str.IsEmpty())
  432. {
  433. // get text justification
  434. HDITEM hditem;
  435. hditem.mask = HDI_FORMAT;
  436. m_ctlHeader.GetItem(nSubItem, &hditem);
  437. int nFmt = hditem.fmt & HDF_JUSTIFYMASK;
  438. UINT nFormat = DT_VCENTER | DT_SINGLELINE;
  439. if (nFmt == HDF_CENTER)
  440. nFormat |= DT_CENTER;
  441. else if (nFmt == HDF_LEFT)
  442. nFormat |= DT_LEFT;
  443. else
  444. nFormat |= DT_RIGHT;
  445. pDC->SetBkMode(TRANSPARENT);
  446. pDC->SetTextColor(crText);
  447. pDC->SetBkColor(crBkgnd);
  448. pDC->DrawText(str, &rect, nFormat);
  449. }
  450. }
  451. void CSortListCtrl::OnSysColorChange()
  452. {
  453. CListCtrl::OnSysColorChange();
  454. // TODO: Add your message handler code here
  455. crWindow = ::GetSysColor(COLOR_WINDOW);
  456. crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  457. crHighLight = ::GetSysColor(COLOR_HIGHLIGHT);
  458. crHighLightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
  459. }
  460. void CSortListCtrl::SetItemColor(int nItem, int nSubItem, COLORREF clrText, COLORREF clrBkgnd)
  461. {
  462. ASSERT(nItem >= 0);
  463. int nItemCount = GetItemCount();
  464. #if 0 //增加下面语句出错用户断点异常,待改进
  465. ASSERT(nItem < nItemCount);
  466. #endif
  467. if ((nItem < 0) || nItem >= GetItemCount())
  468. return ;
  469. ASSERT(nSubItem >= 0);
  470. ASSERT(nSubItem < GetColumns());
  471. if ((nSubItem < 0) || nSubItem >= GetColumns())
  472. return ;
  473. if (nItem < 0)
  474. return ;
  475. ItemData *pid = (ItemData *) CListCtrl::GetItemData(nItem);
  476. if (pid)
  477. {
  478. (pid->crText)[nSubItem] = (clrText == -1) ? crWindowText : clrText;
  479. (pid->crBak)[nSubItem] = (clrBkgnd == -1) ? crWindow : clrBkgnd;
  480. }
  481. UpdateSubItem(nItem, nSubItem);
  482. }
  483. void CSortListCtrl::UpdateSubItem(int nItem, int nSubItem)
  484. {
  485. ASSERT(nItem >= 0);
  486. ASSERT(nItem < GetItemCount());
  487. if ((nItem < 0) || nItem >= GetItemCount())
  488. return;
  489. ASSERT(nSubItem >= 0);
  490. ASSERT(nSubItem < GetColumns());
  491. if ((nSubItem < 0) || nSubItem >= GetColumns())
  492. return;
  493. CRect rect;
  494. if (nSubItem == -1)
  495. {
  496. GetItemRect(nItem, &rect, LVIR_BOUNDS);
  497. }
  498. else
  499. {
  500. GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);
  501. }
  502. InvalidateRect(&rect);
  503. UpdateWindow();
  504. }