Subject: | Tk::Button::Invoke() calls idletasks causing race conditions |
Tk::Button::Invoke() calls idletasks in between saving and restoring
Buttons -state and before actually invoking the callback. This changes
order of events processed - and worse it overwrites any changes made to
Buttons -state from other pending events.
Here is an example:
use strict;
use warnings;
use Tk;
use Tk::Button;
my $b;
my $main= MainWindow->new();
$b = $main->Button(
-text=> 'test',
-command=> sub{print "do work\n"; },
)->pack();
$b->focus ;
$main->update;
$main->afterIdle(sub{$b->eventGenerate('<Return>')});
$main->afterIdle(sub{$b->configure(-state => 'disabled');
print "set buttons state to disabled\n";
}
);
MainLoop;
expected output:
do work
set buttons state to disabled
resulting in a disabled Button after startup.
instead I see:
set buttons state to disabled
do work
and an active Button displayed.
Take a look at Tk::Button::Invoke() (Buttons <Return> handler)
sub Invoke
{
my $w = shift;
if ($w->cget('-state') ne 'disabled')
{
my $oldRelief = $w->cget('-relief');
my $oldState = $w->cget('-state');
$w->configure('-state' => 'active', '-relief' => 'sunken');
$w->idletasks;
$w->after(100);
my $state = $w->cget('-state');
$w->configure('-state' => $oldState, '-relief' => $oldRelief);
$w->invoke;
}
}
The problem is obvious: commenting out the idletasks call fixes
behaviour but then the virtual 'ButtonPress' action won't get displayed.
Is there any alternative to idletasks in the library, which would make
it possible to update the Buttons view without processing other IDLE
events??
Cheers, Christoph