Perl/Tk - MainLoop es szubrutin - hogyan??

 ( ardi | 2019. szeptember 17., kedd - 14:37 )

Sziasztok,

hogy mukodik a szubrutin perl/Tk alatt?

Miert fut le a szubrutinban a:

print "$i\n";

resz $i osszes ertekere es csak azutan a grafikai megjelenites:

$st=$mw->Label(-justify => 'left' ,-foreground => "#196f3d" ,-anchor => 's' ,-text => $i)->place(-x=>$dx, -y=>$dy);

Azt szeretnem elerni, hogy kinyomtassa $i erteket es rogton utana
jelenitse meg GUI-ban adott $i erteket.

Ardi

#!/usr/bin/perl
use Tk;

$dx=60;
$dy=0;
my ( $size, $step ) = ( 450, 1);

my $mw = MainWindow->new;
$mw->configure( -width=>$size, -height=>$size );
$mw->geometry('450x350+40+50'); 
$button = $mw->Button(-text => "Exit", -background => yellow, -foreground => red,  -command => sub { exit })->pack(-side => 'left', -anchor => 'n'); 
$button4 = $mw->Button(-text => "Runx",-background => yellow,-foreground => blue, -command => \&say)->pack(-side => 'left', -anchor => 'n');


sub say{
         for (my $i=0; $i <= 3; $i++) 
         {
           print "$i\n";
           $st=$mw->Label(-justify => 'left' ,-foreground => "#196f3d" ,-anchor => 's' ,-text => $i)->place(-x=>$dx, -y=>$dy);
           sleep(2);
           $dy=$dy+20;
    }
}
     
MainLoop;

Hozzászólás megjelenítési lehetőségek

A választott hozzászólás megjelenítési mód a „Beállítás” gombbal rögzíthető.

A Tk egy eseményvezérelt GUI framework, ami azt jelenti, hogy miután bekonfiguráltad a gombjaidat és címkéidet, meghívod a MainLoop függvényt, és ezzel átadod a vezérlést a Tk fő ciklusának, amely vár a bejövő eseményekre (pl. egérmozdulatok, billentyűleütések az ablakban, vagy éppen új címkék létrejötte), és feldolgozza azokat (pl. újrarajzolja az ablakot az aktuális tartalommal).

Ellenben amikor a gomb megnyomására meghívódik a te say nevű callback függvényed, akkor visszaveszed a vezérlést, és nem is adod vissza a kis for ciklusod végéig. Így a Tk-nak nincs esélye reagálni az eseményekre, a GUI be van fagyva, amíg vissza nem kapja a vezérlést a callbacktól.

"Megoldás": kell egy $mw->update a sleep sor elé. Ezzel átmenetileg visszaadod a vezérlést a Tk-nak, hogy dolgozza fel a függőben lévő eseményeket. Ez első közelítésre megoldja a problémádat és a programod azt csinálja, amit szeretnél: az ablakban kb. ugyanakkor jelenik meg a címke, mint a print eredménye a konzolban.

Valójában azonban még mindig hibás a program, a callback-ben használt sleep miatt. A sleep blokkol, addig a 2 másodpercig a programod nem csinál semmit, a GUI eseményeket sem dolgozza fel. Általában az a szabály, hogy eseményvezérelt programban (GUI programban) sleepet vagy más blokkoló műveletet nem szabad használni, mert befagyasztod velük az egész GUI-t.

A helyes megoldás a Tk által adott periodikus időzítő (repeat) használata. Ezzel az eseménykezelőre bízod az ütemezést, a címke hozzáadása a megfelelő időben fog lefutni, miközben a felület végig reszponzív marad.

#!/usr/bin/perl
use strict;
use warnings;
use Tk;

my $dx = 60;
my $dy = 100;
my ($size, $step) = (450, 1);

my $timer;

my $mw = MainWindow->new;
$mw->configure(-width => $size, -height => $size);
$mw->geometry('450x350+40+50');
my $button = $mw->Button(-text => "Exit", -background => 'yellow', -foreground => 'red',  -command => sub { exit })->pack(-side => 'left', -anchor => 'n');
my $button4 = $mw->Button(-text => "Runx",-background => 'yellow',-foreground => 'blue', -command => \&start)->pack(-side => 'left', -anchor => 'n');

my $number = 0;

sub start {
        add_label();
        $timer = $mw->repeat(2000, \&add_label);
}

sub add_label {
           print "$number\n";
           $mw->Label(-justify => 'left' ,-foreground => "#196f3d" ,-anchor => 's' ,-text => $number)->place(-x=>$dx, -y=>$dy);
           $dy=$dy+20;
           $number++;
           if ($number > 3 and defined $timer) {
                $timer->cancel;
                undef $timer;
           }
}

MainLoop;

Szuper,

ereztem, hogy vmi bibi van a GUI loop-pal.
Bratom is vmi hasonlot ajanlott.

Koszi szepen mindenkinek a segitseget.
Ardi