alterego has asked for the wisdom of the Perl Monks concerning the following question:
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;
|
|---|