Jestem nowicjuszem w TK i chciałbym się dowiedzieć, czy problem dotyczy normalnego zachowania Tk, czy nie.Dlaczego wywołania waitVariable nie są niezależne, nawet jeśli użyto innej zmiennej ref?
W skrócie: Mam skrypt Perl/Tk (Tk wersja 804.028), który używa dwóch widgetów Tk :: ExecuteCommand (v1.6). Takie obiekty mają metodę execute_command, która używa zdefiniowanego wywołania zwrotnego fileevent do odczytania stdout polecenia wykonanego i powraca po jego zakończeniu. Jest rozwiązywany za pomocą funkcji waitVariable. Ale wygląda na to, że jeśli dwa ExecuteCommand zaczęły się razem, zwracają się tylko wtedy, gdy powraca wolniej. Mogę się spodziewać, że szybciej powróci natychmiast po zakończeniu.
zrobiłem mały test skrypt Perl/Tk wykazać 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();
Rysuje widget ROText i 4 przyciski ([DO 0] [Stop 0] [uwagi 1] [stop 1]) (patrz załączony rysunek). Kliknięcie przycisku Do wywołuje funkcję doo
, która czeka aż zmieniony przypisany skalar. Zmienne zmieniają się po naciśnięciu przycisku Stop.
Po naciśnięciu przycisków w kolejności [Do 0] [Stop 0] [Do 1] [Stop 1] wyjście wydaje się być w porządku (patrz wiersze 2-7). Ale jeśli "zadania" rozpoczęły się równolegle, oba wywołania zwrotne kończą się, gdy oba zostaną zatrzymane. Zatem naciśnięcie Przycisków w [Do 0] [Do 1] [Stop 0] [Stop 1] (patrz wiersze 8-13) daje dziwny wynik (patrz zdjęcie).
Moje oczekiwanie na drugim badaniu było to, że pierwsza funkcja zwrotna zwraca natychmiast po naciśnięciu przycisku pierwszy przystanek. Więc myślę, że wyjście powinno być:
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
Działa na komputerze z systemem Linux.
Czy brakuje mi czegoś? Z góry dziękuję!
UPDATE
Aby obejść ten problem, ja waitVariable przepisał ten widget zamiast użyć wywołania zwrotne (dzięki Tantala!). Teraz execute_command natychmiast zwraca. Istnieją dwa wywołania zwrotne, jeden dla anulowania, drugi dla zakończenia. Teraz dzwoniący jest informowany przez te wywołania zwrotne. W każdym razie gdzieś czytam (nie mogę znaleźć źródła), że czekanie w callbacku długo nie jest dobrym pomysłem w Tk. Nowe rozwiązanie jest z tym zgodne.
Dziękuję za pomoc!
Świetnie! Dzięki! Czy znasz sposób implementacji funkcji waitVariable, która działa niezależnie? Próbowałem zaimplementować przy użyciu odpytywania, ale wydaje się, że $ widget-> after (ms) również nie może obsłużyć dwóch timerów niezależnie. – TrueY
Przepraszamy. Dodałabym to, co zrobiłem. – ikegami
Wreszcie znalazłem cytowany tekst w dokumentacji Tk, a nie w Perlu/Tk. Postanowiłem zrezygnować z użycia funkcji waitVariable, a zamiast nich nie są używane wywołania zwrotne ... Dzięki! Świetna pomoc! – TrueY