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

Hello monks, how to disable the button untill certain fields are filled? I want to display the 'pressme" button as disabled untill certain fields are filled in the table, and when these fields are filled, "pressme" button will become active. how can i achieve this? Any Ideas...
use strict; use warnings; use Tk; use Tk::Table; use Tk::Entry; use Tk::Label; my $mw = new MainWindow; my $new_label = $mw -> Label(-text=>"Enter any character", -foreground=>"red", -font => "verdanafont 10 bold") -> pack(-side=>"top"); my $table_frame = $mw->Frame()->pack(-padx=>"10"); our $table = $table_frame->Table(-columns => 4, -rows => 5, -scrollbars => "o", -fixedrows => 1, -fixedcolumns => 1, -relief => 'raised', -pady=>"20", -takefocus=>"0"); my $press = $mw -> Button(-text=>"Press Me", -command =>\\&PressMe, -font => "verdanafont 10 bold") -> pack(-side=>"left",-padx=>"5", -ipadx=>"5"); my $row; my $col; for ($col=1;$col<5;$col++) { my $tmp_label=$table_frame->Label(-text=>"$col")->pack(); $table->put(0,$col,$tmp_label); } for($row=1;$row<6;$row++) { for ($col=1;$col<5;$col++) { my $ent1 = $table -> Entry(-font=>"verdana 10") -> pack(-ipady=>"15"); $table->put($row,$col,$ent1); } } $table->pack(); MainLoop; sub PressMe { for($row=0;$row<5;$row++) { for ($col=0;$col<4;$col++) { my $name = $table->get($row,$col); my $val = $name->get(); if ($val =~ m/[a-zA-Z0-9]/) { my $response=$mw -> messageBox(-type=>"ok", -message=>"alphanumeric en +tered",-icon=>"info",-title=> "info!!"); } } } }

Replies are listed 'Best First'.
Re: how to disable the button untill certain fields are filled?
by GrandFather (Saint) on Oct 26, 2008 at 09:38 UTC

    There were a number of bugs in your sample code which I've cleaned up in the code below. It's generally a good idea not to use global variables if you can avoid it, and generally you can. It's also a good idea to use Perl style for loops when you can rather than C style, and again generally you can.

    use strict; use warnings; use Tk; use Tk::Table; use Tk::Entry; use Tk::Label; use constant kRows => 3; use constant kCols => 3; main (); # Use a main sub to ensure that there are no global variables +s sub main { my $mw = new MainWindow; $mw->Label ( -text => "Enter any character", -foreground => "red", -font => "verdanafont 10 bold" )->pack (-side => "top"); my $table_frame = $mw->Frame ()->pack (-padx => "10"); my $table = $table_frame->Table ( -columns => kCols, -rows => kRows, -scrollbars => "o", -fixedrows => 1, -fixedcolumns => 1, -relief => 'raised', -pady => "20", -takefocus => "0" ); my $press = $mw->Button ( -text => "Press Me", -command => [\&PressMe, $mw, $table], # pass parameters into c +allback -font => "verdanafont 10 bold", -state => 'disabled', )->pack ( -side => "left", -padx => "5", -ipadx => "5" ); my $filled = 0; for my $col (0 .. kCols - 1) { my $tmp_label = $table_frame->Label (-text => "$col")->pack () +; $table->put (0, $col, $tmp_label); } for my $row (0 .. kRows - 1) { for my $col (0 .. kCols - 1) { my $ent1 = $table->Entry ( -font => "verdana 10", -validate => 'key', # Pass button widget and a ref to $filled into callbac +k. Need a # ref because we manipulate $filled in the callback -vcmd => [\&onEdit, $press, \$filled], )->pack (-ipady => "15"); $table->put ($row, $col, $ent1); } } $table->pack (); MainLoop; } sub onEdit { my ($button, $filled, $new, $edit, $current, $idx, $type) = @_; return 1 if $new eq $current; if (length $new && !length $current) { ++$$filled; } elsif (!length $new && length $current) { --$$filled; } if ($$filled == kRows * kCols) { $button->configure (-state => 'normal'); } else { $button->configure (-state => 'disabled'); } return 1; } sub PressMe { my ($mw, $table) = @_; my $message = "alphanumeric entered"; Outer: for my $row (0 .. kRows - 1) { for my $col (0 .. kCols - 1) { my $name = $table->get ($row, $col); my $val = $name->get (); next if $val =~ m/^[a-z0-9]+$/i; $message = "Bad entry ($val) in row " . ($row + 1) . ", column " . ($col + 1); last Outer; } } my $response = $mw->messageBox ( -type => "ok", -message => $message, -icon => "info", -title => "info!!" ); }

    Note the array technique used to pass extra parameters into the call back routines. The extra parameters are passed before the normal parameters.

    Note too the use of named constants to provide row and column counts rather than relying on using the correct manifest constants everywhere (four places for each in this small sample script!). Also note that the column and row indexes range from 0 to count - 1: easier to see and get right with the Perl for loops using the range operator than with the C style for loops.

    I also reworked your validation checking in the button call back so that the message box is only shown once and only for the first bad cell value found. You could of course check all the cells and report all the errors found by not terminating the loop early and by concatenating error messages together.


    Perl reduces RSI - it saves typing
      Thanks a lot!!!!GodFather.. Superbbb... since i am new to perl, i did those mistakes, thanks for correcting them too. Well i am bit confused about the working of onEdit function in the solution provided. can you please explain a little, how and which extra parameters you are passing and why?? Thanks in advance

        In the configuration code where the table entries are being set up the fragment:

        my $ent1 = $table->Entry ( -font => "verdana 10", -validate => 'key', # Pass button widget and a ref to $filled into callbac +k. Need a # ref because we manipulate $filled in the callback -vcmd => [\&onEdit, $press, \$filled], )

        configures the validation call back to be called when an edit is made and to pass the additional parameters $press and \$filled (a reference to $filled) to the call back function onEdit. onEdit receives a number of parameters:

        sub onEdit { my ($button, $filled, $new, $edit, $current, $idx, $type) = @_; return 1 if $new eq $current;

        The first two are the two extra parameters that were passed in when the call back was set up. The remainder are the normal parameters to the validation call back. If not changes will be made to the entry contents ($new eq $current) an early exit is made. Next a check is made to see if and empty cell has had characters added, or a non-empty cell has had its contents deleted and $filled is adjusted appropriately:

        if (length $new && !length $current) { ++$$filled; } elsif (!length $new && length $current) { --$$filled; }

        Finally, depending on the count in $filled, the button is enabled or disabled:

        if ($$filled == kRows * kCols) { $button->configure (-state => 'normal'); } else { $button->configure (-state => 'disabled'); }

        Perl reduces RSI - it saves typing
        sorry...read grandfather instead of godfather..