in reply to Re^2: Tk::Entry and double-Tab key weirdness
in thread Tk::Entry and double-Tab key weirdness

This might help you. It changes color, but dosn't flash. Also it helps to use 'any' for the validate method, rather than focusout. The key lines are
$mw->waitVisibility; $mw->after(100,sub{$entries{3}{'entry'}->focusForce});
Here is a working script that should show you the way of highlighting a textvariable which is invalid. You can perfect it yourself. :-)
#!/usr/bin/perl use strict; use warnings; use Tk; my $mw = MainWindow->new(-title => 'Mac Address Input Example'); my $fr = $mw->Frame()->pack(-expand => 1, -fill => 'both'); my $lb = $fr->Label(-text => 'MAC Address')->pack(-side => 'left'); my %entries; for(1..6){ $entries{$_}{'entry'} = $fr->Entry(); $entries{$_}{'entry'}->configure( -textvariable => \$entries{$_}{'addy'}, -width => 3, # -validate => 'focusout', # -validatecommand => [ \&validate,$_,\%entries ], # -invalidcommand => [ \&show_invalid,$entries{$_}{'entry'},$_ ], ); $entries{$_}{'entry'}->pack(-side => 'left'); } for(1..6){ $entries{$_}{'addy'} = 'zz'.$_ if($_ == 3); $entries{$_}{'entry'}->configure( #-validate => 'focusout', -validate => 'all', -validatecommand => [ \&validate,$_,\%entries ], -invalidcommand => [ \&show_invalid,$entries{$_}{'entry'},$_ ], ); } $mw->waitVisibility; $mw->after(100,sub{$entries{3}{'entry'}->focusForce}); MainLoop(); # returns `1' if valid, and `0' if invalid sub validate { my($num,$val) = @_; unless($val){ print "Field $num has nothing to validate\n";return 1; +} my $valid = ($val =~ /^[0-9a-f]{1,2}$/i) ? 1 : 0; printf "Field %s, validating \`%s'...%s\n",$num,$val,$valid? "ok": " +FAILED"; return $valid; } sub show_invalid { my($widget) = @_; # print "@_\n"; $widget->focus(); # background of the problem field in red my $bg = $widget->cget('-bg'); $widget->configure(-bg => 'lightpink'); $widget->update(); }

I'm not really a human, but I play one on earth.
Old Perl Programmer Haiku ................... flash japh

