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

Hello gurus, I have this client/server app that keeps track of system IP address on a server. The client app uses perl/Tk and runs on a win32 platform. The client has been running great until my boss asked me to add a search component to it. The search component works exactly the way it is supposed, but the problem I am having is with the search dialogbox.

How the search works:
The client has a listbox that lists all the IPs. The search opens a dialogbox that takes the input for the search. If the search finds one match it highlights that ip in the listbox (works great). When the search finds more than one match it opens another dialogbox with the results. The user can then double click one of the results to have it highlight it in the listbox (also works great), and then close (destroy) the dialog box.

Here is the problem I am seeing: When I get the results dialogbox and double click a result, the dialogbox closes and the ip is highlighted. Then if I try to close the client using the windows "X" (standard windows close button), the app closes but the process is still there. I have tested it a bunch of different ways and it seems to have to do with the destroy of the dialogbox. If I never destroy it, the close works great. I was wondering if I was doing this wrong or if there was another way of doing it.

For now I have added this line to overcome the problem:
$top->protocol( 'WM_DELETE_WINDOW', sub{} );


search code (first sub called is search):
sub getSearch { my $dialog = $top->DialogBox( -title => "MxFWcon Search", -buttons => [ "Search", "Cancel" ], ); $dialog->add("Label", -text=> "MxFWcon Search")->grid(-row => '0', + -column => '0', -columnspan => 2); $dialog->add("Label", -text=> "IP:")->grid(-row => '2', -column => + '0', -stick => "e"); my $ip = $dialog->add("Entry", -width => 20)->grid(-row => '2', -c +olumn => '1'); return ($dialog, $ip); } sub getResults { my $list = shift; my $dialog = $top->DialogBox( -title => "MxFWcon Search", -buttons => [ "Done" ], ); $dialog->add("Label", -text=> "MxFWcon Search")->grid(-row => '0', + -column => '0', -columnspan => 2); my $scroll = $dialog->add("Scrollbar", -orient => 'vertical')->gri +d(-row => '2', -column => '1'); my $ltb = $dialog->add("Listbox", -background => 'white', -height => '4', -width => '30', -yscrollcommand => ['set' => $scroll], )->grid(-row => '2', -column => '0'); $scroll->configure(-command => ['yview' => $ltb]); foreach my $item(keys %$list) { $ltb->insert('end', $list->{$item}); } $ltb->bind("<Double-1>", sub { searchGet($dialog, $ltb);}); return ($dialog); } sub searchGet { my ($dialog, $ltb) = @_; if ((my $sel = $ltb->curselection()) !~ /^$/) { my $ip = $ltb->get($sel); my $lk1 = $vars->{lk1}; my @ips = $lk1->get(0,'end'); my $x = 0; foreach my $item(@ips) { if ($item eq $ip) { setBlock($x); $dialog->destroy; return; } $x++; } } return; } sub setBlock { my $sel = shift; my $lk1 = $vars->{lk1}; $lk1->selection('clear', 0, 'end'); $lk1->selection('set', $sel); $lk1->see($sel); } sub search { my $lk1 = $vars->{lk1}; my ($dialog, $ip) = getSearch(); my $ans = $dialog->Show(); if ($ans eq "Search") { my $sip = $ip->get; $sip =~ s/\s*//g; my %list; my @ips = $lk1->get(0,'end'); my $x = 0; foreach my $item(@ips) { if ($item =~ /^$sip/) { $list{$x} = $item; } $x++; } my $found = keys(%list); if ($found > 1) { my $res = getResults(\%list); $res->Show(); } elsif ($found == 1) { my ($x, $y) = each(%list); setBlock($x); } else { getMess("IP: $sip NOT found in the list", "MxFWcon Sea +rch"); } } return; }

Replies are listed 'Best First'.
Re: Problems with perl/Tk dialogbox destroy
by bbfu (Curate) on Jun 11, 2003 at 22:02 UTC

    The simple solution; replace:

      $dialog->destroy;

    With:

      $dialog->Subwidget('Done')->Invoke();

    Ok, now for the long explanation...

    Your problem lies with the following:

    sub getResults { # ... $ltb->bind("<Double-1>", sub { searchGet($dialog, $ltb);}); # ... } sub searchGet { # ... $dialog->destroy; # ... }

    When you Show() a Tk::DialogBox, it calls $toplevel->waitVariable(...) to create modality (ie, so that it doesn't return until the user has clicked a button). So that the application doesn't freeze while waiting, waitVariable() processes any events normally. Therefore, your bind() handler is actually called while the DialogBox is still waiting for a(n internal) variable to change (ie, a button to be clicked).

    When your double-click handler is invoked and calls searchGet(), which then destroys the DialogBox, Tk is still waiting for that variable to change. Tk dutifully continues to wait even after the MainWindow is closed. Incidentally, the DialogBox you destroyed constituted the only way for that variable to actually change. You're pretty much stuck. Instead of bypassing the DialogBox's inner workings, you should've programatically invoked the correct button to submit the dialog choice.

    Update: Restructured post to put the simple, practical answer at the top where it should be. :)

    bbfu
    Black flowers blossom
    Fearless on my breath

Re: Problems with perl/Tk dialogbox destroy
by bobdeath (Scribe) on Jun 11, 2003 at 19:51 UTC
    The Dialog and DialogBox widgets behave strangly when it comes to destroying them. I would recommend using a Toplevel instead. I think that would solve most of your problems with only minor changes to the code