So, I seem to have myself coded into a corner. I'm probably missing something obvious, and need someone to focus my eyes on the answer.

I'm using WxPerl GUI windows with a worker thread. The main frame can create an unlimited number of subframes, which are stored in a hash, which the worker thread and main frame have access to. In my simplified code, the thread writes data to each of the sub frames.

The problem arises when one of the subframes is closed. I'm unsure how to access the key of the hash in order to remove the subframe key/value from the hash before the worker thread tries to write data to controls that have been destroyed.

The two spots in my code where I was trying to remove the key/value from the hash are marked with "WTF". I was trying to pass the key back with the EVT_CLOSE, but then things just got strange.

Any suggestions? I'm sure this code is faulty on more levels than one can count, so I'll take any other suggestions for tightening it up. Thanks in advance.

use threads; use threads::shared; use Thread::Queue; use strict; use Wx; package TheApp; use base 'Wx::App'; sub OnInit { my $self = shift; my $frame = MFrame->new(); $frame->Show(1); $self->SetTopWindow($frame); return 1; } package SFrame; use base 'Wx::Frame'; use Wx qw(wxTE_MULTILINE wxTE_READONLY wxVERTICAL wxID_DEFAULT); use Wx::Event qw(EVT_CLOSE); sub new { my $class = shift; my $self = $class->SUPER::new(undef, -1, "A Server"); $self->{text} = Wx::TextCtrl->new($self, -1, "", [-1,-1], [300, 30 +0], wxTE_MULTILINE|wxTE_READONLY); my $sizer = Wx::BoxSizer->new(wxVERTICAL); $sizer->Add($self->{text}); $self->SetSizer($sizer); $self->Fit; return $self; } package MFrame; use base 'Wx::Frame'; use Wx qw(wxTE_MULTILINE wxTE_READONLY wxVERTICAL wxID_DEFAULT); use Wx::Event qw(EVT_COMMAND EVT_CLOSE EVT_BUTTON EVT_SIZE); my $done_event : shared = Wx::NewEventType; sub new { my $class = shift; my $self = $class->SUPER::new(undef, -1, "EvHelper"); $self->{text} = Wx::TextCtrl->new($self, -1, "", [-1,-1], [500,500 +], wxTE_MULTILINE|wxTE_READONLY ); $self->{button} = Wx::Button->new($self, -1, "&Start"); $self->{button2} = Wx::Button->new($self, -1, "&Zip it"); my $sizer = Wx::BoxSizer->new(wxVERTICAL); $sizer->Add($self->{text}); $sizer->Add($self->{button}); $sizer->Add($self->{button2}); $self->SetSizer($sizer); my ($sec,$min,$hour,$mday,$mon,$year,$wday, $yday,$isdst)=localtime(time); my $dt=sprintf "%4d-%02d-%02d %02d:%02d:%02d\n", $year+1900,$mon+1,$mday,$hour,$min,$sec; $self->{text}->AppendText("Program started at " . $dt . "\n"); EVT_COMMAND($self, -1, $done_event, \&done); EVT_CLOSE($self, \&on_close); EVT_BUTTON($self,$self->{button}, \&on_button ); EVT_BUTTON($self,$self->{button2}, \&on_button2 ); my $sendqueue = Thread::Queue->new(); my $worker = threads->create(\&worker, $self, $sendqueue ); $self->{queue} = $sendqueue; $self->{worker} = $worker; $self->Fit; return $self; } sub on_button { my ($self, $event) = @_; if ($self->{button}->Wx::Button::GetLabel() eq "&Start") { $self->{button}->Wx::Button::SetLabel("&Stop"); $self->{queue}->enqueue('GO'); } else { $self->{button}->Wx::Button::SetLabel("&Start"); $self->{queue}->enqueue('PAUSE'); } } sub on_button2 { my ($self, $event) = @_; if ($self->{button2}->Wx::Button::GetLabel() eq "&Zip it") { my $wcount=scalar(keys %{$self->{SFrame}})+1; my $SFrameID="SVR" . $wcount; $self->{SFrame}{$SFrameID} = SFrame->new(); EVT_CLOSE($self->{SFrame}{$SFrameID}, \&on_sframe_close); $self->{SFrame}{$SFrameID}->SetTitle("Server " . $SFrameID); $self->{SFrame}{$SFrameID}->Show(1); } } sub on_close { my ($self, $event) = @_; $self->{queue}->enqueue('STOP'); $self->{worker}->join; my $key; foreach $key (keys %{$self->{SFrame}}) { $self->{SFrame}{$key}->Destroy(); } $event->Skip(1); } sub on_sframe_close { my ($self, $event) = @_; print "WTF!\n"; } sub done { my ($self, $event) = @_; my $text = $event->GetData; my ($trash, $blipcount) = split /\ /,$text; $self->{text}->AppendText("$text\n"); my $wcount=scalar(keys %{$self->{SFrame}} ); if ($wcount>0) { my $wdest=($blipcount % $wcount); my @SFrameIDs=keys %{$self->{SFrame}}; my $SFrameID=$SFrameIDs[$wdest]; if (defined($self->{SFrame}{$SFrameID}->{text})) { $self->{SFrame}{$SFrameID}->{text}->AppendText("$text\n"); } else { print "WTF! Deleting\n"; delete $self->{SFrame}{$SFrameID}; } } } sub worker { my($handler, $queue) = @_; my $status='PAUSE'; my $blipcount=0; while (1) { my $message; if ($queue->pending > 0) { $message=$queue->dequeue; } return 1 if $message eq 'STOP'; if ($message eq 'PAUSE') { $status='PAUSE'; } if ($message eq 'GO') { $status='GO'; } if ($status eq 'GO') { $blipcount++; my $title : shared = "blip " . $blipcount; print "$title\n"; my $thread_event = Wx::PlThreadEvent->new(-1, $done_event,$t +itle); Wx::PostEvent($handler, $thread_event); } sleep 1; } } package main; TheApp->new->MainLoop;

In reply to Trouble cleaning up child frames stored in a hash. by alterego

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.