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

Hello monks,
I really need some help with this because I don't understand how I can get it to work the way I want it to.

Basically my problem is that I want to call a sub which opens a new GUI window and then destroys the current one so there is only one window open. I'll write out an example of a package and stick in a comment " $mw => 'destroy' " where I want it to happen. I don't know if this problem is trivial or not since everything I have tried hasn't worked but I'm open to suggestions (ps: i looked at perls wizard package but i didn't understand it much, but i'm sure there is a way to do this without using it.)

Here's the code:

package example; use vars qw(@ISA @EXPORT @EXPORT_OK); use Exporter; @ISA = qw(Exporter); # Symbols to autoexport (:DEFAULT tag) @EXPORT = qw( ex1 ex2 %program_config ); use vars qw(%program_config); use Tk; sub ex1(){ my $mw = MainWindow->new; $mw->title("example_window1"); $mw->MainWindow->Frame( -relief=>'groove'); $mw->minsize(600,300); my $bf = $mw-> Frame( -pady => '5') ->pack( -side => 'bottom', -anchor=>'se'); my $cancel = $bf -> Button( -relief=> 'raised', -borderwidth => '2', -text => "Cancel", -command => [$mw => 'destroy']) ->pack( -side => 'right', -padx => '20'); my $next = $bf -> Button( -relief=> 'raised', -borderwidth => '2', -text => "Next", -command => sub {ex2();}, # This is where i want it to kill the window (after the #other sub has been called) # $mw => 'destroy'] ) ->pack( -side => 'right'); my $back = $bf -> Button( -relief=> 'raised', -borderwidth => '2', -text => "Back") ->pack( -side => 'right'); MainLoop; } sub ex2(){ my $mw = MainWindow->new; $mw->title("example_window2"); $mw->MainWindow->Frame( -relief=>'groove'); $mw->minsize(600,300); my $msg = $mw -> Message(-text => "Just an example")->pack(); my $bf = $mw-> Frame( -pady => '5') ->pack( -side => 'bottom', -anchor=>'se'); my $finish = $bf -> Button( -relief=> 'raised', -borderwidth => '2', -text => "Finish", -command => [$mw => 'destroy']) ->pack( -side => 'right', -padx => '20'); MainLoop; }
PS: It also doesn't add the image if I add this code in the sub although if the code is outside a sub it seems to work fine, any ideas?
my $image = $mw->Photo( -file => "saraLogo2.gif"); $mw->Label( -image => 'image1') ->pack( -side=> "left", -anchor => 'n');
Thanks a million everyone for your help, it is much appreciated and sorry for the long post.

Replies are listed 'Best First'.
Re: window destroying
by moot (Chaplain) on Mar 28, 2005 at 17:43 UTC
    Change the relevant line(s) to:
    -command => [ sub { $mw->destroy(); ex2();} ],
    presto change-o! $mw is destroyed and ex2's window is created.

    With the current code, ex2() doesn't exit until its MainLoop is finished, so the second command (to destroy $mw) isn't executed until after ex2()'s window is closed.

      Thanks a lot, I could have sworn I tried that and it didn't work but it just worked now so I guess I didn't, maybe what I tried was the other way around or with the square brackets or something.

      Now I just need to solve my problem with the image hehe.

Re: window destroying
by zentara (Cardinal) on Mar 28, 2005 at 20:09 UTC
    First, your PS image problem is obvious. You create $image fine, but you call it 'image1' in the label. It should be
    -image => $image,

    Second, in your main problem, I'm not sure what you are trying to do, but I am "pretty sure" you are doing it the wrong way. You are setting yourself up for "pseudo memory leaks" in trying to destroy, then create another window.

    What will probably happen, if you run this code for a long period, opening then destroying windows, the memory usage of your program will just keep "going up",( a big chunk for each window you create and destroy). Tk stores alot of references to windows and widgets, and it is nearly impossible to write a Tk program which properly (and completely) destroy a window.

    What you want to do, is to create 1 mainwindow, and a top-level window. Then "withdraw" them. When you want to raise them, you can do

    $mw->deiconify; $mw->raise; #or $top1->deiconify; $top1->raise;
    Then instead of destroying them, when you are done, just
    $mw->withdraw; #or $top1->withdraw;

    Now you are reusing your windows, and no matter how many times you raise and withdraw them, your memory will stay level. You can also repack the windows with different widgets, while they are withdrawn, so they can "appear to be" totally new windows.

    With Tk, always design to reuse widgets. If you want to change that image, don't destroy it, just configure $image to load a different file.

    Finally, having 2 MainLoops, is probably asking for trouble. You should only need a single MainLoop in any Tk program, unless you are forking.

    I'm sorry if I seemed super critical of your script, but I'm just trying to save you time, because if you write 1000 lines of code, then find out it leaks memory, it will be quite disappointing. I learned "the hard way". :-)


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