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

Gurus, How to prevent users from opening more than one "newWin" windows by clicking $button1 ? If there is an existing "newWin" opened, when user clicks button1, the existing window should be in focus instead of opening new window. Thanks.
=========== use Tk; use strict; my $mw = MainWindow->new; my $button1= $mw-> Button(-text=>"newWin", -command=> sub { my $top2 = $mw -> Toplevel(); my $label1= $top2-> Label(-text=>'hi here')->pack(); } )->pack; MainLoop; ================

Replies are listed 'Best First'.
Re: how to prevent more than 1 tk Toplevel windows from opening
by zentara (Cardinal) on May 17, 2008 at 17:18 UTC
    You need to be careful about spawning a toplevel in a sub with widgets added, because you will gain some memory for each invocation. It can be done, but Tk is not too good about cleaning up after itself, especially if secondary widgets( the label) are involved. It involves a thing called the ref-count, and has been discussed many times here in more advanced questions about unwanted memory gains in Tk programs. It is best to create 1 toplevel, and control it thru withdraw, and deiconify and raise. Here is one good way.
    #!/usr/bin/perl use warnings; use strict; use Tk; my $tl; my $mw = MainWindow->new; $mw->title( "MainWindow" ); my $spawn_button = $mw->Button( -text => "Toplevel", -command => \&do_Toplevel )->pack(); MainLoop; sub do_Toplevel { $spawn_button->configure(-state=>'disabled'); if ( !Exists( $tl ) ) { $tl = $mw->Toplevel(); $tl->geometry('300x100+100+100'); $tl->title( "Toplevel" ); $tl->Button( -text => "Close", -command => sub { $tl->withdraw; $spawn_button->configure(-state=>'normal'); } )->pack; } else { $tl->deiconify(); $tl->raise(); } }

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum
      Thanks for your suggestion. I tested your code and I found one problem. If the user close the TopLevel window by clicking the X on the window's top-right corner instead of clicking the Close button., the user can not open any Toplevl window any more. Please help. Thanks
        found solution myself for my second question. OnDestroy will do the trick.. Thanks, perlmonks is a very helpful place.
        ====================== #!/usr/bin/perl use warnings; use strict; use Tk; my $tl; my $mw = MainWindow->new; $mw->title( "MainWindow" ); my $spawn_button = $mw->Button( -text => "Toplevel", -command => \&do_Toplevel )->pack(); MainLoop; sub do_Toplevel { $spawn_button->configure(-state=>'disabled'); if ( !Exists( $tl ) ) { $tl = $mw->Toplevel(); $tl ->OnDestroy( sub { $tl->withdraw; $spawn_button->configure(-state=>'normal'); } ); $tl->geometry('300x100+100+100'); $tl->title( "Toplevel" ); $tl->Button( -text => "Close", -command => sub { $tl->withdraw; $spawn_button->configure(-state=>'normal'); } )->pack; } else { $tl->deiconify(); $tl->raise(); } } ===============
        Probably a better way than using onDestroy, is to just ignore the signal.
        if ( !Exists( $tl ) ) { $tl = $mw->Toplevel(); $tl->protocol('WM_DELETE_WINDOW' => sub { print "do nothing here\n"; }); ......

        I'm not really a human, but I play one on earth. Cogito ergo sum a bum