http://www.perlmonks.org?node_id=1002797

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

This is the scenario:

I have a few arrays (here it's three but in reality I have more):
@preset = qw(tom snare metal analog); @card1 = qw(mellowstr brightstr string3); @ram = qw(acoustic rock bass jazz strato distorted);

now I want to have two interdependent PerlTK BrowseEntry widgets:

The first one should let me choose one of the arrays (preset or card1 or ram), while the second one will let me choose one of the elements from the array chosen in the first BrowseEntry widget.

The BrowseEntry widget needs an array as 'choices' parameter and saves the choice in a string variable.

What I'm struggling with is how to create a suitable data structure for this, I was trying with an additional hash of arrays like this:

%hash=(preset=>\@preset, card=>\@card1, intram=>\@ram);
But first of all I'm not sure if that is the best way to do this and then I'm struggling to make this work (I can't figure out what to assign to -choices in the two BrowseEntry widgets).

It would be a huge help for me if someone could tell me the best data structure for this and the -variable and -choices parameters required to make this work (ideally with actual code snippets, based on my example).

If this problem description sounds confusing that's because I am confused! :-)

Replies are listed 'Best First'.
Re: data structure problem
by graff (Chancellor) on Nov 08, 2012 at 04:12 UTC
    Your hash of arrays idea seems like a perfectly sensible approach. Whether the structure is hard-coded or is somehow input-dependent, you can easily manage the BrowseEntry widgets:
    ... # populate %hash as per the OP # create $first_BrowseEntry, then: $first_BrowseEntry->insert( "end", $_ ) for ( sort keys %hash ); ... sub first_browse_callback { $second_BrowseEntry->delete( 0, "end" ); my $chosen = $first_BrowseEntry->get; $second_BrowseEntry->insert( "end", $_ ) for ( sort @{$hash{$chose +n}} ); }
    There'll be more code than that, of course, but not a lot more. When you create the first_BrowseEntry widget, you'll include the "first_browse_callback" function as the "-browsecmd" option value.

    (updated to use consistent naming on the widget variable)

      Many thanks for your reply!

      It cleared my doubt whether I was on the right track with regards to the data structure and your 'first_browse_callback' code snippet helped me greatly with implementing the callback to modify the second widget based on the user selection of the first widget.
      My code is working fine now.

      You saved me from hours of frustrating experimentation! :-)
Re: data structure problem
by kcott (Archbishop) on Nov 08, 2012 at 06:36 UTC

    G'day perltux,

    I was thinking of a hash before I'd even read as far as %hash=(preset=>\@preset, ....

    Here's a bare-bones (but working) solution that doesn't use the -choices option. First, a few notes:

    • The -browsecmd callback is passed the widget as the first argument. As I haven't needed that, you'll see undef in a few places. You may need to change that.
    • I made some decisions about display defaults: you may want to make changes here also.
    • As I was uncertain what some of the terms you used referred to, my choices for variable names may be less than meaningful.

    Here's the code:

    #!/usr/bin/env perl use strict; use warnings; use Tk; use Tk::BrowseEntry; my %choices = ( preset => [ qw{tom snare metal analog} ], card1 => [ qw{mellowstr brightstr string3} ], ram => [ qw{acoustic rock bass jazz strato distorted} ], ); my @list_order = qw{preset card1 ram}; my ($current_list, $current_choice); my $mw = MainWindow->new(); my $be_F = $mw->Frame()->pack(); my $ex_F = $mw->Frame()->pack(); my $list_BE = $be_F->BrowseEntry( -variable => \$current_list, -browsecmd => \&update_choices, )->pack(-side => 'left'); my $vary_BE = $be_F->BrowseEntry( -variable => \$current_choice, -browsecmd => \&make_choice, )->pack(-side => 'left'); for (@list_order) { $list_BE->insert(end => $_); } update_choices(undef, $list_order[0]); $ex_F->Button(-text => 'Exit', -command => sub { exit })->pack(); MainLoop; sub update_choices { my (undef, $list) = @_; $current_list = $list; $current_choice = $choices{$list}[0]; $vary_BE->delete(0 => 'end'); for (@{$choices{$list}}) { $vary_BE->insert(end => $_); } return; } sub make_choice { my (undef, $choice) = @_; $current_choice = $choice; return; }

    -- Ken

Re: data structure problem
by Anonymous Monk on Nov 08, 2012 at 04:01 UTC
    ???

    #!/usr/bin/perl -- use strict; use warnings; use Tk; use Tk::BrowseEntry; my %foo = ( man => [ 'a'..'c' ], manl => "man label", manv => "", choo => [ 66 .. 69 ], chool => "choo label", choov => "", ); my $mw = tkinit; $mw->BrowseEntry( -choices => $foo{man}, -label => $foo{manl}, -variable => \$foo{manv}, )->pack; $mw->BrowseEntry( -choices => $foo{choo}, -label => $foo{chool}, -variable => \$foo{choov}, )->pack; $mw->MainLoop; use Data::Dump; dd \%foo; __END__ { choo => [66 .. 69], chool => "choo label", choov => 68, man => ["a", "b", "c"], manl => "man label", manv => "b", }

    #!/usr/bin/perl -- use strict; use warnings; use Tk; use Tk::BrowseEntry; my $mw = tkinit; my @barvar; for my $ix ( 'A'..'C' ){ my @var = ( "", undef ); my $widget = foomanchoo( $mw, { choices => [ map { $ix.' '.$_ } 1 .. 12 ], label => "$ix label ", variable => \$var[0], } ); $var[1] = $widget; push @barvar, \@var; } $mw->MainLoop; use Data::Dump; dd \@barvar; sub foomanchoo { my ( $mw, $foo ) = @_; my $bro = $mw->BrowseEntry( -choices => $$foo{choices}, -label => $$foo{label}, -variable => $$foo{variable}, ); $bro->pack; $bro; } __END__ [ [ "A 2", bless({ _BE_buttonHack => 1, _BE_curIndex => 1, _BE_popped => 0, _BE_Style => "MSWin32", _TkValue_ => ".browseentry", }, "Tk::BrowseEntry"), ], [ "B 6", bless({ _BE_buttonHack => 1, _BE_curIndex => 5, _BE_popped => 0, _BE_Style => "MSWin32", _TkValue_ => ".browseentry1", }, "Tk::BrowseEntry"), ], [ "C 4", bless({ _BE_buttonHack => 1, _BE_curIndex => 3, _BE_popped => 0, _BE_Style => "MSWin32", _TkValue_ => ".browseentry2", }, "Tk::BrowseEntry"), ], ]

    References quick reference, Data::Diver, Lexical scoping like a fox, Variable Scoping in Perl: the basics, ...