📄 sortlistctrl.cpp
字号:
/*----------------------------------------------------------------------
Copyright (C)2001 MJSoft. All Rights Reserved.
This source may be used freely as long as it is not sold for
profit and this copyright information is not altered or removed.
Visit the web-site at www.mjsoft.co.uk
e-mail comments to info@mjsoft.co.uk
File: SortListCtrl.cpp
Purpose: Provides a sortable list control, it will sort text, numbers
and dates, ascending or descending, and will even draw the
arrows just like windows explorer!
----------------------------------------------------------------------*/
#include "stdafx.h"
#include "SortListCtrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
//LPCTSTR g_pszSection = _T("ListCtrls");
#define g_pszSection _T("ListCtrls") // Modified by truezq. 减少全局变量
struct ItemData
{
public:
ItemData() : arrpsz( NULL ), dwData( NULL ) {}
LPTSTR* arrpsz;
DWORD dwData;
private:
// ban copying.
ItemData( const ItemData& );
ItemData& operator=( const ItemData& );
};
CSortListCtrl::CSortListCtrl()
: m_iNumColumns( 0 )
, m_iSortColumn( -1 )
, m_bSortAscending( TRUE )
{
}
CSortListCtrl::~CSortListCtrl()
{
}
BEGIN_MESSAGE_MAP(CSortListCtrl, CListCtrl)
//{{AFX_MSG_MAP(CSortListCtrl)
ON_NOTIFY_REFLECT(LVN_COLUMNCLICK, OnColumnClick)
ON_WM_DESTROY()
//}}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();
// Modified by truezq.
// 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;
// Modified by truezq.
// the increment of m_iNumColumns layed in this->InsertColumn()
if (InsertColumn(m_iNumColumns, strHeading, LVCFMT_LEFT, iWidth ) == -1 )
{
return FALSE;
}
}
return TRUE;
}
int CSortListCtrl::AddItem( LPCTSTR pszText, ... )
{
const int iIndex = InsertItem( GetItemCount(), pszText );
LPTSTR* arrpsz = new LPTSTR[ m_iNumColumns ];
arrpsz[ 0 ] = new TCHAR[ lstrlen( pszText ) + 1 ];
(void)lstrcpy( arrpsz[ 0 ], pszText );
va_list list;
va_start( list, pszText );
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 ];
(void)lstrcpy( arrpsz[ iColumn ], pszText );
}
va_end( list );
VERIFY( SetTextArray( iIndex, arrpsz ) );
return iIndex;
}
/*
修改意见 by sea_soul
To insert a variable icon before each row, i must use the function CListCtrl::InsertItem(),just like this:
m_images.Create(IDB_CHECK_BOX,13,1,RGB(255,255,255));
m_listctrl.SetImageList(&m_images,LVSIL_STATE);
LVITEMA lvi;
lvi.iSubItem=0;
lvi.mask=LVIF_TEXT|LVIF_STATE;
lvi.stateMask=LVIS_STATEIMAGEMASK;
lvi.iItem=i;
lvi.pszText="some words";
lvi.state=INDEXTOSTATEIMAGEMASK(UNCHECKED_INDEX);
//enum{UNCHECKED_INDEX=2,CHECKED_INDEX=3};
m_listctrl.InsertItem(&lvi);
then i use your function SetItemText(),but it generates a bug,so i add a member funtion AddItem2(LPCTSTR pszText, ... ) to match the function CListCtrl::InsertItem(),as follows:
commented by truezq:
比如有如下调用:
m_ListCtrl.InsertItem(0,"ZQ"); // 标准方法
m_ListCtrl.AddItem2("Zq"); // 设置排序数据
*/
int CSortListCtrl::AddItem2( LPCTSTR pszText, ... )
{
const int iIndex = GetItemCount() - 1;
LPTSTR* arrpsz = new LPTSTR[ m_iNumColumns ];
arrpsz[ 0 ] = new TCHAR[ lstrlen( pszText ) + 1 ];
(void)lstrcpy( arrpsz[ 0 ], pszText );
va_list list;
va_start( list, pszText );
for( int iColumn = 1; iColumn < m_iNumColumns; iColumn++ )
{
pszText = va_arg( list, LPCTSTR );
/*
// Old code
ASSERT_VALID_STRING( pszText );
VERIFY( CListCtrl::SetItem( iIndex, iColumn, LVIF_TEXT, pszText, 0, 0, 0, 0 ) );
arrpsz[ iColumn ] = new TCHAR[ lstrlen( pszText ) + 1 ];
(void)lstrcpy( arrpsz[ iColumn ], pszText );
*/
// Modified by truezq
// I think it's ought to allow empty subitem.
if (lstrlen(pszText) > 0)
{
ASSERT_VALID_STRING( pszText );
VERIFY( CListCtrl::SetItem( iIndex, iColumn, LVIF_TEXT, pszText, 0, 0, 0, 0 ) );
arrpsz[ iColumn ] = new TCHAR[ lstrlen( pszText ) + 1 ];
(void)lstrcpy( arrpsz[ iColumn ], pszText );
}
else
{
arrpsz[iColumn] = NULL;
}
}
va_end( list );
VERIFY( SetTextArray( iIndex, arrpsz ) );
return iIndex;
}
// commented by truezq. 2004-01-18
// 因为类 CSortListCtrl 节点 ItemData 可能包含了先前的 ItemData
// 如果按照原来的做法,删除节点就 SetItemData 为空,这是极不负责任的
// 很可能造成派生类资源泄漏!
// 正确做法,应该 SetItemData 为原来的值.
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[] arrpsz;
delete pid;
VERIFY( CListCtrl::SetItemData( iItem, NULL ) );
*/
ItemData* pid = reinterpret_cast<ItemData*>( CListCtrl::GetItemData( iItem ) );
DWORD dwItemData = pid->dwData; // Old ItemData value
LPTSTR* arrpsz = pid->arrpsz;
for( int i = 0; i < m_iNumColumns; i++ )
delete[] arrpsz[ i ];
delete[] arrpsz;
delete pid;
VERIFY(CListCtrl::SetItemData(iItem, dwItemData));
}
BOOL CSortListCtrl::DeleteItem( int iItem )
{
ASSERT(FALSE); //
FreeItemMemory( iItem );
return CListCtrl::DeleteItem( iItem );
}
BOOL CSortListCtrl::DeleteAllItems()
{
for( int iItem = 0; iItem < GetItemCount(); iItem ++ )
FreeItemMemory( iItem );
return CListCtrl::DeleteAllItems();
}
// 原来是全局函数
// 改为静态函数
bool CSortListCtrl::IsNumber( LPCTSTR pszText )
{
// commented by truezq. allow empty string
//ASSERT_VALID_STRING( pszText );
// Modified by truezq. allow empty string
if (pszText == NULL)
{
return false;
}
for( int i = 0; i < lstrlen( pszText ); i++ )
if( !_istdigit( pszText[ i ] ) )
return false;
return true;
}
int CSortListCtrl::NumberCompare( LPCTSTR pszNumber1, LPCTSTR pszNumber2 )
{
// commented by truezq. allow empty string
//ASSERT_VALID_STRING( pszNumber1 );
//ASSERT_VALID_STRING( pszNumber2 );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -