Continuing in the series.
This code takes up where the last tutorial left off -- displaying an image -- and the ability to add directories and images to a treeview for browsing. This does build on top of the other tutorials I've written, and so has less detailed commenting, as I assume you've read them. :-)
#!/usr/bin/perl use Wx ; package MyApp; use strict; use vars qw(@ISA); use Wx qw(:everything); use Wx::Event qw(EVT_MENU); @ISA=qw(Wx::App); sub OnInit { my $this = @_; my $frame = MyFrame->new( "Mini-image demo", [-1,-1], [-1,-1]); #my $this->{FRAME}=$frame; unless ($frame) {print "unable to create frame -- exiting."; ret +urn undef} $frame->Show( 1 ); 1; } package MyFrame; use vars qw(@ISA); use strict; # # All we load here are constants used # to keep the image stretched to the dimensions of the window. # use Wx qw(wxWidth wxHeight wxLeft wxTop wxDefaultPosition wxDefaul +tSize wxID_CANCEL wxCentreX wxCentreY); use Wx::Event qw(:everything); # # Wx::Image loads the Image control and all of the Image handler +s. # use Wx::Image; use IO::File; use Wx::Event ; @ISA=qw(Wx::Frame); sub new { my $class = shift; my $this = $class->SUPER::new( undef, -1, $_[0], $_[1], $_[2] +); # # replace the filename with something appropriate. # my $file = IO::File->new( "c:/docume~1/porterje/wx-ex.jpg", "r +" ); unless ($file) {print "Can't load file.";return undef}; binmode $file; my $handler = Wx::JPEGHandler->new(); my $image = Wx::Image->new(); my $bmp; # used to hold the bitmap. $handler->LoadFile( $image, $file ); $bmp = $image->ConvertToBitmap(); if( $bmp->Ok() ) { # create a static bitmap called ImageViewer that displays + the # selected image. $this->{ImageViewer}= Wx::StaticBitmap->new($this, -1, $bm +p); } $this->{ScaleImage}=0; $this->{TreeCtrl}= MyTreeCtrl->new($this, -1); $this->SetAutoLayout( 1 ); # allow wxperl to manage control s +izing & placement # Layout constraints provide the guides # for wxperl's autolayout. my $b1 = Wx::LayoutConstraints->new(); my $b2 = Wx::LayoutConstraints->new(); # These constrainst define the placement and # dimensions of the controls they're bound to, # and can be either absolute, or relative to # other controls $b1->left->Absolute(0); $b1->top->Absolute(0); $b1->width->PercentOf( $this, wxWidth,50); $b1->height->PercentOf( $this, wxHeight, 100); $this->{TreeCtrl}->SetConstraints($b1); $b2->left->RightOf($this->{TreeCtrl}); $b2->top->Absolute(0); $b2->width->PercentOf( $this, wxWidth,50); $b2->height->PercentOf( $this, wxHeight, 100); $this->{ImageViewer}->SetConstraints($b2); # # Set up the menu bar. # my $file_menu = Wx::Menu->new(); my ($OPEN_NEW_DIR, $REMOVE_DIR, $SCALE_IMAGE, $APP_QUIT)=(1..1 +00); $file_menu-> Append( $OPEN_NEW_DIR, "&Open A Directory\tCtrl-O +"); $file_menu->AppendSeparator(); $file_menu->Append($SCALE_IMAGE,"&Scale Images To Window\tCtrl +-S","",1); $file_menu->AppendSeparator(); $file_menu->Append ($APP_QUIT, "E&xit\tCtrl-x","Exit Applicati +on"); # # Note that even though there are 6 options, only # 4 of them are active as they're the only ones # bound to event handlers. # EVT_MENU($this, $OPEN_NEW_DIR, \&OnDirDialog); EVT_MENU($this, $SCALE_IMAGE, \&Set_Scale); EVT_MENU($this, $APP_QUIT, sub {$_[0]->Close( 1 )}); my $menubar= Wx::MenuBar->new(); $menubar->Append ($file_menu, "&File"); $this->SetMenuBar($menubar); $this; # return the frame object to the calling application. } # Set_Scale changes a scalar flag which will determine # if a displayed image is resized to fit the full # dimensions of the image control. sub Set_Scale { my $this = shift; # yes, I could have used NOT here. if ($this->{ScaleImage}){$this->{ScaleImage}=0} else {$this->{ +ScaleImage}=1}; } # # OnDirDialog scans a user specified directory for images. # sub OnDirDialog { my( $this, $event ) = @_; my $dialog = Wx::DirDialog->new( $this ); unless ( $dialog->ShowModal == wxID_CANCEL ) { $this->{TreeCtrl}->ScanDir($dialog->GetPath); } $dialog->Destroy; } package MyTreeCtrl; use vars qw (@ISA); use strict; use Wx qw(:everything); use Wx::Event qw(EVT_TREE_SEL_CHANGED EVT_TREE_ITEM_ACTIVATED) ; use Win32; use HTML::SimpleLinkExtor; use LWP::MediaTypes qw(guess_media_type); use LWP::UserAgent; @ISA=qw(Wx::TreeCtrl); sub new { my $class = shift; my $this = $class->SUPER::new( @_ ); EVT_TREE_SEL_CHANGED ($this,$this, \&OnChange); my $root=$this->AddRoot("Image listings"); #add one default it +em. $this; } # # Scandir adds a child node to the treeview that # lists the directory, and then sets each image file to # be a child of that newly created node. # sub ScanDir { my $this=shift; my $dir=shift; $dir =~tr/\\/\//; if ($dir !~/[\/]$/) {$dir.="/"} $dir=Win32::GetShortPathName($dir); my (@files) =glob "$dir*.jpg"; push @files, glob "$dir*.gif"; my $item = $this->AppendItem ($this->GetRootItem, "$dir (".scalar +@files.") files"); foreach (@files) {$this->AppendItem ($item,"$_")} } # # event handler for selecting different images. # sub OnChange { my ($this, $event) =@_; my $item = $event->GetItem(); if ($item== $this->GetRootItem()) {return} # return if user clicke +d on the root node. my $txt = $this->GetItemText($item); my $ext; my $handler; $txt=reverse $txt; if ($txt=~/^(.*?)\./){ $ext=lc(reverse($1)); } $txt=reverse ($txt); # this is cheesy, but the autosensing handler doesn't work, # or I can't get it to work appropriately. if ($ext eq "jpg"){$handler = Wx::JPEGHandler->new()}; if ($ext eq "gif"){$handler = Wx::GIFHandler->new()}; # create file my $file; $file = IO::File->new( $txt, "r" ) or return undef; binmode $file; return unless $handler; # exit if problems occur during handle cre +ation #and stuff into the image handler. my $image = Wx::Image->new(); my $bmp; # used to hold the bitmap. $handler->LoadFile( $image, $file ) or print "can't load file!"; $bmp = $image->ConvertToBitmap(); if( $bmp->Ok() ) { # create a static bitmap called ImageViewer that displays the # selected image. my $parent=$this->GetParent(); my $img =$parent->{ImageViewer}; my $size= $img->GetSize(); $img->SetBitmap($bmp); if ($parent->{ScaleImage}){$img->SetSize($size)}; $parent->Clear(); $img->Refresh; } } package main; my $app = MyApp->new(); # create $app->MainLoop(); # go