in reply to problem with TK, tag, passing param with binding, destroying binds

#!/usr/bin/perl # http://perlmonks.org/?node_id=1213205 use strict; use warnings; use Tk; my $mw = MainWindow->new( -bg=> "#000000", -borderwidth=> 0); $mw->geometry( '1000x600' ); my $LB = $mw->Scrolled ( 'ROText', -bg => '#C0C0C0', -fg => '#000000', -selectforeground => '#000000', -selectbackground => '#C0C0C0', -font => 'Courier 16 normal', -relief => 'groove', -cursor => 'top_left_arrow', -scrollbars => 'e', )->pack( -side => 'right', -expand => 1, -fill => 'both', ); sub selectAccount { my $this = shift; print "select: $this\n"; } sub markAccount { my $this = shift; print "mark: $this\n"; } sub InitializeListBox { $LB->delete('1.0','end'); #for (my $i=1; $i<200; $i++) { for my $i (1..200) { $LB->insert('end', $i x 10, "A$i" ); $LB->tag( 'bind', "A$i", '<Button-1>' => sub { selectAccount( +$i) } ); $LB->tag( 'bind', "A$i", '<Double-1>' => sub { markAccount($i +) } ); $LB->insert('end', "\n" ); } } InitializeListBox(); MainLoop;
  • Comment on Re: problem with TK, tag, passing param with binding, destroying binds
  • Download Code

Replies are listed 'Best First'.
Re^2: problem with TK, tag, passing param with binding, destroying binds
by jsteng (Beadle) on Apr 20, 2018 at 02:15 UTC
    Why your code sub { selectAccount(+$i) } works?
    And why my code sub { &selectAccount(+$i) } did not?
    I took that code from a working script. I have always been using with the ampersand with binds.

    When to use with & and when not to use?


    Secondly, Am I doing it correctly: Tagging and Binding each line in that ROText?

    My goal is to bind Button-1 to a highlight a line. and to bind Double-1 to change color/font of the line.


    I have tried using Pane + Labels, Canvas but want to see alternatives and compare which is faster/efficient. Pane+Labels has the best quality, but suck in performance with long lists. Canvas still in the works. But ROText was my first iteration and it was fastest but suck in quality.


    My next goal is to have a multiple column ListView with same ability to highlight a single line and change font/color. Again, Pane+Label's performance was terrible though appearance great.
      #!/usr/bin/perl # http://perlmonks.org/?node_id=1213205 use strict; use warnings; use Tk; use Tk::ROText; my $mw = MainWindow->new( -bg=> "#000000", -borderwidth=> 0); $mw->geometry( '1000x600' ); my $LB = $mw->Scrolled ( 'ROText', -bg => '#C0C0C0', -fg => '#000000', -selectforeground => '#000000', -selectbackground => '#C0C0C0', -font => 'Courier 16 normal', -relief => 'groove', -cursor => 'top_left_arrow', -scrollbars => 'e', )->pack( -side => 'right', -expand => 1, -fill => 'both', ); sub selectAccount { my $this = shift; print "select: $this\n"; $LB->tagConfigure("A$_", -background => 'grey') for 1..200; $LB->tagConfigure("A$this", -background => 'yellow'); } sub markAccount { my $this = shift; print "mark: $this\n"; my $fontref = $LB->tagCget("A$this", -font); my $font = $fontref ? $$fontref : 'Courier 16 normal'; my $new = $font =~ /normal/ ? 'Courier 16 bold' : 'Courier 16 norm +al'; $LB->tagConfigure("A$this", -font => $new); } sub InitializeListBox { $LB->delete('1.0','end'); #for (my $i=1; $i<200; $i++) { for my $i (1..200) { $LB->insert('end', $i x 10, "A$i" ); $LB->tag( 'bind', "A$i", '<Button-1>' => sub { selectAccount( +$i) } ); $LB->tag( 'bind', "A$i", '<Double-1>' => sub { markAccount($i +) } ); $LB->insert('end', "\n" ); } } InitializeListBox(); MainLoop;
      Why your code sub { selectAccount(+$i) } works?
      And why my code sub { &selectAccount(+$i) } did not?
      ... I have always been using with the ampersand with binds.

      Further to tybalt89's reply...
      The  & (ampersand) has nothing to do with it. (Likewise the  + (plus) sign in front of the $i; I don't know where that came from.) The trick is to switch from your C-style  for (my $i=1; $i<200; $i++) { ... } loop to a Perl-style  for my $i (1..200) { ... } loop.

      In the C-style loop, the variable  $i is defined once and given many values, the last of which is 200 (because that's the value that finally fails the  $i<200 test). All the  sub { selectAccount($i) } and  sub { markAccount($i) } expressions symbolicly reference (if that's the right term) this single  $i variable which has only one final value. At the end of the  InitializeListBox() routine, the referential bindings "close" over the single  $i variable (with its single value) because all symbolic references to the variable are used within code references which are passed to another subroutine, tag(), and must therefore persist. (Again, I may not have quite the right terminology here, but that's the general idea.)

      In the Perl-style loop, the  $i variable is aliased to many different values. Each  sub { ... } expression symbolically references a different value via the  $i alias. All these different, individual values are then closed over. I think that's about right.

      See closure.

      As to your other, Tk-related questions, it's been a while since I've played with Tk very much and someone else could, I'm sure, give you much better answers with much less mental effort.

      Update: Made a few minor changes to wording in the interest, I hope, of clarity.


      Give a man a fish:  <%-{-{-{-<

        I actually never used any perl style loops before other than foreach my $i ( ... );
        and the working script I took that code indeed used foreach statement.

        I got alot of recoding work to do, replacing all C style loops with a Perl style loop. Thanks for clarification.

      Never use & except in one very special rare case.

      The real fix was using for my $i (1..200) { instead of the C style for(;;).