Subject: | Pre/post nextButtonAction does not work as intended when associated function returns false |
I want to create a preNextButtonAction function that performs some
checks using the info entered on the current wizard screen. When the
checks fail, the wizard should not allow you to continue to the next
page. I suppose that is the intended behaviour of a preNextButtonAction
routine.
However when the function I associate to the nextbuttonaction returns
false, all is messed up, and it is impossible to use the Next button
again, even when the function returns true later on.
The issue refers to the code in sub _NextButtonEventCycle of Wizard.pm.
Obviously it holds a counter how many times it has been called at the
same time (the variable "_inside_nextButtonEventCycle_" which I will
refer to as "counter").
The counter is increased first.
However when its value is more than 1, the routine exits. I assume that
is done to avoid that the routine is running twice at the same time?...
Suppose however that the routine is run only once. The next step in the
code is to execute (_dispatch) the preNextButtonAction. When this
returns 0, a "return" is called and the _NextButtonEventCycle is left.
According to me, you first have to decrease the counter again. Otherwise
its value remains at 1, and when you click the Next button again, you
will always immediately exit the _NextButtonEventCycle because the
counter will always increase to 2.
So the code has to become:
if ( _dispatch( $self->cget( -preNextButtonAction ) ) ) {
DEBUG "preNextButtonAction says we should not go ahead";
# GDP: Decrease _inside_nextButtonEventCycle_ again
# otherwise unable to click Next button again
# (will always bail out on condition above.
$self->{_inside_nextButtonEventCycle_}--;
return;
}
The second issue refers to the postNextButtonAction. According to me, it
makes no sense to leave the _NextButtonEventCycle when that routine
returns false. At the moment when you call it, the page counter has been
increased already, the next page has already been rendered and it is
impossible to go back to the previous page again. I would just execute
the routine and continue, no matter wheter it succeeds or fails.
Besides, leaving the _NextButtonEventCycle without decreasing
_inside_nextButtonEventCycle_ would generate the same problem as above.
So I would put the "return" statement in comment:
DEBUG "Before _dispatch postNextButtonAction";
if ( _dispatch( $self->cget( -postNextButtonAction ) ) ) {
DEBUG "postNextButtonAction says we should not go ahead";
# GDP: Makes no sense to leave routine here.
# Page counter is already increased anyway.
# Besides, we have to decrease _inside_nextButtonEventCycle_
anyway.
# So putting next line in comment.
# return;
}
It might be useful to populate a variable in the $self so you can query
afterwards if this routine had succeeded or not, something like
$self->lastNextButtonActionSucceeded() or so.
The file I have uploaded has an example that demonstrates the problem.
Run it in the current version of Wizard.pm, and press the next button on
page 2 while the radio button is in the first state. You will see that
then the Next button becomes unusable.
Subject: | effe2.pl |
use Tk;
use Tk::Wizard ();
use Log::Log4perl qw(:easy);
Log::Log4perl->easy_init($DEBUG);
my $wizard = Tk::Wizard->new( );
my $RadioChoice = 'N';
$wizard->addPage( sub {$wizard->blank_frame(-title => "page 1");
},
-preNextButtonAction=>sub{1}
);
$wizard->addPage( sub {$Frame1 = $wizard->blank_frame(-title => "page 2");
$Frame1->Radiobutton(-text => "Cannot goto next page. Choosing this one will make Next button unusable",
-variable => \$RadioChoice,
-value => 'N')->pack();
$Frame1->Radiobutton(-text => "Choose this one for going to next page",
-variable => \$RadioChoice,
-value => 'E')->pack();
return $Frame1;
},
-preNextButtonAction => sub { if ($RadioChoice eq 'E') {return 1;} else {return 0;} },
);
$wizard->addPage( sub {$wizard->blank_frame(-title => "page 3");
},
-preNextButtonAction=>sub{1}
);
$wizard->addPage( sub {$wizard->blank_frame(-title => "page 4");
},
);
$wizard->Show;
MainLoop;
exit;