A Multi Column Sort listview

 Download Source Code and Example


This class handles sorting of multiple columns in a listctrl at the same time. The way it works is simple. When you click on a column, the column number is stored in an array, the array is cleared each time you click on a column without holding control. Telling the sort routine that only 1 column needs to be sorted. If you press control while clicking another column that second column is appended to the array and the columns are sorted in reverse order. Accomplishing a "subsort".

One other thing it does is save column widths for each instance of the listctrl. To acheive this though you must call SetUniqueName. Each instance needs a unique name to know where to save and retreive column widths.

Usage:

You generally should not use this class directly, though it is possible. You need to do two things to use it directly. Set m_strUniqueName to someting, and set m_strColumnWidthSection to where you want the column widths to be saved. m_strColumnWidthSection by default is set to "ColumnWidths".

The purpose of m_strUniqueName is to allow for saving of multiple instances of listview objects. So obviously you would need to set this differently for each instance. SetUniqueName must be called before calling InsertColumn() or LoadColumnWidths().

If you are deriving from this class, you need to do the following: Add a class to your project derived from CListView, then go into the header file and include MultiColumnSortListView.h and change all references to CListView to CMultiColumnSortListView. Then in the .cpp file of your class, change all the message maps to CMultiColumnSortListView instead of CListView. That should do it.

Functions you must call:

A sample CreateView:

    < CMyListView is derived from CMultiColumnSortListView >

    m_wndSplitter.CreateView( 0, 0, RUNTIME_CLASS( CMyListView ), CSize( 0, 200 ), pContext );
    CMyListView *pView = (CMyListView *) m_wndSplitter.GetPane( 0, 0 );
    pView->SetUniqueName( "MYVIEW1" );

Functions you dont need to call but may find useful:

  • SetColumnNumeric:

    This function tells the sorting routine that this column will contain only numeric data. It will not crash if there are string inside the column, it just wont sort them correctly.

        CMyListView *pView = GetTheListView();
        pView->SetColumnNumeric(2);
        pView->SetColumnNumeric(3);
    
  • IsSorting:

    This function will tell you if the listctrl is in the middle of being sorted.

         if( pView->IsSorting() )
          MessageBox("Cannot sort, i am already sorting");
    

Miscellaneous utility functions are also provided:

  • void CMultiColumnSortListView::DeleteAllColumns()

    Utility function to get rid of all the columns

  • void CMultiColumnSortListView::DeleteAllItems()

    Utility function to get rid of all items.

  • UINT CMultiColumnSortListView::GetColumnCount()

    Utility function to get the number of columns written by Zafir Anjum

  • const int CMultiColumnSortListView::IsControlPressed() const

    Utility function to tell you if the control key is being pressed

  • const SORT_STATE CMultiColumnSortListView::GetItemSortState( int iItem ) const

    Utility function to get you the sort state of a column

  • void CMultiColumnSortListView::SetItemSortState(int iItem, SORT_STATE bSortState)

    Utility function to set the sort state of a column

  • const int CMultiColumnSortListView::GetRegColumnWidth( int iColumn ) const

    Utility function to look up a columns width in the registry.

  • void CMultiColumnSortListView::AutoSizeAllColumns()

    Utility function to Autosize all columns in the case there is no registry entry.

  • void CMultiColumnSortListView::SetColumnWidth( int nCol )

    Utility function to set the width on the column based on the registry value and a set minimum column width.

Most of the functions have very descriptive names.

Compiling:

One problem you will have is finding IDB_ARROWUP and IDB_ARROWDOWN. Those bitmaps will be included with this set of classes, You should add them to your project or add your own bitmaps named correctly. These are the bitmaps that show the sort order on the header control.

I hope this is simple enough, kind of a pain to get started but after that it should be cake and hopefully it will be useful.

Things to be aware of:

Multithreading:
If you delete all the items from another thread in the middle of a sort, it will crash. This is the only bug i have found.

Column Widths:
MINCOLWIDTH - Minimum width a column can be.
MAXCOLWIDTH - Maximum width a column can be.

These are hard coded in the header file. Be aware.

MAXCOLUMNS - The most columns you can have right now is 64, that is only because im using __int64 to hold the column sort states. Who needs more than 64 columns anyway? If you do, you can change it to CUIntArray, i just didnt see the need for a whole int when all i needed was a bit.

Credits:

  • Iuri Apollonio -- Sorting Class ( great class )
  • Zafir Anjum -- CMultiColumnSortListView::GetColumnCount
  • Roger Onslow -- CMultiColumnSortListView::AutoSizeColumns
  • Zafir Anjum -- CSortableHeaderCtrl::SetSortImage
  • Me -- The Rest, I think.

Last updated: 12 July 1998