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

My fellow monks,

I've been working for the past week and a half to learn Tk. As I've mentioned in Other Nodes, I come from a Win32::GUI background, so I'm used to working with and around it's limitations. Well, I've come to the point where I want to do something I know Win32::GUI can do, but I don't know if Tk can do, can anyone tell me how?

Basically, this is what I want: A listbox (complete with scrollbars etc...) containing nothing all that complex, just a checkbox on the left, and some text to the right.

Looking something like this:
-------------------
[X]Top|/\|
[X]More|
[]
|
[X]More|
[]
|
[X]More|
[]
|
[X]More|
[]
|
[]More|
[]
|
[X]More| |
[X]More| |
[]More| |
[X]More| |
[X]More| |
[]More| |
[]More| |
[]More| |
[X]More|\/|
-------------------


Thats the best I can come up with in HTML :) Sue me :)

Anyway, is it possible in Tk? And how would I do it? Thanks!



"Weird things happen, get used to it."

Flame ~ Lead Programmer: GMS

Replies are listed 'Best First'.
Re: Tk List of Checkboxes?
by jlongino (Parson) on Jun 09, 2002 at 20:28 UTC
    First, let me say that this is only the third or fourth Tk script I've fooled with so this is as much a learning process for me as it is you (if not moreso). I've tried this little script and I think it has the elements you've described. The only problem is that although it looks right, it doesn't scroll. So maybe you can use this as a starting point and do some research from there. I'll keep working on it as well, and hopefully one of us or some more experienced and merciful monk will figure it out.
    use strict; use Tk; my $mw = MainWindow->new(); # Create the vertical Scrollbar my $scrollbar = $mw->Scrollbar(); my $lb = $mw->Listbox(-yscrollcommand => ['set' => $scrollbar]); # Configure the Scrollbar to talk to the Listbox widget $scrollbar->configure(-command => ['yview' => $lb]); # Pack the Scrollbar first so that it doesn't disappear when we resize $scrollbar->pack(-side => 'right', -fill => 'y'); $lb->pack(-side => 'left', -fill => 'both'); my %cb; foreach ( qw/a b c d e f g h/ ) { $lb->Checkbutton(-text => "$_", -variable => \$cb{"cb$_"}) -> pack(-side => 'top'); } MainLoop();
    BTW, this is made up from fragments scrounged from Mastering Perl/Tk. The comments are from the book as well.

    --Jim

    Update: After some digging, I'd recommend that you follow the suggestion by Util. I'm not sure what led me to try and embed checkboxes into a listbox widget (one example in the book gives an example packing entry widgets into a text widget, but the whole idea of inserting multiple widgets into either text or listbox widgets seems convoluted and flawed to me).

    One alternative is to use a listbox instead of several checkboxes using the "-selectmode => multiple" option, but it appears to work correctly only on NT class boxes (on lesser boxes it ignores the multiselect and uses single select).

Re: Tk List of Checkboxes?
by Util (Priest) on Jun 09, 2002 at 22:22 UTC

    Warning: I, too, am new to the Tk parts of Perl. I have Mastering Perl/Tk at the office, but have not yet read it.

    jlongino, I think that there are two problems in your code:

    1. The $lb->pack( ... ) statement needs to have an extra parameter: -expand => 'yes' . This change makes it work better, but still not right.
    2. The Listbox widget does not expect to have other widgets embedded in it, (it expects $lb->insert() instead), so its scrolling code does not react to the Checkbuttons you are adding. I played with it several ways, and looked at the Listbox.pm source code, and cannot see how to make this work. I could be completely wrong, though.

    The code below "works"; it scrolls, it looks like what Flame asked for, and each button tracks its input separately. There may be a simpler way, though.

    #!/usr/bin/perl -W use warnings 'all'; use strict; use Tk::Pane; my $mw = Tk::MainWindow->new(); my $pane = $mw->Scrolled( 'Pane', -scrollbars => 'oe' )->pack( -expand => 'yes', -fill => 'both', # "-fill => 'y'" works, too ); my @list; for my $text ('A' .. 'Z') { my $value; $pane->Checkbutton( -anchor => 'w', -text => $text, -variable => \$value, )->pack( -side => 'top', -fill => 'x', ); push @list, \$value; } Tk::MainLoop(); printf "%s\n", $$_||0 foreach @list;
      Well, we're getting closer, I should probably expand on the goals for this though:

      Basically, I want to have the list one one side, and then a large 60x5 text field, a 60x1 text field and another list on the other side. As the user selects an item from the list on the left, I want to clear the elements on the right, and fill them with data pertaining to the object.

      Basically, the list is a list of options (hence, the checkboxes) but I'm building it to be expandable as I don't know how large the boxes could get in the long run. The other fields describe the options and their requirements.

      Hope this explains my question a little better. If anyone can offer an alternative, I'd be happy to hear it.



      "Weird things happen, get used to it."

      Flame ~ Lead Programmer: GMS

Re: Tk List of Checkboxes?
by Util (Priest) on Jun 10, 2002 at 01:11 UTC
    I only used one text field here, but otherwise I think this what you want as a starting point:
    #!/usr/bin/perl -W use warnings 'all'; use strict; use Tk::Pane; my %data; while (<DATA>) { m/^(.)(.+?)\s+$/ and push @{ $data{"\u$1"} }, "\u$1\L$2"; } my $mw = Tk::MainWindow->new(); my $left_pane = $mw->Scrolled( 'Pane', -scrollbars => 'oe' )->pack( -expand => 'yes', -fill => 'y', -side => 'left', ); my $right_pane = $mw->Scrolled( 'Pane', -scrollbars => 'oe' )->pack( -expand => 'yes', -fill => 'y', -side => 'right', ); my $middle_pane = $mw->Scrolled( 'Pane', -scrollbars => 'oe' )->pack( -expand => 'yes', -fill => 'x', -side => 'top', ); my $mid_entry = $middle_pane->Scrolled( 'Entry', -relief => 'sunken', -scrollbars => 's', )->pack(); my @right_list; sub alter_mid_and_right_panes { my ($key,$value) = @_; return unless $value; # Don't change when unchecking left box. while( my $cb = pop @right_list ) { $cb->destroy(); } $mid_entry->delete(0, length($mid_entry->get())); $mid_entry->insert( 'end', "Ah, '$key'. What a great letter! I remember her well." ); for my $word ( sort @{ $data{$key} } ) { my $cb = $right_pane->Checkbutton( -anchor => 'w', -text => $word, )->pack( -side => 'top', -fill => 'x', ); push @right_list, $cb; } } my @list; for my $key ( sort keys %data ) { my $value; my $cb = $left_pane->Checkbutton( -anchor => 'w', -text => $key, -variable => \$value, -command => sub { alter_mid_and_right_panes($key, $value) }, )->pack( -side => 'top', -fill => 'x', ); push @list, \$value; } Tk::MainLoop(); __DATA__ Abe Apple Baker Bananna