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

Hello Monks

I need to create a table of widgets to display records from a database. The records will be chosen later in the program. The problem is identifying the individual widgets sdo I can insert information.Here is my code for that section:

for ($j = 1; $j < 7; $j++) { my $frame = $mf->Frame(-background => 'alice blue', -padx => 2 +0, -pady => 5) ->pack(-expand => 1, -fill => 'both', -side => 'top'); $frame->Label(-text => $meals[$j-1], -background => 'alice blue', -width => 9) ->pack(-side => 'left'); $frame->Text(-height => 6, -background => 'white', -width => 25) ->pack(-side => 'left'); for ($i = 2; $i < 9; $i++) { if ($c <= 6) {++$c;} else {$c = 1;} my $id = "\$f" . $j . $c; # Create identifier $id = $frame->Text(-height => 6, -background => 'white', -width => 10) ->pack(-side => 'left'); } #end for $i } # End for $j

This renders the widgets beautifully, just the way I want them. The problem comes here:

$f22->insert('end', 'R2, C4');

Which results in this error: Can't call method "insert" on an undefined value.

Can I use a variable to identify the widgets? If not is there a work around? I have looked at Tk::Table but it doesn't work well for my needs.

Desperate for help. Thanks

Replies are listed 'Best First'.
Re: Asssigning widget identifier
by tybalt89 (Monsignor) on Sep 24, 2018 at 17:01 UTC

    Use a hash for your identifiers. What you did is not perl :(

    Here's minimal changes to make it (sort of) work.

    #!/usr/bin/perl # https://perlmonks.org/?node_id=1222918 use strict; use warnings; use Tk; my @meals; my %identifiers; my $mf = MainWindow->new; for (my $j = 1; $j < 7; $j++) { my $frame = $mf->Frame(-background => 'alice blue', -padx => 2 +0, -pady => 5) ->pack(-expand => 1, -fill => 'both', -side => 'top'); $frame->Label(-text => $meals[$j-1], -background => 'alice blue', -width => 9) ->pack(-side => 'left'); $frame->Text(-height => 6, -background => 'white', -width => 25) ->pack(-side => 'left'); my $c = 0; for (my $i = 2; $i < 9; $i++) { if ($c <= 6) {++$c;} else {$c = 1;} my $id = $j . $c; # Create identifier $identifiers{$id} = $frame->Text(-height => 6, -background => 'white', -width => 10) ->pack(-side => 'left'); } #end for $i } # End for $j $identifiers{'22'}->insert('end', 'R2, C4'); MainLoop;

      I was updating my answer after I realised what "f22" was when tybalt89 wrote this. Which is exactly what my updated suggestion is. Glad we arrived at the same spot though I took the scenic route :)

Re: Asssigning widget identifier
by bliako (Abbot) on Sep 24, 2018 at 17:22 UTC

    Separating $i and $j with, say, a dash will save you a bug if and when the number of your widgets increase to 100+: 'f111' can be 1/11 or 11/1

Re: Asssigning widget identifier
by bliako (Abbot) on Sep 24, 2018 at 16:54 UTC

    All that message says is that $f22 = undef. Sometimes subs return undef in the case of errors. Because I can not see $f22 anywhere in the code you provided and my knowlegde of Tk is minimal I will stop my answer here. Hopefully it will get you a bit further until others appear.

    Update: sorry I spotted my $id = "\$f" . $j . $c; # Create identifier

    But you are overriding your identifier in the next line by $id = $frame->Text

    Should you perhaps declare a hash before the loops and then save each return of $frame->Text() to that keyed on (ad-hoc) id names? For example:

    my %widgets = (); ... # your loops my $id = "f" . $j . $c; # Create identifier my $awidget = $frame->Text(-height => 6, -background => 'white', -width => 10) ->pack(-side => 'left'); die "widget failed $id" if ! defined($awidget); $widgets{$id} = $awidget; ... # closing the loops

    Then you can access f22 like $widgets->{'f22'}->insert()...

    Update #2: $widgets{'f22'}->insert()... is the correct way to access 'f22' widget

Re: Asssigning widget identifier
by Oberbee (Novice) on Sep 24, 2018 at 19:35 UTC

    Thanks guys. The suggestions work great.