Change the text of a Tk label asynchronously

1.4k Views Asked by At

I need graphical output from a Perl program. The window has a label status field and should show what programming code decides.

How do I change the text of a label field after the window has been created without any buttons?

I have the following:

use Tk;

$mw = Tk::MainWindow->new(-title => 'Status Window',-bg=>"white");    
$mw->geometry ("400x200+0+0");     

$lala = $mw->Label(-text => "Current Status")->grid(-row=>0,-column=>0);    

$mw->bind( 'all' => '<Key-Escape>' => sub {exit;} );

MainLoop;

How do I incorporate the following subroutine so that it is run automatically after the window is created? Label-Widget does not have a -command field. It should start immediately and not wait for a event to happen

sub calculate() {

    for ( $i = 0; $i < 10; $i++ ) {
        sleep 2s;
        $lala->configure(-text=>"Current Status : $i");
    }
}
1

There are 1 best solutions below

0
Håkon Hægland On

The following seems to work. I used after() to run code after 100 ms then used update() to redraw window:

use feature qw(say);
use strict;
use warnings;

use Tk;

my $mw = Tk::MainWindow->new(-title => 'Status Window',-bg=>"white");    
$mw->geometry ("400x200+0+0");     
my $lala = $mw->Label(-text => "Current Status")->grid(-row=>0,-column=>0);    
$mw->bind('all'=> '<Key-Escape>' => sub {exit;});

$lala->after(100, \&calculate ); 
MainLoop;

sub calculate() {
    for(my $i=0; $i<10; $i++){
        sleep 1;
        $lala->configure(-text=>"Current Status : $i");
        $mw->update();
    }
}

Edit:

The above code blocks during the sleep 1 call, so any input for the Tk event loop will will be delayed. In particular, pressing Esc to quit the application will not work immediately. It will be blocked until sleep returns. To solve this, one can use Tk's repeat() instead of sleep and Tk's after(), and cancel the repeat if necessary:

my $repeat_count = 10;
my $timer_id = $lala->repeat(1000, \&calculate ); 

MainLoop;

sub calculate() {
    $lala->configure(-text=>"Current Status : $repeat_count");
    if ( --$repeat_count == 0) {
        $timer_id->cancel;
    }
}