erez_ez has asked for the wisdom of the Perl Monks concerning the following question:

Hi Monks, Recently I've written a perl GUI and used Checkbutton. I wanted to create an Entry once the Checkbutton is "on" and succeded on that. The problem is that when the Checkbutton is turned on, An entry is opened but when I turn it off it doesnt disappear. The "unpack" isnt working for me. How can I disappear the entry?? Thanks.

Replies are listed 'Best First'.
Re: Perl-tk Entry
by zentara (Cardinal) on Jul 16, 2008 at 15:26 UTC
    Here comes a dose of wisdom for you Limbic~Region, :-)

    If you destroy the entry, and try to redisplay it with the checkbutton click, you will gain memory. Tk will not clean up it's refcounts totally. So packForget the entry instead, then repack it it when the checkbutton is checked.

    BUT, it usually is better for screen appearance to leave the entry widget in place, and just change it's state.

    #!/usr/bin/perl use warnings; use strict; use Tk; my ( $entry, $cbvalue ); my $mw = tkinit; $mw->Checkbutton( -text => 'Use Entry widget below?', -variable => \$cbvalue, -command => \&SetState, )->pack; $entry = $mw->Entry->pack; SetState(); MainLoop; sub SetState { $entry->configure( -state => $cbvalue ? 'normal' : 'disabled' ); }

    I'm not really a human, but I play one on earth CandyGram for Mongo
      zentara,
      I can buy the packForget/re-pack in lieu of ->destroy. On the other hand, if I don't want something on my screen - just disabling it isn't going to cut it.

      Out of curiosity, would you mind showing a complete example of Tk::ProgressBar attached to the main window (along with other frames, menus, and other widgets) which disappears after the task is completed? That's what I used ->destroy for but would rather not have.

      Cheers - L~R

        Just to broaden your horizons a bit, Perl/Gtk2 has a neat way to handle it. You can set an entrie frame or widget to visible(0) or visible(1). That way you can multiple widgets located in one screen spot, and choose which one to show. packForgetting is clumsy compared to that.

        For an example of progressbar, see Tk-with-worker-threads. I made my own progressbar in that, because the regular Tk::Progressbar widget leaks memory on reuse, probably because it uses Photo objects internally, that leave refcounts behind. But the following works pretty well.

        #!/usr/bin/perl use strict; use Tk; use Tk::ProgressBar; #dosn't leak my $mw=MainWindow->new; $mw->geometry('+100+100'); my $tframe = $mw->Frame->pack(); my $pro_on = 0; my $count = 0; my $label = $tframe->Label( -text => 'Show Progress', )->pack(-side => 'left', -padx => 5); my $cb = $tframe->Checkbutton( -activebackground => "white", -variable => \$pro_on, -command => [ \&display_pro ] )->pack(-side => 'left'); my $bframe = $mw->Frame->pack(); my $pb = $bframe->ProgressBar( -height => 0, -width => 20, -length => 100, -colors=>[0,'blue'], -blocks=>100, -variable => \$count, )->pack(); # need to pack then unpack them to get right window size my @w = $bframe->packSlaves; foreach (@w) { $_->packForget; } MainLoop; sub display_pro { print $pro_on,"\n"; if($pro_on){ $count = 0; $bframe->pack(); $pb->pack(); # $mw->packPropagate; # $mw->update; show_progress(); }else{ my @w = $bframe->packSlaves; foreach (@w) { $_->packForget; } $bframe->packForget; } } sub show_progress{ my $timer; $timer = $mw->repeat(100,sub{ $count++; $pb->value($count); $mw->update; if($count == 100){$timer->cancel} }); } __END__

        I'm not really a human, but I play one on earth CandyGram for Mongo
Re: Perl-tk Entry
by Limbic~Region (Chancellor) on Jul 16, 2008 at 14:47 UTC
    erez_ez,
    Presumably you want to
    $entry->destroy; $mw->update;
    But without seeing code, it is hard to tell.

    Cheers - L~R

      First of all thanks for the quick response. I tried what you said with no luck... this is my code:
      use strict; use Tk; my $main = MainWindow->new; $main->minsize(qw(350 350)); $main->title("GUI"); $main->configure(); my $left3 = $main->Frame()->pack(-side=>'left'); my $padchk=0; if ($padchk==1) {$padchk=1;} else {$padchk=0;} my $padchk = $left3->Checkbutton(-variable=>\$padchk,-command=> sub{op +en_menu($padchk)})->pack(); MainLoop; sub open_menu { my $padchk= shift; my $gdsPath= shift; my $text=$left3->Label(-text=> 'enter your name:', -background=>'white +'); my $gdsPath=$left3->Entry(); if ($padchk==1){ $text->pack(); $gdsPath->pack(); } elsif ($padchk==0){ $text->destroy; $gdsPath->destroy; $left3->update; } }
      If you'll run it you'll see that each time you turn it on new entry appears but when you turn it off, it doesnt disappear. Thanks again!
        erez_ez,
        You really should use warnings. What I have does what you want, but is really a bad way of doing it - you should look at the advice from zentara. I only had a couple of minutes in between playing blocks with my 2 year old.
        #/usr/bin/perl use strict; use warnings; use Tk; my $main = MainWindow->new; $main->minsize(qw(350 350)); $main->title("GUI"); $main->configure(); my $l_frame = $main->Frame()->pack(-side => 'left'); my ($checked, $entry); my $check_box = $l_frame->Checkbutton( -variable => \$checked, -command => sub { open_menu($checked, \$entry); } )->pack(); MainLoop; sub open_menu { my ($checked, $entry) = @_; if ($checked) { $$entry = $l_frame->Label( -text => 'enter your name: ', -background => 'white' ) if ! defined $$entry; $$entry->pack(); } else { $$entry->destroy; $$entry = undef; $main->update; } }

        Cheers - L~R