Sorted List Control - how?

classic Classic list List threaded Threaded
17 messages Options
Reply | Threaded
Open this post in threaded view
|

Sorted List Control - how?

Donn Ingle
Hello,
I have been sorting a list before putting its elements into a list-control,
but is there a way to make the list-control itself maintain a sort-order?

I need this because new items can be added to the list-control (later) and
they appear out of order - at the top of the list.

Even more importantly, can it do so based on the current locale?

/d



Reply | Threaded
Open this post in threaded view
|

Re: Sorted List Control - how?

Peter Hansen-5
Donn Ingle wrote:
> I have been sorting a list before putting its elements into a list-control,
> but is there a way to make the list-control itself maintain a sort-order?

The docs show a SortItems() call that does this.  (Note it doesn't
"maintain" it for you... you just call that method to ensure it is
sorted whenever you want it to be.)

> Even more importantly, can it do so based on the current locale?

Since you supply the method to do the comparison, certainly... just make
sure to handle the locale correctly yourself.

-Peter


Reply | Threaded
Open this post in threaded view
|

Re: Sorted List Control - how?

Donn Ingle
> The docs show a SortItems() call that does this.  (Note it doesn't
> "maintain" it for you... you just call that method to ensure it is
> sorted whenever you want it to be.)
Thanks, I dunno how I missed that one. I'll go have another look.

/d




Reply | Threaded
Open this post in threaded view
|

Re: Re: Sorted List Control - how?

Peter Hansen-5
Donn Ingle wrote:
>> The docs show a SortItems() call that does this.  (Note it doesn't
>> "maintain" it for you... you just call that method to ensure it is
>> sorted whenever you want it to be.)
> Thanks, I dunno how I missed that one. I'll go have another look.

The interface for wxPython might be non-obvious, especially to a
beginner (not sure if you are one or not).  Here's a trivialized example
you can probably build on, which should explain what the note about "a
callable object" means in the C++ docs:

Define a sorter class, something like this.  It exists basically so
__call__() can be defined for it:

class _StepSorter(object):
     '''used in call to ListCtrl.SortItems()'''
     def __call__(self, a, b):
         # a and b were set by ListCtrl.SetItemData()
         return cmp(a, b)

# when you insert/add items into the list, call SetItemData for them
# since that's what SortItems() passes to the sorter object:

     index = self.listCtrl.InsertStringItem(0, 'some string')
     self.listCtrl.SetItemData(index, someValue)

     # elsewhere in your code...
     stepSorter = _StepSorter() # could create this once and save

     # now do the sort itself
     self.listCtrl.SortItems(stepSorter)

At this point the list items are sorted according to how your __call__()
comparator method in the sorter compares the values passed in, which are
the values you passed to SetItemData().  I don't know whether you can
pass in values that are not integers, not having tried it, but the docs
suggest you won't be able to, so if you wanted to compare the strings
themselves (e.g. for alphabetical order) you'd probably need to make
someValue the same as index, and index into an array of strings that
you'd store elsewhere, or look them up directly with GetItemText() or
something.  I haven't worked with this feature a lot... just hoping this
helps a little.  (My list items were basically images with numbers as
labels, and I just wanted them sorted numerically so it was simple.)

-Peter


Reply | Threaded
Open this post in threaded view
|

Re: Re: Sorted List Control - how?

Donn Ingle
> I haven't worked with this feature a lot... just hoping this
> helps a little.  
Right, gulp!
Thanks for the real effort! I'll have to hit the keyboard and see what I can
do.

/d

~ Fonty Python : And now font something completely different...
(Gnu/Linux TTF viewer and manager.)
website : https://savannah.nongnu.org/projects/fontypython



Reply | Threaded
Open this post in threaded view
|

Re: Re: Sorted List Control - how?

Donn Ingle
In reply to this post by Peter Hansen-5
Peter - thanks for that stepsorter info, that's not in the wxpython docs I
have. Did you get it from the wx Widgets docs?

> I don't know whether you can
> pass in values that are not integers, not having tried it, but the docs
> suggest you won't be able to,
Nope - it has to be a long.

> so if you wanted to compare the strings
> themselves (e.g. for alphabetical order) you'd probably ... snip
Yeah - that's the thing. I gotta go do hoops and loops after that point. So
it seems the ListCtrl cannot keep itself sorted, which is just downright
weird.

(After all that work, it might simply be easier to delete all the items,
sort a list and then re-insert them into the control!)

Please someone, tell me I'm wrong!

/d



Reply | Threaded
Open this post in threaded view
|

Re: Re: Re: Sorted List Control - how?

Peter Hansen-5
Donn Ingle wrote:
> Peter - thanks for that stepsorter info, that's not in the wxpython docs I
> have. Did you get it from the wx Widgets docs?

Yes, I tend to keep the Windows help file "wxWidgets Reference" open all
the time as I program, since it seems to answer the bulk of my questions
and is far more responsive than the wxPython docs on the SourceForge site...

-Peter


Reply | Threaded
Open this post in threaded view
|

Re: Re: Re: Sorted List Control - how?

Werner F. Bruhin
In reply to this post by Donn Ingle
Donn,

Donn Ingle wrote:

> ...
> Yeah - that's the thing. I gotta go do hoops and loops after that point. So
> it seems the ListCtrl cannot keep itself sorted, which is just downright
> weird.
>
> (After all that work, it might simply be easier to delete all the items,
> sort a list and then re-insert them into the control!)
>
> Please someone, tell me I'm wrong!
>  
Have you looked at the "wx\lib\mixins\listctrl.py" mixin?  It is used in
the wxPython demo Core Windows/Controls ListCtrl.  I don't know how it
reacts adding a new item to the list, in worst case you might just have
to call SortListItems.

Hope this helps
Werner



Reply | Threaded
Open this post in threaded view
|

Re: Sorted List Control - how?

Ed Leafe
In reply to this post by Donn Ingle
On Dec 10, 2006, at 7:44 AM, Donn Ingle wrote:

> I have been sorting a list before putting its elements into a list-
> control,
> but is there a way to make the list-control itself maintain a sort-
> order?
>
> I need this because new items can be added to the list-control  
> (later) and
> they appear out of order - at the top of the list.
>
> Even more importantly, can it do so based on the current locale?

        This looks like a great feature, so I just added it to the Dabo. All  
controls based on item lists now have a Sorted property to turn this  
behavior off/on, and a SortFunction property to control sorting.

        Even if you don't use Dabo, thanks for the idea!

-- Ed Leafe
-- http://leafe.com
-- http://dabodev.com




Reply | Threaded
Open this post in threaded view
|

Re: Re: Sorted List Control - how?

Robin Dunn
In reply to this post by Peter Hansen-5
Peter Hansen wrote:

> Donn Ingle wrote:
>>> The docs show a SortItems() call that does this.  (Note it doesn't
>>> "maintain" it for you... you just call that method to ensure it is
>>> sorted whenever you want it to be.)
>> Thanks, I dunno how I missed that one. I'll go have another look.
>
> The interface for wxPython might be non-obvious, especially to a
> beginner (not sure if you are one or not).  Here's a trivialized example
> you can probably build on, which should explain what the note about "a
> callable object" means in the C++ docs:
>
> Define a sorter class, something like this.  It exists basically so
> __call__() can be defined for it:
>
> class _StepSorter(object):
>     '''used in call to ListCtrl.SortItems()'''
>     def __call__(self, a, b):
>         # a and b were set by ListCtrl.SetItemData()
>         return cmp(a, b)

A "callable object" doesn't have to be a class with a __call__ method.
It is anything that can be called, IOW, any foo for which foo(a,b) is
possible.


--
Robin Dunn
Software Craftsman
http://wxPython.org  Java give you jitters?  Relax with wxPython!



Reply | Threaded
Open this post in threaded view
|

Re: Sorted List Control - how?

Donn Ingle
In reply to this post by Ed Leafe
> This looks like a great feature, so I just added it to the Dabo. All
> controls based on item lists now have a Sorted property to turn this
> behavior off/on, and a SortFunction property to control sorting.
 
> Even if you don't use Dabo, thanks for the idea!
Okay, now you just know I *gotta* click on your link ;)

/d



Reply | Threaded
Open this post in threaded view
|

Re: Re: Sorted List Control - how?

Donn Ingle
In reply to this post by Robin Dunn
> A "callable object" doesn't have to be a class with a __call__ method.
> It is anything that can be called, IOW, any foo for which foo(a,b) is
> possible.
Robin,
If all that ca get passed to foo is a and b - which are numbers assigned
during a SetItemData call, how can one achieve an alphabetical sort?

I mean - let's assume everything I put into the listctrl up-front gets the
numbers 1 to 10 as the items go into it; later-on I want to add a new item.
How do I know what number to give the new item such that it will sort into
the listctrl?
Let's say the new item should fit between 3 and 4 in the list. How do I know
this?

It seems like I have to keep a separate list, add the new item, sort the
list and then go through it and re-number each item (perhaps each item is
stored in a tuple) and then go through the listcontrol and re-number each
item there (by a SetItemData) from my separate list and then call
SortItems(foo). No?

Feeling thick today ;)
/d



Reply | Threaded
Open this post in threaded view
|

Re: Re: Re: Sorted List Control - how?

Werner F. Bruhin
Hi Donn,

Donn Ingle wrote:

>> A "callable object" doesn't have to be a class with a __call__ method.
>> It is anything that can be called, IOW, any foo for which foo(a,b) is
>> possible.
>>    
> Robin,
> If all that ca get passed to foo is a and b - which are numbers assigned
> during a SetItemData call, how can one achieve an alphabetical sort?
>
> I mean - let's assume everything I put into the listctrl up-front gets the
> numbers 1 to 10 as the items go into it; later-on I want to add a new item.
> How do I know what number to give the new item such that it will sort into
> the listctrl?
> Let's say the new item should fit between 3 and 4 in the list. How do I know
> this?
>
> It seems like I have to keep a separate list, add the new item, sort the
> list and then go through it and re-number each item (perhaps each item is
> stored in a tuple) and then go through the listcontrol and re-number each
> item there (by a SetItemData) from my separate list and then call
> SortItems(foo). No?
>
> Feeling thick today ;)
> /d
>
>  
To me it is magic and it took me some time to figure out the basics of it.

I suggest that you put some print statements into the method
__ColumnSorter in lib/mixins/listctrl.py and then run the demo.

You will see that item1 and item2 is the thing being sorted (text, int
etc) and the key1 and key2 is the unique value you put into ClientData.

Werner



Reply | Threaded
Open this post in threaded view
|

Re: Re: Sorted List Control - how?

Peter Hansen-5
In reply to this post by Robin Dunn
Robin Dunn wrote:

> Peter Hansen wrote:
>> Define a sorter class, something like this.  It exists basically so
>> __call__() can be defined for it:
>>
>> class _StepSorter(object):
>>     '''used in call to ListCtrl.SortItems()'''
>>     def __call__(self, a, b):
>>         # a and b were set by ListCtrl.SetItemData()
>>         return cmp(a, b)
>
> A "callable object" doesn't have to be a class with a __call__ method.
> It is anything that can be called, IOW, any foo for which foo(a,b) is
> possible.

Oh, how very simple.  I think I misinterpreted the "wxPython" comments
in the wxWidgets docs, about how the "SortData" parameter is not
available for use.  Thanks for the correction.

-Peter


Reply | Threaded
Open this post in threaded view
|

Re: Re: Re: Sorted List Control - how?

Donn Ingle
In reply to this post by Werner F. Bruhin
> I suggest that you put some print statements into the method
> __ColumnSorter in lib/mixins/listctrl.py and then run the demo.
Right Werner, off I go to hack the demo, thanks for the clues!

/d



Reply | Threaded
Open this post in threaded view
|

Re: Re: Re: Sorted List Control - how?

Robin Dunn
In reply to this post by Donn Ingle
Donn Ingle wrote:
>> A "callable object" doesn't have to be a class with a __call__ method.
>> It is anything that can be called, IOW, any foo for which foo(a,b) is
>> possible.
> Robin,
> If all that ca get passed to foo is a and b - which are numbers assigned
> during a SetItemData call, how can one achieve an alphabetical sort?

Because of the unfortunate decision made years ago to model the
wxListCtrl API on the Win32 ListView API we are stuck with some a bad
design issues until we have something that can replace the wxListCtrl.
One of those is that each items' data value is what is passed to the
sort function rather than something like the item indexes or whatever.

So the way to work with this wart, instead of against it, is to maintain
something that will allow you to map from the item data value to the
item or the item's textual values.  The Python dictionary is perfect for
this, and is how it is done in the ListCtrl.py sample in the demo.  Then
you simply have to assign each item a unique numerical value as a data
value, and make that value a key in a dictionary that maps to the values
or objects you want to use for sorting.  Then your sort function simply
looks something like this:

def SortCompare(self, key1, key2):
        value1 = self.valueMap[key1]
        value2 = self.valueMap[key2]
        return cmp(value1, value2)

Of course you can use something besides a dictionary to get from the key
to the value, if that makes more sense for your app.  Also if needed the
comparison can be much more complex as well, for secondary sorts using
values in other columns, etc.



> I mean - let's assume everything I put into the listctrl up-front gets the
> numbers 1 to 10 as the items go into it; later-on I want to add a new item.
> How do I know what number to give the new item such that it will sort into
> the listctrl?
> Let's say the new item should fit between 3 and 4 in the list. How do I know
> this?

You don't need to know.  Just give it a new key value of 11 (or
whatever) that maps to the sortable values, and then call SortItems
again.  The key will get mapped to the text to sort by and the item will
get shuffled into place.


--
Robin Dunn
Software Craftsman
http://wxPython.org  Java give you jitters?  Relax with wxPython!



Reply | Threaded
Open this post in threaded view
|

Re: Re: Re: Sorted List Control - how?

Donn Ingle
> The key will get mapped to the text to sort by and the item will
> get shuffled into place.
Thanks for the help Robin, it's early here and my brain needs to warm up
before I'll get the picture!

/d