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