123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708 |
- #include "stdafx.h"
- #include "SortListCtrl.h"
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- #define ID_LIST_PRINT 200
- #define ID_LIST_SAVE 201
- #define ID_LIST_DELETE 202
- #define ID_LIST_DELETEALL 203
- LPCTSTR g_pszSection = _T("ListCtrls");
- struct ItemData
- {
- public:
- ItemData() : arrpsz( NULL ), dwData( NULL ),crText ( NULL ),crBak (NULL) {}
- LPTSTR* arrpsz;
- DWORD dwData;
- //color
- COLORREF * crText;
- COLORREF * crBak;
-
- private:
- // ban copying.
- ItemData( const ItemData& );
- ItemData& operator=( const ItemData& );
- };
- CSortListCtrl::CSortListCtrl()
- : m_iNumColumns( 0 )
- , m_iSortColumn( -1 )
- , m_bSortAscending( TRUE )
- {
- crWindow = ::GetSysColor(COLOR_WINDOW);
- crWindowText = ::GetSysColor(COLOR_WINDOWFRAME);
- crHighLight = ::GetSysColor(COLOR_HIGHLIGHT);
- crHighLightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
-
- }
- CSortListCtrl::~CSortListCtrl()
- {
- }
- BEGIN_MESSAGE_MAP(CSortListCtrl, CListCtrl)
- //{{AFX_MSG_MAP(CSortListCtrl)
- ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
- ON_WM_DESTROY()
- ON_WM_RBUTTONDOWN()
- ON_WM_PAINT()
- ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
- ON_WM_SYSCOLORCHANGE()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- /////////////////////////////////////////////////////////////////////////////
- // CSortListCtrl message handlers
- void CSortListCtrl::PreSubclassWindow()
- {
- // the list control must have the report style.
- ASSERT( GetStyle() & LVS_REPORT );
- CListCtrl::PreSubclassWindow();
- VERIFY( m_ctlHeader.SubclassWindow( GetHeaderCtrl()->GetSafeHwnd() ) );
- }
- BOOL CSortListCtrl::SetHeadings( UINT uiStringID )
- {
- CString strHeadings;
- VERIFY( strHeadings.LoadString( uiStringID ) );
- return SetHeadings( strHeadings );
- }
- // the heading text is in the format column 1 text,column 1 width;column 2 text,column 3 width;etc.
- BOOL CSortListCtrl::SetHeadings( const CString& strHeadings )
- {
- int iStart = 0;
- for( ;; )
- {
- const int iComma = strHeadings.Find( _T(','), iStart );
- if( iComma == -1 )
- break;
- const CString strHeading = strHeadings.Mid( iStart, iComma - iStart );
- iStart = iComma + 1;
- int iSemiColon = strHeadings.Find( _T(';'), iStart );
- if( iSemiColon == -1 )
- iSemiColon = strHeadings.GetLength();
- const int iWidth = atoi( strHeadings.Mid( iStart, iSemiColon - iStart ) );
-
- iStart = iSemiColon + 1;
- if( InsertColumn( m_iNumColumns++, strHeading, LVCFMT_LEFT, iWidth ) == -1 )
- return FALSE;
- }
- return TRUE;
- }
- int CSortListCtrl::AddItem( LPCTSTR pszText, ... )
- {
- int nItemCount = GetItemCount();
-
- const int iIndex = InsertItem( nItemCount, pszText );
- LPTSTR* arrpsz = new LPTSTR[ m_iNumColumns ];
- COLORREF * clrText = new COLORREF[ m_iNumColumns ];
- COLORREF * clrBak= new COLORREF[ m_iNumColumns ];
- arrpsz[ 0 ] = new TCHAR[ lstrlen( pszText ) + 1 ];
- clrText[ 0 ] = crWindowText;
- clrBak[ 0 ] = crWindow;
- (void)lstrcpy( arrpsz[ 0 ], pszText );
- va_list list;
- va_start( list, pszText );
- //insert sub item and set subitem data
- for( int iColumn = 1; iColumn < m_iNumColumns; iColumn++ )
- {
- pszText = va_arg( list, LPCTSTR );
- ASSERT_VALID_STRING( pszText );
- VERIFY( CListCtrl::SetItem( iIndex, iColumn, LVIF_TEXT, pszText, 0, 0, 0, 0 ) );
- arrpsz[ iColumn ] = new TCHAR[ lstrlen( pszText ) + 1 ];
- clrText[ iColumn ] = crWindowText;
- clrBak[ iColumn ] = crWindow;
- (void)lstrcpy( arrpsz[ iColumn ], pszText );
- }
- va_end( list );
- VERIFY( SetArray( iIndex, arrpsz,clrText,clrBak ) );
- return iIndex;
- }
- void CSortListCtrl::FreeItemMemory( const int iItem )
- {
- ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( iItem ) );
- LPTSTR* arrpsz = pid->arrpsz;
- for( int i = 0; i < m_iNumColumns; i++ )
- {
- delete[] arrpsz[ i ];
- }
- delete[] pid->crText;
- delete[] pid->crBak;
- delete[] arrpsz;
- delete pid;
- VERIFY( CListCtrl::SetItemData( iItem, NULL ) );
- }
- BOOL CSortListCtrl::DeleteItem( int iItem )
- {
- FreeItemMemory( iItem );
- return CListCtrl::DeleteItem( iItem );
- }
- BOOL CSortListCtrl::DeleteAllItems()
- {
- for( int iItem = 0; iItem < GetItemCount(); iItem ++ )
- FreeItemMemory( iItem );
- return CListCtrl::DeleteAllItems();
- }
- bool IsNumber( LPCTSTR pszText )
- {
- ASSERT_VALID_STRING( pszText );
- for( int i = 0; i < lstrlen( pszText ); i++ )
- if( !_istdigit( pszText[ i ] ) )
- return false;
- return true;
- }
- int NumberCompare( LPCTSTR pszNumber1, LPCTSTR pszNumber2 )
- {
- ASSERT_VALID_STRING( pszNumber1 );
- ASSERT_VALID_STRING( pszNumber2 );
- const int iNumber1 = atoi( pszNumber1 );
- const int iNumber2 = atoi( pszNumber2 );
- if( iNumber1 < iNumber2 )
- return -1;
-
- if( iNumber1 > iNumber2 )
- return 1;
- return 0;
- }
- bool IsDate( LPCTSTR pszText )
- {
- ASSERT_VALID_STRING( pszText );
- // format should be 99/99/9999.
- if( lstrlen( pszText ) != 10 )
- return false;
- return _istdigit( pszText[ 0 ] )
- && _istdigit( pszText[ 1 ] )
- && pszText[ 2 ] == _T('/')
- && _istdigit( pszText[ 3 ] )
- && _istdigit( pszText[ 4 ] )
- && pszText[ 5 ] == _T('/')
- && _istdigit( pszText[ 6 ] )
- && _istdigit( pszText[ 7 ] )
- && _istdigit( pszText[ 8 ] )
- && _istdigit( pszText[ 9 ] );
- }
- int DateCompare( const CString& strDate1, const CString& strDate2 )
- {
- const int iYear1 = atoi( strDate1.Mid( 6, 4 ) );
- const int iYear2 = atoi( strDate2.Mid( 6, 4 ) );
- if( iYear1 < iYear2 )
- return -1;
- if( iYear1 > iYear2 )
- return 1;
- const int iMonth1 = atoi( strDate1.Mid( 3, 2 ) );
- const int iMonth2 = atoi( strDate2.Mid( 3, 2 ) );
- if( iMonth1 < iMonth2 )
- return -1;
- if( iMonth1 > iMonth2 )
- return 1;
- const int iDay1 = atoi( strDate1.Mid( 0, 2 ) );
- const int iDay2 = atoi( strDate2.Mid( 0, 2 ) );
- if( iDay1 < iDay2 )
- return -1;
- if( iDay1 > iDay2 )
- return 1;
- return 0;
- }
- int CALLBACK CSortListCtrl::CompareFunction( LPARAM lParam1, LPARAM lParam2, LPARAM lParamData )
- {
- CSortListCtrl* pListCtrl = reinterpret_cast<CSortListCtrl*>( lParamData );
- ASSERT( pListCtrl->IsKindOf( RUNTIME_CLASS( CListCtrl ) ) );
- ItemData* pid1 = reinterpret_cast<ItemData*>( lParam1 );
- ItemData* pid2 = reinterpret_cast<ItemData*>( lParam2 );
- ASSERT( pid1 );
- ASSERT( pid2 );
- LPCTSTR pszText1 = pid1->arrpsz[ pListCtrl->m_iSortColumn ];
- LPCTSTR pszText2 = pid2->arrpsz[ pListCtrl->m_iSortColumn ];
- ASSERT_VALID_STRING( pszText1 );
- ASSERT_VALID_STRING( pszText2 );
- if( IsNumber( pszText1 ) )
- return pListCtrl->m_bSortAscending ? NumberCompare( pszText1, pszText2 ) : NumberCompare( pszText2, pszText1 );
- else if( IsDate( pszText1 ) )
- return pListCtrl->m_bSortAscending ? DateCompare( pszText1, pszText2 ) : DateCompare( pszText2, pszText1 );
- else
- // text.
- return pListCtrl->m_bSortAscending ? lstrcmp( pszText1, pszText2 ) : lstrcmp( pszText2, pszText1 );
- }
- void CSortListCtrl::OnColumnClick( NMHDR* pNMHDR, LRESULT* pResult )
- {
- NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
- const int iColumn = pNMListView->iSubItem;
- // if it's a second click on the same column then reverse the sort order,
- // otherwise sort the new column in ascending order.
- Sort( iColumn, iColumn == m_iSortColumn ? !m_bSortAscending : TRUE );
- *pResult = 0;
- }
- void CSortListCtrl::Sort( int iColumn, BOOL bAscending )
- {
- m_iSortColumn = iColumn;
- m_bSortAscending = bAscending;
- // show the appropriate arrow in the header control.
- m_ctlHeader.SetSortArrow( m_iSortColumn, m_bSortAscending );
- VERIFY( SortItems( CompareFunction, reinterpret_cast<DWORD>( this ) ) );
- }
- void CSortListCtrl::LoadColumnInfo()
- {
- // you must call this after setting the column headings.
- ASSERT( m_iNumColumns > 0 );
- CString strKey;
- strKey.Format( _T("%d"), GetDlgCtrlID() );
- UINT nBytes = 0;
- BYTE* buf = NULL;
- if( AfxGetApp()->GetProfileBinary( g_pszSection, strKey, &buf, &nBytes ) )
- {
- if( nBytes > 0 )
- {
- CMemFile memFile( buf, nBytes );
- CArchive ar( &memFile, CArchive::load );
- m_ctlHeader.Serialize( ar );
- ar.Close();
- m_ctlHeader.Invalidate();
- }
- delete[] buf;
- }
- }
- void CSortListCtrl::SaveColumnInfo()
- {
- ASSERT( m_iNumColumns > 0 );
- CString strKey;
- strKey.Format( _T("%d"), GetDlgCtrlID() );
- CMemFile memFile;
- CArchive ar( &memFile, CArchive::store );
- m_ctlHeader.Serialize( ar );
- ar.Close();
- DWORD dwLen = (DWORD)memFile.GetLength();
- BYTE* buf = memFile.Detach();
- VERIFY( AfxGetApp()->WriteProfileBinary( g_pszSection, strKey, buf, dwLen ) );
- free( buf );
- }
- void CSortListCtrl::OnDestroy()
- {
- for( int iItem = 0; iItem < GetItemCount(); iItem ++ )
- FreeItemMemory( iItem );
- CListCtrl::OnDestroy();
- }
- BOOL CSortListCtrl::SetItemText( int nItem, int nSubItem, LPCTSTR lpszText )
- {
- SetRedraw(FALSE);
- if( !CListCtrl::SetItemText( nItem, nSubItem, lpszText ) )
- return FALSE;
- LPTSTR* arrpsz = GetTextArray( nItem );
- LPTSTR pszText = arrpsz[ nSubItem ];
- delete[] pszText;
- pszText = new TCHAR[ lstrlen( lpszText ) + 1 ];
- (void)lstrcpy( pszText, lpszText );
- arrpsz[ nSubItem ] = pszText;
- SetRedraw(TRUE);
- return TRUE;
- }
- BOOL CSortListCtrl::SetItemData( int nItem, DWORD dwData )
- {
- /*
- if( nItem >= GetItemCount() )
- return FALSE;
-
- ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( nItem ) );
- ASSERT( pid );
- pid->dwData = dwData;
-
- return TRUE;*/
- CListCtrl::SetItemData( nItem, dwData);
- return TRUE;
-
- }
- DWORD CSortListCtrl::GetItemData( int nItem ) const
- {
- ASSERT( nItem < GetItemCount() );
-
- ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( nItem ) );
- ASSERT( pid );
- return pid->dwData;
-
- }
- BOOL CSortListCtrl::SetArray( int iItem, LPTSTR* arrpsz,COLORREF * clrText,COLORREF * clrBak )
- {
- ASSERT( CListCtrl::GetItemData( iItem ) == NULL );
- ItemData* pid = new ItemData;
- pid->arrpsz = arrpsz;
- pid->crText = clrText;
- pid->crBak = clrBak;
- return CListCtrl::SetItemData( iItem, reinterpret_cast<DWORD>( pid ) );//set item data /
- }
- LPTSTR* CSortListCtrl::GetTextArray( int iItem ) const
- {
- ASSERT( iItem < GetItemCount() );
- ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( iItem ) );
- return pid->arrpsz;
- }
- void CSortListCtrl::OnPaint()
- {
- Default();
-
- // TODO: Add your message handler code here
-
- // Do not call CListCtrl::OnPaint() for painting messages
- }
- void CSortListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
- {
- //draw each item.set txt color,bkcolor....
- SetRedraw(FALSE);
- NMLVCUSTOMDRAW* pLVCD = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
-
- // Take the default processing unless we set this to something else below.
- *pResult = CDRF_DODEFAULT;
-
- // First thing - check the draw stage. If it's the control's prepaint
- // stage, then tell Windows we want messages for every item.
-
- if (pLVCD->nmcd.dwDrawStage == CDDS_PREPAINT)
- {
- *pResult = CDRF_NOTIFYITEMDRAW;
- }
- else if (pLVCD->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
- {
- // This is the notification message for an item. We'll request
- // notifications before each subitem's prepaint stage.
-
- *pResult = CDRF_NOTIFYSUBITEMDRAW;
- }
- else if (pLVCD->nmcd.dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM))
- {
- // This is the prepaint stage for a subitem. Here's where we set the
- // item's text and background colors. Our return value will tell
- // Windows to draw the subitem itself, but it will use the new colors
- // we set here.
-
- int nItem = static_cast<int> (pLVCD->nmcd.dwItemSpec);
- int nSubItem = pLVCD->iSubItem;
-
- ItemData *pXLCD = (ItemData *) pLVCD->nmcd.lItemlParam;
- #if 0 //增加下面语句出错用户断点异常,待改进
- ASSERT(pXLCD);
- #endif
-
- COLORREF crText = crWindowText;
- COLORREF crBkgnd = crWindow;
-
-
- if (pXLCD){
- crText = (pXLCD->crText)[nSubItem];
- crBkgnd = (pXLCD->crBak)[nSubItem];
- }
-
-
-
- // store the colors back in the NMLVCUSTOMDRAW struct
- pLVCD->clrText = crText;
- pLVCD->clrTextBk = crBkgnd;
-
- CDC* pDC = CDC::FromHandle(pLVCD->nmcd.hdc);
- CRect rect;
- GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);
- if (GetItemState(nItem, LVIS_SELECTED))
- DrawText(nItem, nSubItem, pDC, crHighLightText, crHighLight , rect);
- else
- DrawText(nItem, nSubItem, pDC, crText, crBkgnd, rect);
- //2011-10-31 add
- //DeleteObject( pDC ); //?????
-
- *pResult = CDRF_SKIPDEFAULT; // We've painted everything.
- }
- SetRedraw(TRUE);
- }
- int CSortListCtrl::AddItemColor(LPCTSTR pszText, COLORREF crText, COLORREF crBak)
- {
- //insert item at the last
- const int iIndex = InsertItem( GetItemCount(), pszText );
- ItemData *m_pSortItemData=new ItemData[GetColumns()];
- /*
- m_pSortItemData[0].crText=crText;
- m_pSortItemData[0].crBak=crBak;
- */
-
- SetItemData(iIndex,(DWORD) m_pSortItemData);
- //no sort function
-
- return iIndex;
- }
- int CSortListCtrl::GetColumns()
- {
- return m_ctlHeader.GetItemCount();
- }
- BOOL CSortListCtrl::GetSubItemRect(int nItem, int nSubItem, int nArea, CRect &rect)
- {
- ASSERT(nItem >= 0);
- ASSERT(nItem < GetItemCount());
- if ((nItem < 0) || nItem >= GetItemCount())
- return FALSE;
- ASSERT(nSubItem >= 0);
- ASSERT(nSubItem < GetColumns());
- if ((nSubItem < 0) || nSubItem >= GetColumns())
- return FALSE;
-
- BOOL bRC = CListCtrl::GetSubItemRect(nItem, nSubItem, nArea, rect);
-
- // if nSubItem == 0, the rect returned by CListCtrl::GetSubItemRect
- // is the entire row, so use left edge of second subitem
-
- if (nSubItem == 0)
- {
- if (GetColumns() > 1)
- {
- CRect rect1;
- bRC = GetSubItemRect(nItem, 1, LVIR_BOUNDS, rect1);
- rect.right = rect1.left;
- }
- }
-
- return bRC;
- }
- void CSortListCtrl::DrawText(int nItem, int nSubItem, CDC *pDC, COLORREF crText, COLORREF crBkgnd, CRect &rect)
- {
- ASSERT(pDC);
-
- // GetDrawColors(nItem, nSubItem, crText, crBkgnd);
-
- pDC->FillSolidRect(&rect, crBkgnd);
-
- CString str;
- str = GetItemText(nItem, nSubItem);
-
- if (!str.IsEmpty())
- {
- // get text justification
- HDITEM hditem;
- hditem.mask = HDI_FORMAT;
- m_ctlHeader.GetItem(nSubItem, &hditem);
- int nFmt = hditem.fmt & HDF_JUSTIFYMASK;
- UINT nFormat = DT_VCENTER | DT_SINGLELINE;
- if (nFmt == HDF_CENTER)
- nFormat |= DT_CENTER;
- else if (nFmt == HDF_LEFT)
- nFormat |= DT_LEFT;
- else
- nFormat |= DT_RIGHT;
-
-
- pDC->SetBkMode(TRANSPARENT);
- pDC->SetTextColor(crText);
- pDC->SetBkColor(crBkgnd);
- pDC->DrawText(str, &rect, nFormat);
- }
- }
- void CSortListCtrl::OnSysColorChange()
- {
- CListCtrl::OnSysColorChange();
-
- // TODO: Add your message handler code here
- crWindow = ::GetSysColor(COLOR_WINDOW);
- crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
- crHighLight = ::GetSysColor(COLOR_HIGHLIGHT);
- crHighLightText = ::GetSysColor(COLOR_HIGHLIGHTTEXT);
-
-
-
- }
- void CSortListCtrl::SetItemColor(int nItem, int nSubItem, COLORREF clrText, COLORREF clrBkgnd)
- {
- ASSERT(nItem >= 0);
- int nItemCount = GetItemCount();
- #if 0 //增加下面语句出错用户断点异常,待改进
- ASSERT(nItem < nItemCount);
- #endif
- if ((nItem < 0) || nItem >= GetItemCount())
- return ;
- ASSERT(nSubItem >= 0);
- ASSERT(nSubItem < GetColumns());
- if ((nSubItem < 0) || nSubItem >= GetColumns())
- return ;
-
-
- if (nItem < 0)
- return ;
-
-
- ItemData *pid = (ItemData *) CListCtrl::GetItemData(nItem);
- if (pid)
- {
- (pid->crText)[nSubItem] = (clrText == -1) ? crWindowText : clrText;
- (pid->crBak)[nSubItem] = (clrBkgnd == -1) ? crWindow : clrBkgnd;
- }
-
- UpdateSubItem(nItem, nSubItem);
- }
- void CSortListCtrl::UpdateSubItem(int nItem, int nSubItem)
- {
- ASSERT(nItem >= 0);
- ASSERT(nItem < GetItemCount());
- if ((nItem < 0) || nItem >= GetItemCount())
- return;
- ASSERT(nSubItem >= 0);
- ASSERT(nSubItem < GetColumns());
- if ((nSubItem < 0) || nSubItem >= GetColumns())
- return;
-
- CRect rect;
- if (nSubItem == -1)
- {
- GetItemRect(nItem, &rect, LVIR_BOUNDS);
- }
- else
- {
- GetSubItemRect(nItem, nSubItem, LVIR_BOUNDS, rect);
- }
-
- InvalidateRect(&rect);
- UpdateWindow();
-
-
- }
|