in reply to $mw->OnDestroy and Dialog Box

Hi Graham Drabble,

It's true that you can use OnDestroy to invoke some code when a widget is destroyed, but only if it's not the MainWindow.  If it's the MainWindow that's destroyed, it's too late, as you've discovered.

Here's a way to test it.  With some slight modifications to your code and the addition of a boolean variable $b_destroy_button you can try running the following:

use strict; use warnings; use Tk; use Tk::DialogBox; # User-defined my $b_destroy_button = 0; # If set, destroy the Button, not the MainW +indow # Main program my $mw = MainWindow->new(); my $button = $mw->Button(-text => 'Exit'); # Choose which widget to destroy my $psub; ($b_destroy_button) or $psub = sub { $mw->destroy() }; ($b_destroy_button) and $psub = sub { $button->destroy() }; $button->configure(-command => $psub); $button->pack(-side => 'right', -ipadx => 10, -padx => 30); $button->OnDestroy(\&exit_app); MainLoop; # Subroutines sub exit_app{ print "1\n"; my $db = $mw->DialogBox(-title => 'Error',-buttons => ['CSV','Aban +don']); my $text = "Do you wish to save a new CSV file or abandon changes? +"; $db->Label(-text => $text)->pack(); my $button = $db->Show(); if ($button eq 'CSV'){ save_csv(); } } sub save_csv{ return 1; }

Now if you run it "as is", you'll get the same behavior, because destroying the MainWindow causes a problem.

But when you destroy just the Button instead, by changing the value of $b_destroy_button to 1, it will successfully give you the DialogBox you want.

An alternative way to do this (if you don't want to have to destroy a widget before taking the action of possibly writing the CSV file), is to just put the call to exit_app() in the callback for the Button.  Then, after you're done writing the CSV file (or not), you can have the callback destroy the application, like so:

use strict; use warnings; use Tk; use Tk::DialogBox; # Main program my $mw = MainWindow->new(); my $button = $mw->Button(-text => 'Exit'); $button->configure(-command => \&exit_app); $button->pack(-side => 'right', -ipadx => 10, -padx => 30); MainLoop; # Subroutines sub exit_app{ print "1\n"; my $db = $mw->DialogBox(-title => 'Error',-buttons => ['CSV','Aban +don']); my $text = "Do you wish to save a new CSV file or abandon changes? +"; $db->Label(-text => $text)->pack(); my $button = $db->Show(); if ($button eq 'CSV'){ save_csv(); } $mw->destroy(); } sub save_csv{ return 1; }

s''(q.S:$/9=(T1';s;(..)(..);$..=substr+crypt($1,$2),2,3;eg;print$..$/

Replies are listed 'Best First'.
Re^2: $mw->OnDestroy and Dialog Box
by Graham Drabble (Initiate) on Mar 15, 2007 at 13:21 UTC

    I had tried the latter example. The problem is that the exit_app() sub gets bypassed if you shut down using the 'X' button rather than the 'Exit' button.

    I have come up with

    use strict; use warnings; use Tk; use Tk::DialogBox; my $exit_pressed = 0; my $mw = MainWindow->new(); $mw->OnDestroy(\&exit_x); $mw->Button(-text => 'Exit', -command=> \&exit_app)->pack(-side=>'righ +t', -ipadx => 10, -padx=>30); MainLoop; sub exit_app{ print "1"; $exit_pressed = 1; my $db = $mw->DialogBox(-title => 'Save?',-buttons => ['CSV',' +Abandon']); $db->Label(-text => "Do you wish to save a new CSV file or aba +ndon changes?")->pack(); my $button = $db->Show(); if ($button eq 'CSV'){ save_csv(); } $mw->destroy(); } sub save_csv{ return 1; } sub exit_x{ unless ($exit_pressed){ print "2"; my $check = MainWindow->new(-title=> 'Save?'); $check->Label(-text => "Do you wish to save a new CSV file + or abandon changes?")->pack(); $check->Button(-text => 'CSV', -command => sub { save_csv( +);$check->destroy();})->pack(-side=>'bottom'); $check->Button(-text => 'Abandon', -command => sub {$check +->destroy();})->pack(-side=>'bottom'); } }

    However it a) isn't elegant from a code point of view, b) means that the screen (which will contain data) is closed before the option to have it is displayed and c)It will be hard to make the 2 save windows look the same.