in reply to Perl Tk , MainLoop, destroy function problem

The code has two while loops. The inner while loop works fine, but the outer while loop which is responsible for reading the file every 5 secs is not working. After every 5 secs I am trying to destroy the Tk objects and re-constructing them again.

It is very bad to use a while loop and/or sleep() in any GUI program, as it interferes with the GUI's event loop. That is why you get a window only when you comment the outer while loop.

Your code is seriously messed up, and needs a pretty major rewrite to get it working. As a start, you need to remove your while loops and use timers to get your 1 second and 5 second intervals to work with the GUI.

Finally, the Hlist has an internal path counter, and instead of destroying the existing Hlist for the next update, you should reconfigure the existing Hlist paths. Your idea to destroy and recreate the Hlist for updates will almost certainly lead to unwanted memory gains in the process.

So, without me wasting all fff'ing morning on this, here is a general guide as to setup your program. I left out the rebuilding of the HList for now, until you can load your data successfully.... as you can see from the $1 $2 $3 printouts, your regex is broken.

See ztkdb for how to handle an Hlist.

#!/usr/bin/perl use Tk; use Tk::HList; use Tk::ItemStyle; use Data::Dumper; my $user = $ARGV[0] || 'alex'; my $hash = {}; my ($tool,$issued,$use,$vendor,$feature); #gui variables my ($hl,$ok,$alert); # Making the Gui my $mw = new MainWindow; $mw->geometry("500x200"); my $userframe = $mw->Frame(-width=>5,-height=>10)->pack(-side=>'top',- +anchor=>'nw'); $userframe->Label(-text => "USER: $user")->pack(-anchor => 'nw',-padx +=> 0); my $hlistframe = $mw->Frame()->pack(-fill => 'both', -expand => 1); $hl = $hlistframe->Scrolled('HList', -scrollbars => 'ose', -columns =>4 , -header => 1, -width => 100, -command => sub {print "AAA\n";}, -selectmode => 'browse', )->pack(-fill => 'both',-expand =>1 ); my $label1 = $hl->Label(-text => "Tool", -anchor => 'w'); $hl->headerCreate(0,-itemtype => 'window',-widget => $label1); my $label3 = $hl->Label(-text => "Available", -anchor => 'w'); $hl->headerCreate(1,-itemtype => 'window',-widget => $label3); my $label4 = $hl->Label(-text => "checkedout", -anchor => 'w'); $hl->headerCreate(2,-itemtype => 'window',-widget => $label4); my $label5 = $hl->Label(-text => "checkedout%", -anchor => 'w'); $hl->headerCreate(3,-itemtype => 'window',-widget => $label5); $ok = $hl->ItemStyle('text', -selectforeground =>'black', -anchor => +'center',-background =>'green'); $alert = $hl->ItemStyle('text', -selectforeground =>'black', -anchor + =>'center',-background =>'red'); open_report(); my $timer = $mw->repeat(1000, \&open_report); # my $timer1 = $mw->repeat(5000, \&clear_data); MainLoop; sub clear_data{ # fix your loading data problem first, before # worrying about clearing out the Hlist # you will probably get a memory gain unless you # reuse the Hlist, so don't try to destroy the Hlist # but just reconfigure the existing paths } sub open_report{ open(FP, "< 1report"); while(<FP>){ if(/^Users of (\w+):\s+\(Total of ([0-9]+) licenses issued;\s+Total +of ([0-9]+) (licenses|license) in use/) { ($tool,$issued,$use) = ($1,$2,$3); print "$1 $2 $3\n"; } if (/^\s+$user(.*)/){ $hash->{$user}->{$tool}->{tool} = $tool; $hash->{$user}->{$tool}->{issued} = $issued; $hash->{$user}->{$tool}->{inuse} = $use; print "2\n"; } } print "3\n"; close(FP); print Dumper($hash); my $path = 0; for my $toolkey (sort keys %{$hash->{$user}}){ _insertData($path,$toolkey); $path++; } # sleep 5; #not working # NEVER USE SLEEP IN A GUI !!!!!! # $hl->destroy; #not working #} } sub _insertData { my $path = shift; my $tool = shift; my $availbl = $hash->{$user}->{$tool}->{issued}; my $chk = $hash->{$user}->{$tool}->{inuse}; $hl->add($path); $hl->itemCreate($path,0,-text=> $hash->{$user}->{$tool}->{tool}); $hl->itemCreate($path,1,-text=> $hash->{$user}->{$tool}->{issued}) +; $hl->itemCreate($path,2,-text=> $hash->{$user}->{$tool}->{inuse}); my ($percent_lic_co,$color)= calculate_percent($availbl,$chk); $hl->itemCreate($path,3,-text=> $hash->{$user}->{$tool}->{inuse}, +-style => $color); } sub calculate_percent { my $avail = shift; my $co = shift; my $percent = ($co * 100)/$avail ; $percent = sprintf "%.2f", $percent; my $color; if($percent > 90) { $color = $alert; } else { $color = $ok; } return ($percent,$color); }

I'm not really a human, but I play one on earth.
Old Perl Programmer Haiku ................... flash japh

Replies are listed 'Best First'.
Re^2: Perl Tk , MainLoop, destroy function problem
by ghosh123 (Monk) on Feb 19, 2013 at 14:15 UTC
    Thanks a lot for replying. I will try with that clear_data() and get back to you.