Replies are listed 'Best First'.
Re^4: Tk::Entry and double-Tab key weirdness
by atreyu (Sexton) on May 29, 2012 at 15:44 UTC
    Here is a working script that should show you the way of highlighting a textvariable which is invalid.

    @zentara,

    Thanks for this, will definitely check it out!

    heh, lightpink should not be too hard to miss...

    Edit:

    zentara, I checked out your code, there are a couple problems. The first is; I think in your validate sub, you left off the 2nd argument ($ref), b/c in yours it is trying to validate a HASH, not the value in the field. Am I right there?

    The second is; if I use 'all' instead of 'focusout' for -validate, then it breaks again - I can tab or click out of the bad field. Is there some other piece missing for 'all' to work properly?

    Edit 2:

    Here's an updated version that I'm now trying out. It seems to work okay. It incorporates zentara's suggestion of using 'all' vs 'focusout' (though I'm not sure how/why it is working correctly...)

    Also, to get it to evaluate all pre-populated fields when the app first fires up, I'm using eventGenerate to auto-Tab thru all the fields. It will stop on the first bad field it encounters, by virtue of the fact that I disable all other Entry widgets, if a problem is discovered. Once the field is validated, the other fields are re-enabled.

    This works, but it feels very hacky though...(the auto-tabbing and widget-disabling parts).

    #!/usr/bin/perl use strict; use warnings; use Tk; my $mw = MainWindow->new(-title => 'Mac Address Input Example'); my $fr = $mw->Frame()->pack(-expand => 1, -fill => 'both'); my $lb = $fr->Label(-text => 'MAC Address')->pack(-side => 'left'); # widget used to display Entry field errors my $errW = $fr->Label(-foreground=>'red')->pack(-side=>'bottom'); # hash to hold Entry widgets my %entries; # loop thru the number of Entry widgets desired for(1..6){ # create the Entry widget $entries{$_}{'entry'} = $fr->Entry( -textvariable => \$entries{$_}{'addy'}, -width => 3, ); # save default widget background $entries{$_}{'bg'} = $entries{$_}{'entry'}->cget('-bg'); # pack/display the widget $entries{$_}{'entry'}->pack(-side => 'left'); } # loop back thru the created widgets for(1..6){ # put some bogus values in for testing... $entries{$_}{'addy'} = ($_>1) ? $_.$_ : ''; $entries{$_}{'addy'} .= 'z' if($_ == 3 or $_ == 4); # configure the validation for the widget $entries{$_}{'entry'}->configure( # -validate => 'focusout', -validate => 'all', -validatecommand => [ \&validate,$_ ], -invalidcommand => [ \&show_invalid,$entries{$_}{'entry'},$_ ], ); } # put focus on initial Entry widget $entries{1}{'entry'}->focus(); # auto-tab thru all Entry widgets to perform validation on pre-populat +ed values for(1..6){ $mw->eventGenerate('<Tab>'); # $mw->idletasks; $mw->after(100); $mw->update; } MainLoop(); sub clear_err { my($num) = @_; $errW->configure(-text=>''); $entries{$num}{'entry'}->configure(-bg=>$entries{$num}{'bg'}); } # returns `1' if valid, and `0' if invalid sub validate { my($num,$val) = @_; unless($val){ print "Field $num has nothing to validate\n";return 1; +} my $valid = ($val =~ /^[0-9a-f]{1,2}$/i) ? 1 : 0; printf "Field %s, validating \`%s'...%s\n",$num,$val,$valid? "ok": " +FAILED"; if($valid){ # clear error widget &clear_err($num); # re-enable all other widgets for(1..6){ next if(/^$num$/); $entries{$_}{'entry'}->configure(-state=>'normal'); } }else{ # update the error widget with text indicating a problem with the +value $errW->configure(-text=>"Field $num value \`$val' is invalid"); } return $valid; } sub show_invalid { my($widget,$num) = @_; $widget->focus(); # turn the background of the problem field to red my $bg = $widget->cget('-bg'); $widget->configure(-bg => 'red'); $widget->update(); # temporarily disable focus on all other widgets for(1..6){ next if(/^$num$/); $entries{$_}{'entry'}->configure(-state=>'disabled'); } }
      I checked out your code, there are a couple problems.

      I said, I showed you the way, and it was up to you to perfect it. :-) It looks like you did a nice job. By the way, Entry validation is notoriously hard to setup right, you are doing a pretty good job.

      P.S. I would enlarge the font and make a white background color if I were you.

      # fontcreate works more reliably to add a font $mw->fontCreate('big', # -family=>'arial', -weight=>'bold', -size=> 18 ); # create the Entry widget $entries{$_}{'entry'} = $fr->Entry( -font => 'big', -textvariable => \$entries{$_}{'addy'}, -width => 3, -bg => 'white' );

      I'm not really a human, but I play one on earth.
      Old Perl Programmer Haiku ................... flash japh
        I said, I showed you the way, and it was up to you to perfect it. :-)

        i am spoiled, zentara. i have copied more of your code examples than I can remember and it had always works flawlessly before... ;)

        I would enlarge the font and make a white background color if I were you.

        Good suggestion - my "final product" code has the white background in the fields, but thanks for noting. i've used fontCreate before, but I'm lazy and use the -font => '{arial} 18 {bold}' syntax a lot. Could you tell me what the difference is there, if there is one (other than you can re-use 'big' as a font in your code, which is ultimately easier)?