Beefy Boxes and Bandwidth Generously Provided by pair Networks
Clear questions and runnable code
get the best and fastest answer
 
PerlMonks  

Re: Strange behavior of iteration while creating Perl/Tk widgets dynamically

by kcott (Archbishop)
on Oct 29, 2021 at 10:16 UTC ( [id://11138196]=note: print w/replies, xml ) Need Help??


in reply to Strange behavior of iteration while creating Perl/Tk widgets dynamically

G'day Zsolt,

You have written your for loop like this:

for (INIT; COND; INCR) { ... }

The following is very important. I'm not attempting to be patronising; you need to fully understand this. Pay close attention to the numbers.

INIT
This is an initialisation which only occurs once. In your case, it sets $i to 1.
COND
This is a condition which determines whether the loop is entered. When $i is 1, 2, 3, 4 or 5 the condition $i <= 5 is TRUE and the loop is entered. When $i is 6, the condition is FALSE, and the loop ends.
INCR
This increments $i at the end of the loop before another iteration is attempted. $i is set to 2 at the end of the 1st iteration. It continues to be incremented. $i is set to 6 at the end of the 5th iteration. The last value that $i has is 6!

In each iteration, you set up two callbacks with the -command option. In both cases, the value of the callback is a coderef (an anonymous subroutine: sub { ... }); You redefine those coderefs on each iteration. The code in those coderefs contains the variable $i. On the final redefinition, the last value that $i has is 6!

This is why, regardless of which CLR button you use, you always see "title: Choose color for 6 degree!"; and similarly, regardless of which CHK button you use, you always see "degreeClr6".

Using (non-reference) variables in a callback is almost always a bad idea in Tk applications: use references instead. Here's a somewhat contrived Tk application using two scalarrefs and an arrayref in a callback. It's possibly a little over the top; however, it's intended to make a point.

#!/usr/bin/env perl use strict; use warnings; use Tk; my $mw = MainWindow::->new(); my @colours = qw{magenta red blue green darkred}; my $swatch = $mw->Label(-bg => 'black')->pack(-fill => 'x'); for my $i (0 .. 4) { $mw->Button( -bg => $colours[$i], -command => sub { colour_swatch(\$swatch, \@colours, \$i); }, )->pack(-fill => 'x'); } sub colour_swatch { my ($swatch_ref, $colours_ref, $i_ref) = @_; my $bg = ${$colours_ref}[$$i_ref]; $$swatch_ref->configure(-bg => $bg); return; } MainLoop;

The swatch at the top starts off black. As you click on any of the five coloured buttons below, it takes on the colour of that button.

You have no end of other problems with the code you posted: package variables springing into existence all over the place; symbolic references which you should really avoid (arrays and hashes are often a better choice — see @colours in my code above); lines so long that they're almost unreadable (one statement has 262 characters); and other code which I suspect you just threw at it in the hope that it would somehow fix something (for instance, what did think the utf pragma would achieve?).

I strongly recommend that you read perlintro to get a basic grounding in Perl coding. Following that, you may want to look at: "Symbolic references", "Anonymous Subroutines", and Tk::callbacks.

— Ken

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11138196]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others admiring the Monastery: (5)
As of 2024-03-28 13:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found