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



Comments

  • Does it works with ownerdata

    Posted by Legacy on 12/18/2003 12:00am

    Originally posted by: PoperoH

    Is there a way to work it with ownerdata??

    Reply
  • Excellant Class! Question about ListCtrl

    Posted by Legacy on 05/15/2003 12:00am

    Originally posted by: Charles M. Curtis Jr.

    This Class is excellant and it works great. I would like to know if you can tell me. Is the ListCtrl a single list control or is it in fact two seperate ListCtrl's? If it is Seperate is there a way to Seperate them and use them independently of one another? I.E. is it possible to set one list with one set of data and the other with something different?

    Thanks for any help and Thanks for a Great ListCtrl!

    Reply
  • Need the Same in VB

    Posted by Legacy on 08/21/2002 12:00am

    Originally posted by: Deepak

    Hi,
    Could you please tell where I can find similar control to use in VB6.0.
    Regards
    Deepak.

    Reply
  • How do i Increase Height ?

    Posted by Legacy on 06/11/2002 12:00am

    Originally posted by: rivaldo

    hi, how do i increase the Height of the each Row in the listctrl. how do i do that?
    any help .... or any source...
    pl. help me..

    Reply
  • Inserting subitems doesn't work

    Posted by Legacy on 01/19/2001 12:00am

    Originally posted by: Daniel Benmergui

    When i try to add a subitem in the function OnUpdate
    the subitems aren't drawn on screen...how can it be fixed?

    Thanks.
    Daniel.

    Reply
  • Minor Bug and Warning Solution

    Posted by Legacy on 09/13/2000 12:00am

    Originally posted by: Ariel Benary

    A truly great class!!

    The Warning about SORT_STATE is solved easily, just fix the following line :

    in SortColumn (multisort class) change :

    csc.Sort(ssEachItem);

    to :

    csc.Sort(ssEachItem == DESCENDING);

    Also, in DeleteAllItems the function should call
    the function DeleteAllItems of its base class, since
    the current situation results in an endless recursion

    Reply
  • Problem when setting HDS_FILTERBAR to header control

    Posted by Legacy on 01/17/2000 12:00am

    Originally posted by: Rob Davidson

    If you add the line:
    
    m_ctlHeaderCtrl.ModifyStyle(0,HDS_FILTERBAR);
    to the CMultiColumnSortListView::OnCreate function

    Then you get a sortable IE5 filterbar listview.

    However, the column headings don't repaint properly - there are white parts left in the sorted heading.

    Any ideas for a fix?

    Rob

    Reply
  • A simple algorithm for sorting multiple columns

    Posted by Legacy on 09/15/1999 12:00am

    Originally posted by: Rick Shide

    // here's an algorithm for sorting on multiple string columns on column header clicks, 
    
    // if two cols compare equally, it sorts on subsequent columns.
    // this example is for three cols specifically, but one could extend this easily
    // (how about a sort class that allocates the sort col and asc/dec keys dynamically
    // to match the size of the listview?)
    // notice that this is used very simply, all that I stuff
    // in the listview's item data are strings


    int sortCol[3] = { 0, 1, 2 }; // sorting column
    BOOL sortAsc[3] = { TRUE, TRUE, TRUE }; // "sort ascending?" compare return vals

    static int CALLBACK CompareFunc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
    {
    for (int i = 0; i < 3; i++) {
    if ((CString*)lParam1)[sortCol[i]] != ((CString*)lParam2)[sortCol[i]])
    return str1 > str2 ? (sortAsc[sortCol[i]] ? 1 : -1) : (sortAsc[sortCol[i]] ? -1 : 1);
    }
    return 0; // all equal
    }


    // message map entry
    ON_NOTIFY(LVN_COLUMNCLICK, IDC_MY_LIST, OnColumnclicked)


    // NOTE: my hard-coded 3 way switch statement should be replaced with a more heuristical approach
    // for sorting on n columns

    void COutbox::OnColumnclicked(NMHDR* pNMHDR, LRESULT* pResult)
    {
    NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;

    iSortCol = pNMListView->iSubItem;
    switch(iSortCol) {
    case 0: sortCol[0] = 0; sortCol[1] = 1; sortCol[2] = 2; break;
    case 1: sortCol[0] = 1; sortCol[1] = 0; sortCol[2] = 2; break;
    case 2: sortCol[0] = 2; sortCol[1] = 0; sortCol[2] = 1; break;
    }
    sortAsc[sortCol[0]] = !sortAsc[sortCol[0]];

    if (m_MyList.GetItemCount() > 1)
    m_MyList.SortItems((PFNLVCOMPARE)CompareFunc, (LPARAM)&m_MyList);

    *pResult = 0;
    }

    Reply
  • There's a problem when the number of colums to sort exceds 2

    Posted by Legacy on 08/27/1999 12:00am

    Originally posted by: Nuno

    When the number of columns exceds 2 the third one don't do nothing, neither sort ascending nor descending.
    I will try to fix this problem, but if there's anyone that already do this please tell me.

    Reply
  • A minor bug in function : MoveItemInCombinedSortedListToEnd

    Posted by Legacy on 06/03/1999 12:00am

    Originally posted by: Frank Chen

    Thanks for the orginal poster. This
    
    is a greate class.

    But I found some weird behavior when I
    tried the sorting function. After tracing
    the sorce code, I think the following code in function
    MoveItemInCombinedSortedListToEnd should be changed.

    >>>if( iItemIndex != -1 )
    >>>{
    >>> if( iItemIndex > 0 )
    >>> {

    change to

    >>>if( iItemIndex != -1 )
    >>>{
    >>> if( iItemIndex >= 0 )
    >>> {

    Regards

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Today's agile organizations pose operations teams with a tremendous challenge: to deploy new releases to production immediately after development and testing is completed. To ensure that applications are deployed successfully, an automatic and transparent process is required. We refer to this process as Zero Touch Deployment™. This white paper reviews two approaches to Zero Touch Deployment--a script-based solution and a release automation platform. The article discusses how each can solve the key …

  • Learn How A Global Entertainment Company Saw a 448% ROI Every business today uses software to manage systems, deliver products, and empower employees to do their jobs. But software inevitably breaks, and when it does, businesses lose money -- in the form of dissatisfied customers, missed SLAs or lost productivity. PagerDuty, an operations performance platform, solves this problem by helping operations engineers and developers more effectively manage and resolve incidents across a company's global operations. …

Most Popular Programming Stories

More for Developers

RSS Feeds