I'm new to Tk and I'd like to know whether the issue in question is a normal Tk behavior or not.
In short: I have a Perl/Tk (Tk version 804.028) script which uses two Tk::ExecuteCommand (v1.6) widgets. Such objects have an execute_command method which uses the defined fileevent callback to read the executed command's stdout and returns after it is finished. It is solved with the usage of waitVariable. But it seems if two ExecuteCommand started together they returns only when the slower returns. I may expect that the faster returns immediately, when finished.
I made a small test Perl/Tk script to demonstrate the problem:
#!/usr/bin/perl
use strict;
use warnings;
use Tk;
use Tk::ROText;
my $MAIN = new MainWindow -title => "TEST";
my $text = $MAIN->Scrolled('ROText')->pack(qw/-expand 1 -fill both/);
sub pr { # Write into ROText widget
$text->insert('end', join '', @_); $text->yview('end');
}
pr "Tk version ", Tk->VERSION, "\n";
my @v = (100, 200);
sub doo { # Button callback
my ($rv, $txt) = @_;
pr "B4 wait: $txt, ref=$rv, val=", $$rv, "\n";
$MAIN->waitVariable($rv);
pr "Aft wait: $txt, ref=$rv, val=", $$rv, "\n";
}
$MAIN->Button(-text => 'Do 0', -command => [\&doo, \$v[0], "Do 0" ]
)->pack(qw/-expand 1 -side left -fill both/);
$MAIN->Button(-text => 'Stop 0', -command => [sub {++$v[0]; pr "Stop 0\n";} ]
)->pack(qw/-expand 1 -side left -fill both/);
$MAIN->Button(-text => 'Do 1', -command => [\&doo, \$v[1], "Do 1" ]
)->pack(qw/-expand 1 -side left -fill both/);
$MAIN->Button(-text => 'Stop 1', -command => [sub {++$v[1]; pr "Stop 1\n";} ]
)->pack(qw/-expand 1 -side left -fill both/);
MainLoop();
This draws an ROText widget and 4 Buttons ([Do 0][Stop 0][Do 1][Stop 1]) (see attached picture). Clicking on a Do button, calls the function doo
, which waits until the assigned scalar has changed. The variables are changed when a Stop button is pressed.
If the buttons are pressed in the [Do 0][Stop 0][Do 1][Stop 1] order the output seems to be ok (see lines 2-7). But if the "tasks" started in parallel then both callback finishes only if both are stopped. So pressing the Buttons in [Do 0][Do 1][Stop 0][Stop 1] (see lines 8-13) gives a weird result (see picture).
My expectation for the second test was that the first callback function returns immediately after pressing the first Stop Button. So I think output should be:
B4 wait: Do 0, ref=SCALAR(0x9970560), val=101
B4 wait: Do 1, ref=SCALAR(0x9970bfc), val=201
Stop 0
Aft wait: Do 0, ref=SCALAR(0x9970560), val=102
Stop 1
Aft wait: Do 1, ref=SCALAR(0x9970bfc), val=202
It runs on a Linux machine.
Am I missing something? Thanks in advance!
UPDATE
To bypass this waitVariable issue I rewrote this widget to use callbacks instead (thanks to Tantalus!). Now execute_command returns immediately. There are two callbacks, one for Cancel, one for Finish. Now the caller is informed through these callbacks. Anyway I read somewhere (I cannot find the source now) that waiting in a callback for long is not a good idea in Tk. The new solution is compliant with this.
Thank for your help!
Emphasis mine.