in reply to Re^4: What's wrong with this Wx::Bitmap construction?
in thread What's wrong with this Wx::Bitmap construction?

After playing with it, I see what is happening. IO::String, like perls in-memory file handles, only exist in perl land, whereas wxWidgets expect an actual system file handle, so that approach won't work.

Luckily you can use newFromBits or newFromXPM (newData seems broken).

#!/usr/bin/perl ###################################################################### +####### ## Name: samples/listctrl/listctrl.pl ## Purpose: ListCtrl wxPerl sample ## Author: Mattia Barbon ## Modified by: ## Created: 06/02/2001 ## RCS-ID: $Id: listctrl.pl,v 1.7 2005/08/07 21:17:01 mbarbon Exp + $ ## Copyright: (c) 2001, 2003 Mattia Barbon ## Licence: This program is free software; you can redistribute it + and/or ## modify it under the same terms as Perl itself ###################################################################### +####### use Wx; package MyFrame; use strict; use vars qw(@ISA); use MIME::Base64 (); use IO::Scalar (); @ISA = qw(Wx::Frame); use Wx qw(:everything); my( $id_about, $id_quit, $id_listctrl, $id_iconview , $id_listview, $id_reportview , $id_icontextview , $id_smalliconview, $id_smallicontextview , $id_togglefirst , $id_deselectall, $id_selectall , $id_showcolinfo , $id_sort , $id_deleteall, $id_togglemultisel , $id_setfgcol , $id_setbgcol ) = ( 1 .. 100 ); Wx::InitAllImageHandlers(); sub ICON($) { if( Wx::wxMSW() ) { Wx::Icon->new( "bitmaps/$_[0].ico", wxBITMAP_TYPE_ICO ); } else { Wx::Icon->new( "bitmaps/$_[0].xpm", wxBITMAP_TYPE_XPM ); } } sub new { my( $class ) = shift; my( $this ) = $class->SUPER::new( undef, -1, $_[0], [ @_[1, 2] ], [ @_[3, 4] ] ); $this->SetIcon( Wx::GetWxPerlIcon() ); $this->{IMAGELISTNORMAL} = Wx::ImageList->new( 32, 32, 1 ); $this->{IMAGELISTSMALL} = Wx::ImageList->new( 16, 16, 1 ); ### test area! my $raw_data = "R0lGODlhEAAQAJEAAAAAAP///+vc3AAAACwAAAAAEAAQAAACDp +SPqcvtD6OctNqLsz4FADs="; # light red single color GIF my $icon_data = MIME::Base64::decode_base64( $raw_data ); #~ $ perl -MWx -le"print for sort grep /new|load/i , keys %Wx::Image:: +" #~ LoadFile #~ LoadFileMIME #~ LoadFileType #~ LoadStreamMIME #~ LoadStreamType #~ new #~ newBitmap #~ newData #~ newDataAlpha #~ newIcon #~ newNameMIME #~ newNameType #~ newNull #~ newStreamMIME #~ newStreamType #~ newWH #~ $ perl -MWx -le"print for sort grep /new|load/i , keys %Wx::Bitmap: +:" #~ LoadFile #~ new #~ newEmpty #~ newFile #~ newFromBits #~ newFromXPM #~ newIcon #~ newImage my $image = Wx::Image->new(); my $file ; #~ $image->LoadFile( $file, wxBITMAP_TYPE_ANY ); if(0){ #~ doesn't work because it isn't a real filehandle #~ 12:25:10 AM: Can't load image from file 'Wx::Image=SCALAR(0xeb7064) +': file does not exist. #~ 12:25:10 AM: Couldn't add an image to the image list. $file = IO::Scalar->new( \$icon_data ) or die $!; $image->LoadStreamType( $file, wxBITMAP_TYPE_ANY ); } if(0){ #~ same result, but curious message about gif format #~ 12:24:19 AM: GIF: error in GIF image format. #~ 12:24:19 AM: Can't load image from file 'Wx::Image=SCALAR(0xeb7064) +': file does not exist. #~ 12:24:19 AM: Couldn't add an image to the image list. $file = IO::Scalar->new( \$raw_data ) or die $!; $image->LoadStreamMIME( $file, 'image/gif' ); } if(0){ #~ same result #~ 12:30:52 AM: Can't load image from file 'Wx::Image=SCALAR(0xeb7064) +': file does not exist. #~ 12:30:52 AM: Couldn't add an image to the image list. #~ open $file , '<:raw', \$icon_data or die "$!\n$^E "; ## NO +SUCH FILE OR DIRECTORY, WEIRD, in memory files and layers open $file , '<', \$icon_data or die "$!\n$^E "; $image->LoadStreamMIME( $file, 'image/gif' ); } if(0){ ## doesn't work #~ errror: "not enough data in image constructor" #~ probable bug in newData $image = Wx::Image->newData( 16, 16 , $icon_data ) ; } if(1){ ## WORKS $image = Wx::Bitmap->newFromBits( $icon_data , 16, 16 ) ; } if(0){ ## WORKS ## ImageMagick-6.5.6-Q16/convert.exe working.gif working.xpm my $xpm = <<'__XPM__'; /* XPM */ static char *working[] = { /* columns rows colors chars-per-pixel */ "16 16 4 1", " c #000000", ". c #FFFFFF", "X c #EBDCDC", "o c #000000", /* pixels */ "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX", "XXXXXXXXXXXXXXXX" }; __XPM__ $xpm = [ $xpm =~ /"([^"]+)"/g ]; $image = Wx::Bitmap->newFromXPM( $xpm ) ; } close($file) if $file and fileno $file; open (my $fh, '>working.gif'); binmode $fh; print $fh $icon_data; close($fh); ### /test area! $this->{IMAGELISTSMALL}->Add( $image ); #~ $this->{IMAGELISTSMALL}->Add( Wx::Bitmap->new($image, -1) ); $this->{LISTCTRL} = MyListCtrl->new( $this, $id_listctrl, wxDefaultP +osition, wxDefaultSize, wxLC_LIST| wxSUNKEN_BORDER|wxLC_EDIT_LABEL +S| wxLC_SINGLE_SEL ); $this->{LOGWINDOW}; $this->{LOGOLD} = Wx::Log::SetActiveTarget ( Wx::LogTextCtrl->new( $this->{LOGWINDOW} ) ); my( $topsizer ) = Wx::BoxSizer->new( wxVERTICAL ); $topsizer->Add( $this->{LISTCTRL}, 2, wxGROW ); $this->SetSizer( $topsizer ); $this->SetAutoLayout( 1 ); my( $idx ); foreach my $i ( 0 .. 100 ) { $idx = $this->{LISTCTRL}->InsertStringImageItem( $i, "Item $i", $i + ); $this->{LISTCTRL}->SetItemData( $idx, $i * $i ); } $this->CreateStatusBar( 3 ); use Wx::Event qw(EVT_MENU EVT_UPDATE_UI); EVT_MENU( $this, $id_quit, \&OnQuit ); EVT_MENU( $this, $id_about, \&OnAbout ); EVT_MENU( $this, $id_listview, \&OnListView ); EVT_MENU( $this, $id_reportview, \&OnReportView ); EVT_MENU( $this, $id_iconview, \&OnIconView ); EVT_MENU( $this, $id_icontextview, \&OnIconTextView ); EVT_MENU( $this, $id_smalliconview, \&OnSmallIconView ); EVT_MENU( $this, $id_smallicontextview, \&OnSmallIconTextView ); EVT_MENU( $this, $id_togglefirst, \&OnToggleFirstSel ); EVT_MENU( $this, $id_deselectall, \&OnDeselectAll ); EVT_MENU( $this, $id_selectall, \&OnSelectAll ); EVT_MENU( $this, $id_deleteall, \&OnDeleteAll ); EVT_MENU( $this, $id_sort, \&OnSort ); EVT_MENU( $this, $id_setfgcol, \&OnSetFgColour ); EVT_MENU( $this, $id_setbgcol, \&OnSetBgColour ); EVT_MENU( $this, $id_togglemultisel, \&OnToggleMultiSel ); EVT_MENU( $this, $id_showcolinfo, \&OnShowColInfo ); EVT_UPDATE_UI( $this, $id_showcolinfo, \&OnUpdateShowColInfo ); $this; } sub DESTROY { my $this = shift; Wx::Log::SetActiveTarget( $this->{LOGOLD} )->Destroy; } sub OnQuit { $_[0]->Close( 1 ); } sub OnAbout { my( $dialog ) = Wx::MessageDialog->new( $_[0], "ListCtrl sample", "About ListCtrl Sample", wxO +K ); $dialog->ShowModal; $dialog->Destroy; } sub OnToggleFirstSel { $_[0]->{LISTCTRL}->SetItemState( 0, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); } sub OnDeselectAll { my( $this, $event ) = @_; foreach ( 0 .. $this->{LISTCTRL}->GetItemCount - 1 ) { $this->{LISTCTRL}->SetItemState( $_, 0, wxLIST_STATE_SELECTED ); } } sub OnSelectAll { my( $this, $event ) = @_; foreach ( 0 .. $this->{LISTCTRL}->GetItemCount - 1 ) { $this->{LISTCTRL}->SetItemState( $_, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED ); } } sub OnListView { my( $this, $event ) = @_; $this->{LOGWINDOW}->Clear; $this->{LISTCTRL}->ClearAll; $this->{LISTCTRL}->SetSingleStyle( wxLC_LIST ); $this->{LISTCTRL}->SetImageList( undef, wxIMAGE_LIST_NORMAL ); $this->{LISTCTRL}->SetImageList( undef, wxIMAGE_LIST_SMALL ); foreach ( 1 .. 29 ) { $this->{LISTCTRL}->InsertStringItem( $_, "Item $_" ); } } sub OnReportView { my( $this, $event ) = @_; $this->{LOGWINDOW}->Clear; $this->{LISTCTRL}->ClearAll; $this->{LISTCTRL}->SetSingleStyle( wxLC_REPORT ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTNORMAL}, wxIMAGE_L +IST_NORMAL ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTSMALL}, wxIMAGE_LI +ST_SMALL ); $this->{LISTCTRL}->InsertColumn( 0, "Column 1" ); $this->{LISTCTRL}->InsertColumn( 1, "Column 2" ); $this->{LISTCTRL}->InsertColumn( 2, "One more column" ); # control hidden to speed up insertion $this->{LISTCTRL}->Show( 0 ); my( $watch ) = Wx::StopWatch->new; $watch->Start; my( $id ); my( $elements ) = 300; foreach ( 1 .. $elements - 1 ) { $id = $this->{LISTCTRL}->InsertStringImageItem( $_, "This is item +$_", 0 ); $this->{LISTCTRL}->SetItemData( $id, $_ ); $this->{LISTCTRL}->SetItem( $id, 1, "Col 1, Item $_" ); $this->{LISTCTRL}->SetItem( $id, 2, "Item $_ in column 2" ); } Wx::LogMessage( "Inserted %d elements in %d milliseconds", $elements, $watch->Time ); $this->{LISTCTRL}->Show( 1 ); my( $item ) = Wx::ListItem->new; $item->SetId( 0 ); $item->SetTextColour( wxRED ); $this->{LISTCTRL}->SetItem( $item ); $item->SetId( 2 ); $item->SetTextColour( wxGREEN ); $this->{LISTCTRL}->SetItem( $item ); $item->SetId( 4 ); $item->SetTextColour( wxLIGHT_GREY ); $item->SetFont( wxITALIC_FONT ); $item->SetBackgroundColour( wxRED ); $this->{LISTCTRL}->SetItem( $item ); $this->{LISTCTRL}->SetTextColour( wxBLUE ); $this->{LISTCTRL}->SetBackgroundColour( wxLIGHT_GREY ); $this->{LISTCTRL}->SetColumnWidth( 0, wxLIST_AUTOSIZE ); $this->{LISTCTRL}->SetColumnWidth( 1, wxLIST_AUTOSIZE ); $this->{LISTCTRL}->SetColumnWidth( 2, wxLIST_AUTOSIZE ); } sub OnIconView { my( $this, $event ) = @_; $this->{LOGWINDOW}->Clear; $this->{LISTCTRL}->ClearAll; $this->{LISTCTRL}->SetSingleStyle( wxLC_ICON ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTNORMAL}, wxIMAGE_L +IST_NORMAL ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTSMALL}, wxIMAGE_LI +ST_SMALL ); foreach ( 1 .. 8 ) { $this->{LISTCTRL}->InsertImageItem( $_, $_ ); } } sub OnIconTextView { my( $this, $event ) = @_; $this->{LOGWINDOW}->Clear(); $this->{LISTCTRL}->ClearAll(); $this->{LISTCTRL}->SetSingleStyle( wxLC_ICON ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTNORMAL}, wxIMAGE_L +IST_NORMAL ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTSMALL}, wxIMAGE_LI +ST_SMALL ); foreach ( 1 .. 8 ) { $this->{LISTCTRL}->InsertStringImageItem( $_, "Label $_", $_ ); } } sub OnSmallIconView { my( $this, $event ) = @_; $this->{LOGWINDOW}->Clear; $this->{LISTCTRL}->ClearAll; $this->{LISTCTRL}->SetSingleStyle( wxLC_SMALL_ICON ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTNORMAL}, wxIMAGE_L +IST_NORMAL ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTSMALL}, wxIMAGE_LI +ST_SMALL ); foreach ( 0 .. 8 ) { $this->{LISTCTRL}->InsertImageItem( $_, 0 ); } } sub OnSmallIconTextView { my( $this, $event ) = @_; $this->{LOGWINDOW}->Clear; $this->{LISTCTRL}->ClearAll; $this->{LISTCTRL}->SetSingleStyle( wxLC_SMALL_ICON ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTNORMAL}, wxIMAGE_L +IST_NORMAL ); $this->{LISTCTRL}->SetImageList( $this->{IMAGELISTSMALL}, wxIMAGE_LI +ST_SMALL ); foreach ( 0 .. 8 ) { $this->{LISTCTRL}->InsertImageStringItem( $_, "Label $_", 0 ); } } sub OnShowColInfo { my( $this, $event ) = @_; my( $n ) = $this->{LISTCTRL}->GetColumnCount; Wx::LogMessage( "$n columns:" ); foreach ( 0 .. $n - 1 ) { Wx::LogMessage( "\t column %d has width %d", $_, $this->{LISTCTRL}->GetColumnWidth( $_ ) ); } } sub OnUpdateShowColInfo { my( $this, $event ) = @_; $event->Enable( $this->{LISTCTRL}->GetWindowStyleFlag & wxLC_REPORT +); } sub Cmp { $_[0] < $_[1] }; sub OnSort { my( $this ) = @_; $this->{LISTCTRL}->SortItems( \&Cmp ); } sub OnToggleMultiSel { my( $this, $event ) = @_; $this->{LOGWINDOW}->WriteText( "Current selection mode: " ); my( $flag ) = $this->{LISTCTRL}->GetWindowStyleFlag; if( $flag & wxLC_SINGLE_SEL ) { $this->{LISTCTRL}->SetWindowStyleFlag( $flag & ~wxLC_SINGLE_SEL ); $this->{LOGWINDOW}->WriteText( "multiple" ); } else { $this->{LISTCTRL}->SetWindowStyleFlag( $flag | wxLC_SINGLE_SEL ); $this->{LOGWINDOW}->WriteText( "single" ); } $this->{LOGWINDOW}->WriteText( "\nRecreate the control now\n" ); } sub OnDeleteAll { my( $this, $event ) = @_; my( $watch ) = Wx::StopWatch->new; $this->{LISTCTRL}->DeleteAllItems; Wx::LogMessage( "Deleted all items in %d milliseconds", $watch->Time() ); } sub OnSetFgColour { my( $this, $event ) = @_; $this->{LISTCTRL}->SetForegroundColour( Wx::GetColourFromUser( $this + ) ); $this->{LISTCTRL}->Refresh(); } sub OnSetBgColour { my( $this, $event ) = @_; $this->{LISTCTRL}->SetBackgroundColour( Wx::GetColourFromUser( $this + ) ); $this->{LISTCTRL}->Refresh(); } package MyListCtrl; use strict; use vars qw(@ISA); @ISA = qw(Wx::ListCtrl); use Wx::Event qw{EVT_LIST_BEGIN_DRAG EVT_LIST_BEGIN_RDRAG EVT_LIST_BEGIN_LABEL_EDIT EVT_LIST_END_LABEL_EDIT EVT_LIST_DELETE_IT +EM EVT_LIST_DELETE_ALL_ITEMS EVT_LIST_ITEM_SELECTED EVT_LIST_ITEM_DESELECTED EVT_LIST_KEY_DOWN EVT_LIST_ITEM_ACTIVATED EVT_LIST_COL_CLICK EVT_CHAR}; sub new { my( $class ) = shift; my( $this ) = $class->SUPER::new( @_ ); EVT_LIST_BEGIN_DRAG( $this, $this, \&OnBeginDrag); EVT_LIST_BEGIN_RDRAG( $this, $this, \&OnBeginRDrag ); EVT_LIST_BEGIN_LABEL_EDIT( $this, $this, \&OnBeginLabelEdit ); EVT_LIST_END_LABEL_EDIT( $this, $this, \&OnEndLabelEdit ); EVT_LIST_DELETE_ITEM( $this, $this, \&OnDeleteItem ); EVT_LIST_DELETE_ALL_ITEMS( $this, $this, \&OnDeleteAllItems ); EVT_LIST_ITEM_SELECTED( $this, $this, \&OnSelected ); EVT_LIST_ITEM_DESELECTED( $this, $this, \&OnDeselected ); EVT_LIST_KEY_DOWN( $this, $this, \&OnListKeyDown ); EVT_LIST_ITEM_ACTIVATED( $this, $this, \&OnActivated ); EVT_LIST_COL_CLICK( $this, $this, \&OnColClick ); EVT_CHAR( $this, \&OnChar ); $this } sub OnColClick { my( $this, $event ) = @_; Wx::LogMessage( "OnClumnClick at %d.", $event->GetColumn ); } sub OnBeginDrag { my( $this, $event ) = @_; Wx::LogMessage( "OnBeginDrag ad ( %d, %d ).", $event->GetPoint->x, $event->GetPoint->y ); } sub OnBeginRDrag { my( $this, $event ) = @_; Wx::LogMessage( "OnBeginRDrag ad ( %d, %d ).", $event->GetPoint->x, $event->GetPoint->y ); } sub OnBeginLabelEdit { my( $this, $event ) = @_; Wx::LogMessage( "OnBeginLabelEdit: %s", $event->GetItem->GetText ); } sub OnEndLabelEdit { my( $this, $event ) = @_; Wx::LogMessage( "OnBeginLabelEdit: %s", $event->GetItem->GetText ); } sub OnDeleteItem { my( $this, $event ) = @_; $this->LogEvent( $event, "OnDeleteItem" ); } sub OnDeleteAllItems { my( $this, $event ) = @_; $this->LogEvent( $event, "OnDeleteAllItems" ); } use Wx qw(:listctrl); sub OnSelected { my( $this, $event ) = @_; $this->LogEvent( $event, "OnSelected" ); if( $this->GetWindowStyleFlag && wxLC_REPORT ) { my( $info ); if( $info = ( $this->GetItem( $event->GetIndex, 1 ) ) ) { Wx::LogMessage( "Value of the second field of the selected item: + %s", $info->GetText ); } else { #die; } } } sub OnDeselected { $_[0]->LogEvent( $_[1], "OnDeselected" ); } sub OnActivated { $_[0]->LogEvent( $_[1], "OnActivated" ); } sub OnListKeyDown { my( $this, $event ) = @_; $this->LogEvent( $event, "OnListKeyDown" ); $event->Skip; } sub OnChar { my( $this, $event ) = @_; Wx::LogMessage( "OnChar" ); $event->Skip; } sub LogEvent { my( $this, $event, $name ) = @_; Wx::LogMessage( "Item %d: %s ( item text = %s, data = %d )", $event->GetIndex, $name, $event->GetText, $event->GetData ); } package MyApp; use strict; use vars qw(@ISA); @ISA = qw(Wx::App); sub OnInit { my( $this ) = @_; my( $frame ) = MyFrame->new( 'wxPerl ListCtrl Test', 50, 50, 450, 34 +0 ); $frame->Show( 1 ); $this->SetTopWindow( $frame ); 1; } package main; my( $app ) = MyApp->new; $app->MainLoop; # Local variables: # # mode: cperl # # End: #
You could get some ideas from App::Wx::PodEditor (and this bug report)