Re^2: Perl Tk , MainLoop, destroy function problem
by ghosh123 (Monk) on Feb 20, 2013 at 13:29 UTC

    Hi zentara,

    I need a help regarding configuring this hlist.
    The _insertData() is working for the first time, but next
    time when it gets invoked thru repeat(),
    I am getting the following error :
    XS_Tk__Callback_Call error:element "0" already exists at /opt/perl_5.8.8/lib/Tk.pm line 250.

    I ma stuck here, please help. Not able to figure ou from the tar files you sent me.

      Hi, Yes I know the problem and it is why I mentioned to you the fact that Hlist maintains an internal counter that can't ( as far as I know ) be changed. In essence what it means is that once you itemCreate a path 0 ( or 1,2,3 etc) it is always maintained inside the Hlist. So if you delete path 0 ( or which ever path you please ) you cannot itemCreate it again, you can only itemConfigure it. You can get the number of paths in the Hlist by using my @entries = $h->info('children');

      Here is a simple example which shows all the methods fairly clearly.

      #!/usr/bin/perl use strict; use Tk; use Tk::HList; my $mw = MainWindow->new(); #create some sample data my %data; foreach (0..100) { $data{$_}{'name'} = 'name'.$_; $data{$_}{'id'} = rand(time); } #get random list of keys my @keys = keys %data; ################# my $h = $mw->Scrolled( 'HList', -header => 1, -columns => 2, -width => 30, -height => 60, -takefocus => 1, -background => 'steelblue', -foreground =>'snow', -selectmode => 'single', -selectforeground => 'pink', -selectbackground => 'black', # -browsecmd => \&browseThis, )->pack(-side => "left", -anchor => "n"); my $nameh = $h->header('create', 0, -text => ' Name ', -borderwidth => 3, -headerbackground => 'steelblue', -relief => 'raised'); my $idh = $h->header('create', 1, -text => ' ID ', -borderwidth => 3, -headerbackground => 'lightsteelblue', -relief => 'raised'); foreach (@keys) { my $e = $h->addchild(""); #will add at end $h->itemCreate ($e, 0, -itemtype => 'text', -text => $data{$_}{'name'}, ); $h->itemCreate($e, 1, -itemtype => 'text', -text => $data{$_}{'id'}, ); } my $button = $mw->Button(-text => 'exit', -command => sub{exit})->pack; my $sortid = $mw->Button(-text => 'Sort by Id', -command => [\&sort_me,1] )->pack; MainLoop; ######################################################### sub sort_me{ my $col = shift; my @entries = $h->info('children'); my @to_be_sorted =(); foreach my $entry(@entries){ push @to_be_sorted, [ $h->itemCget($entry,0,'text'), $h->itemCget($entry,1,'text') ]; } my @sorted = sort{ $a->[$col] cmp $b->[$col] } @to_be_sorted; my $entry = 0; foreach my $aref (@sorted){ # print $aref->[0],' ',$aref->[1],"\n"; $h->itemConfigure( $entry, 0, 'text' => $aref->[0] ); $h->itemConfigure( $entry, 1, 'text' => $aref->[1] ); $entry++; } $mw->update; }

      I'm not really a human, but I play one on earth.
      Old Perl Programmer Haiku ................... flash japh

        Hi

        Thank you for your reply !
        But still one more thing is not working, though I am following the cpan doc for HList. I have tried using both itemExists($entrypath,$col) and info(exists, $entrypath), but of no use.
        The scenario is like :
        The gui always has two columns , no issue on that. But first time the gui has one row, so entrypath 0 is added and I used itemCreate() to populate values.
        Next time due to updation of the input file the gui should have some 3 rows with entirely new data. This time for entrypath 0 , the if(itemExists) returns true and I am using itemConfigure inside the if block. All fine so far. But next iteration for entrypath 1, itemExists should fail and I should be able to go to the else block to add() and itemCreate(), but I am not able to.
        I am getting following error :

        XS_Tk__Callback_Call error:Entry "1" not found at /user/perl_5.8.8/lib/Tk.pm line 250.
        Tk::Error: Entry "1" not found at /opt/perl_5.8.8/lib/Tk.pm line 250.
        Tk::Error:: Too many arguments.
        Tk callback for .frame1.frame.hlist
        Tk::After::repeat at /opt/perl_5.8.8/lib/Tk/After.pm line 79
        [repeat,[{},after#12,5000,repeat,\&main::clear_data]]
        [repeat,[{},after#12,5000,repeat,&main::clear_data]]: No match.
        Here is the code snipppet which is not working

        if($hl->itemExists($path,0)){ #if($hl->info(exists, $path)){ # tried both info and itemExist alterna +tely, but :( print "itemexists ...\n"; $hl->itemConfigure($path,0,-text=> $hash->{$user}->{$tool}->{tool} +); $hl->itemConfigure($path,1,-text=> $hash->{$user}->{$tool}->{issue +d}) ; $hl->itemConfigure($path,2,-text=> $hash->{$user}->{$tool}->{inuse +}); $hl->itemConfigure($path,3,-text=> $hash->{$user}->{$tool}->{in +use}, -style => $color); } else { print "Inside else ....\n"; $hl->add($path); $hl->itemCreate($path,0,-text=> $hash->{$user}->{$tool}->{tool}); $hl->itemCreate($path,1,-text=> $hash->{$user}->{$tool}->{issued}) ; $hl->itemCreate($path,2,-text=> $hash->{$user}->{$tool}->{inuse}); $hl->itemCreate($path,3,-text=> $hash->{$user}->{$tool}->{inuse}, -style => $color); }