mhearse has asked for the wisdom of the Perl Monks concerning the following question:

I'm making a simple app which uses lists, Tk::Hlist to be specific. Here is a picture. I would like the ability to sort the list by clicking on the column header. I know how to do this (just an alternating regular/reverse sql query in this case), but does Tk::Hlist support it? I didn't see it in the docs. If not Tk::Hlist, is there another widget which would act similarly? I guess I could always add some buttons under the columns.... The list could bet very long, so some sorting mechanism is needed. Thanks much.

In case you aren't sure what I'm talking about, by 'sorted lists', here is an example in CGI. Clicking the column title reverses the order.

Replies are listed 'Best First'.
Re: Sorted lists in Tk
by zentara (Cardinal) on May 04, 2005 at 11:59 UTC
    It's not that hard, but you have to do it manually, and you need to be familiar with the Hlist methods. But here is a simple demo. I couldn't easily figure out how to make a button-click binding on the HList column header, so I just made a button. Also with more columns (than in this snippet), you will need to sort on (and itemConfigure) more fields.

    UPDATE: It's easy to make clickable headers, just groups.google search for "Tk HList header bind" for a few examples. I added a second example in the readmore below, to show a double sort.

    #!/usr/bin/perl use strict; use Tk; use Tk::HList; my $mw = MainWindow->new(); #create some sample data my %data; foreach (0..100) { $data{$_}{'name'} = 'name'.$_; $data{$_}{'id'} = rand(time); } #get random list of keys my @keys = keys %data; ################# my $h = $mw->Scrolled( 'HList', -header => 1, -columns => 2, -width => 30, -height => 60, -takefocus => 1, -background => 'steelblue', -foreground =>'snow', -selectmode => 'single', -selectforeground => 'pink', -selectbackground => 'black', # -browsecmd => \&browseThis, )->pack(-side => "left", -anchor => "n"); my $nameh = $h->header('create', 0, -text => ' Name ', -borderwidth => 3, -headerbackground => 'steelblue', -relief => 'raised'); my $idh = $h->header('create', 1, -text => ' ID ', -borderwidth => 3, -headerbackground => 'lightsteelblue', -relief => 'raised'); foreach (@keys) { my $e = $h->addchild(""); #will add at end $h->itemCreate ($e, 0, -itemtype => 'text', -text => $data{$_}{'name'}, ); $h->itemCreate($e, 1, -itemtype => 'text', -text => $data{$_}{'id'}, ); } my $button = $mw->Button(-text => 'exit', -command => sub{exit})->pack; my $sortid = $mw->Button(-text => 'Sort by Id', -command => [\&sort_me,1] )->pack; MainLoop; ######################################################### sub sort_me{ my $col = shift; my @entries = $h->info('children'); my @to_be_sorted =(); foreach my $entry(@entries){ push @to_be_sorted, [ $h->itemCget($entry,0,'text'), $h->itemCget($entry,1,'text') ]; } my @sorted = sort{ $a->[$col] cmp $b->[$col] } @to_be_sorted; my $entry = 0; foreach my $aref (@sorted){ # print $aref->[0],' ',$aref->[1],"\n"; $h->itemConfigure( $entry, 0, 'text' => $aref->[0] ); $h->itemConfigure( $entry, 1, 'text' => $aref->[1] ); $entry++; } $mw->update; }
    And here is a double sort example:

    I'm not really a human, but I play one on earth. flash japh
      Thanks for the code examples. As you suggested, I searched groups.google.com. I found there mention of a very powerful list widget, with built in sorting capabilities. Tk::MListbox. It's pretty impressive. Allows column sorting, hiding columns, etc. It's available as an activestate package. Life is good!
        There was a recent post on comp.lang.perl.tk about MListbox leaking memory, when you make alot of entry changes. I recommended in a response to use HList, because it's methods allow reuse of entries. I actually thought you were the same person who posted there, because he said the drawback to HList was no built-in sorting. Anyways...watch your memory with MListbox, if you are doing alot of entry changes.

        I'm not really a human, but I play one on earth. flash japh
Re: Sorted lists in Tk
by rcseege (Pilgrim) on May 05, 2005 at 21:18 UTC

    It's true. MListbox leaks memory, but only because the current Listbox in the most recent releases of Tk leaks. If that were fixed, then it would be fine.

    I guess I can take a look at updating MListbox to use TextList instead of Listbox like I intended to a year or two ago. I don't believe it has the same memory leak problem. Perhaps I'll create an option that will use one or the other. Unfortunately, I don't think TextList will be as efficient.

    The Leak in Listbox is a fairly new thing. I don't recall it being a problem before Tk804.*

    Rob
      I guess I can take a look at updating MListbox to use TextList instead of Listbox like I intended

      That would be great!

      I'm rather new to Perl Tk. Just out of curiousity, is a widget such as Tk::MListbox 'pure Perl'?

        Yes. MListbox is a widget that is built from several Tk core widgets. MListbox consists of no C code itself, and generally relies on its subwidgets to "do the right thing" when it comes to freeing memory that is no longer required.

        Each sort operation essentially deletes all data from each Listbox (Column), and then loads each Listbox again with the data once it has been sorted. So, as you can imagine leaks in Listbox are obvious very quickly.

        Tk::TextList is a widget that was created several years ago to emulate the functionality provided by Listbox (method calls, look-and-feel, etc), but to give it the power of Text widget tags. In theory, this gives TextList the ability to create and apply styles (tags) at a much greater granularity (per character) than even HList, though, I think the current set of methods support a per-item configuration.

        You should be able to plugin TextList every where there is a Listbox call, and it should work, but now that I think about it, there may have been one or two issues with it that I'm not sure if I ever released fixes for. Feel free to experiment with it. I'm going to look at it again as well.

        If you have the time to devote to it, I definitely encourage you to experiment with HList. I've also used it for similar purposes in the past, with a reasonable amount of success. Whenver I did, however, I always had this nagging feeling that I was using it to solve problems that it wasn't really created to solve.