#!/usr/bin/perl -w # # 070502 liverpole -- Demonstrates a weirdness which I don't understand # # Strict use strict; use warnings; # Libraries use Tk; ################## ## Main program ## ################## # Construct the GUI my $mw = new MainWindow(); my $f1 = $mw->Frame()->pack; my $chosen = ""; my $fr1 = $f1->Frame()->pack(-side => 'left'); my $fr2 = $f1->Frame()->pack(-side => 'left'); button($fr1, 'green', ' Exit GUI ', sub { $mw->destroy() }); button($fr1, 'green', ' Start test ', sub { start_test($fr2) }); $fr1->Label(-width => 16, -textvar => \$chosen, -bg => 'white')->pack; MainLoop(); ################# ## Subroutines ## ################# sub button { my ($w, $bg, $text, $pcmd) = @_; my $b = $w->Button(-bg => $bg, -text => $text); $b->configure(-width => 16, -command => $pcmd); $b->pack; return $b; } sub randomize_list { my $plist = shift; my $prandom = [ ]; while (@$plist) { push @$prandom, splice(@$plist, int(rand(@$plist)), 1); } return $prandom; } sub start_test { my ($frame) = @_; # Create a random list of 9 items { 1 ... 9 } my @values = qw( 1 2 3 4 5 6 7 8 9 ); my $pvalues = randomize_list([ @values ]); my $chosen_idx = -1; foreach my $num (@$pvalues) { $chosen = $num; # Create a duplicate list (not including the chosen number) my @dups = grep { $_ ne $num } @values; my $pdups = randomize_list([ @dups ]);; # Insert chosen number at a random place { 0 ... 3 } in the list my $correct_idx = int(rand(4)); $pdups->[$correct_idx] = $num; my $pbuttons = [ ]; for (my $i = 0; $i < 4; $i++) { my $dup = $pdups->[$i]; my $icopy = $i; # The closure where I'm expecting $chosen_idx to get # assigned to $i = {0,1,2,3}, but it seems to always # get assigned to 4! (or whatever the final value of # $i is.) However, if I set $chosen_idx to $icopy: # # my $psub = sub { $chosen_idx = $icopy }; # # then everything works ... ??? # my $psub = sub { $chosen_idx = $i }; push @$pbuttons, button($frame, 'skyblue', $dup, $psub); } $chosen_idx = -1; while ($chosen_idx < 0) { $mw->update(); } # Delete the buttons map { $_->destroy() } @$pbuttons; # Why on EARTH is this showing $chosen_idx as 4 every time?! print "correct idx[$correct_idx] ... chosen_idx[$chosen_idx]\n"; } } #### sub button { my ($w, $bg, $text, $pcmd, $ival) = @_; (defined $ival) and print "Value of \$i is $ival\n"; my $b = $w->Button(-bg => $bg, -text => $text); $b->configure(-width => 16, -command => $pcmd); $b->pack; return $b; } # ... and later, when calling button() ... push @$pbuttons, button($frame, 'skyblue', $dup, $psub, $i); # The above correctly displays each value of $i #### my $icopy = $i; # ... my $psub = sub { $chosen_idx = $icopy };