📄 sortlistctrl.cpp
字号:
const int iNumber1 = pszNumber1 ? atoi( pszNumber1 ) : 0;
const int iNumber2 = pszNumber1 ? atoi( pszNumber2 ) : 0;
if( iNumber1 < iNumber2 )
return -1;
if( iNumber1 > iNumber2 )
return 1;
return 0;
}
bool CSortListCtrl::IsDate( LPCTSTR pszText )
{
// commented by truezq. allow empty string
//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 CSortListCtrl::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 ];
// commented by truezq. allow empty string
//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 = memFile.GetLength();
BYTE* buf = memFile.Detach();
VERIFY( AfxGetApp()->WriteProfileBinary( g_pszSection, strKey, buf, dwLen ) );
free( buf );
}
int CSortListCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CListCtrl::OnCreate(lpCreateStruct) == -1)
return -1;
/*
Failed. why?
if (GetHeaderCtrl()->GetSafeHwnd())
{
VERIFY(m_ctlHeader.SubclassWindow(
GetHeaderCtrl()->GetSafeHwnd()));
}
CWnd *pWnd = GetDlgItem(0);
ASSERT(pWnd);
CHeaderCtrl *pHeader = static_cast<CHeaderCtrl*>(pWnd);
//ASSERT(pHeader);
*/
return 0;
}
void CSortListCtrl::OnDestroy()
{
for( int iItem = 0; iItem < GetItemCount(); iItem ++ )
FreeItemMemory( iItem );
CListCtrl::OnDestroy();
}
BOOL CSortListCtrl::SetItemText( int nItem, int nSubItem, LPCTSTR lpszText )
{
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;
return TRUE;
}
// 子类必须调用 SetItemData, 而不能直接用 LVM_INSERTITEM 消息存储
// ItemData , 否则会发生未知结果。
BOOL CSortListCtrl::SetItemData( int nItem, DWORD dwData )
{
if( nItem >= GetItemCount() )
return FALSE;
ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( nItem ) );
// 如果下面这个断言失败,表明在 调用 SetItemData 前,没有调用一次 AddItem2
if (pid == NULL)
{
TRACE0( _T("must call AddItem() or AddItem2() firstly!!!") );
}
ASSERT( pid );
pid->dwData = dwData;
return TRUE;
}
// 子类不能在 DeleteItem 里调用 GetItemData
// 原因是 DeleteItem 首先调用 CSortListCtrl::DeleteItem
// 而 CSortListCtrl::DeleteItem 已经把 ItemData 这个空间释放了!
DWORD CSortListCtrl::GetItemData( int nItem ) const
{
ASSERT( nItem < GetItemCount() );
ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( nItem ) );
ASSERT( pid );
return pid->dwData;
}
BOOL CSortListCtrl::SetTextArray( int iItem, LPTSTR* arrpsz )
{
ASSERT( CListCtrl::GetItemData( iItem ) == NULL );
ItemData* pid = new ItemData;
/*
// Modified by truezq. 允许先设置 ItemData
ItemData* pid = new ItemData;
if (CListCtrl::GetItemData(iItem) != 0)
{
pid->dwData = CListCtrl::GetItemData(iItem);
}
*/
pid->arrpsz = arrpsz;
return CListCtrl::SetItemData( iItem, reinterpret_cast<DWORD>( pid ) );
ASSERT(CListCtrl::GetItemData( iItem ) != 0); // added by truezq
}
LPTSTR* CSortListCtrl::GetTextArray( int iItem ) const
{
ASSERT( iItem < GetItemCount() );
ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( iItem ) );
return pid->arrpsz;
}
// Added by truezq, 2004-01-18
// 因为用户程序员可能用标准的方法加入列头,而不是调用该类的 SetHeadings 方法。
int CSortListCtrl::InsertColumn(int nCol, LPCTSTR lpszColumnHeading, int nFormat,
int nWidth, int nSubItem)
{
m_iNumColumns++;
return CListCtrl::InsertColumn(nCol, lpszColumnHeading, nFormat,
nWidth, nSubItem);
}
// 同时提供重载版本
int CSortListCtrl::InsertColumn(int nCol, const LVCOLUMN* pColumn)
{
m_iNumColumns++;
return CListCtrl::InsertColumn(nCol, pColumn);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -