Kaughper has asked for the wisdom of the Perl Monks concerning the following question:

Greetings Exalted Monks!
Below is a code that shows two Canvases ("Canvasi"?), the first with a XPM image of the letter "A", the second empty.
When the button at the bottom is clicked, the second Canvas is supposed to have an XPM image of the letter "B" placed into it.
That much happens, but the weird thing is that the image in the FIRST Canvas is ALSO changed to the letter "B".

I have no idea why. There is no code in the button command that even mentions the items for the first Canvas.

Any guidance is greatly appreciated. Thank you for reading.

use strict; use warnings; use Tk; # Create Main Window my $mw = MainWindow -> new; $mw->bind('<Escape>' => sub { $mw->destroy(); }); # Letter A in XPM format my $LtrA = '/* XPM */ static char * a[] = { "8 8 2 1", " c none", "x c #000000", " xx ", " xxxx ", " xx xx ", "xx xx", "xxxxxxxx", "xxxxxxxx", "xx xx", "xx xx"};'; # Letter B in XPM format my $LtrB = '/* XPM */ static char * b[] = { "8 8 2 1", " c none", "x c #000000", "xxxxxxx ", "xxxxxxxx", "xx xx", "xxxxxxx ", "xx xx", "xx xx", "xxxxxxxx", "xxxxxxx "};'; # Image A holder in Main Window my $LblA = $mw->Label(-text => 'Image A:')->pack(); my $cvsA = $mw->Canvas(-background=>'yellow', -height => 40, -width => + 40)->pack(); # Image B holder in Main Window my $LblB = $mw->Label(-text => 'Image B:')->pack(); my $cvsB = $mw->Canvas(-background=>'green', -height => 40, -width => +40)->pack(); # Set Image A my $imgA = $mw->Photo('image', -data => $LtrA); $cvsA->create('image', 10, 10, -image => $imgA); # Button to make Image B my $btn = $mw->Button(-text => 'Add Letter B', -command => \&Add_B)->p +ack(-pady => 5); MainLoop; sub Add_B { my $imgB = $mw->Photo('image', -data => $LtrB); $cvsB->create('image', 30, 30, -image => $imgB); }

Replies are listed 'Best First'.
Re: Tk::Photo XPM images being copied
by kcott (Archbishop) on Dec 28, 2018 at 07:28 UTC

    G'day Kaughper,

    Welcome to the Monastery.

    "There is no code in the button command that even mentions the items for the first Canvas."

    Well, actually there is. You've given $imgA the name 'image'. In &Add_B, you've used the same Photo named 'image'.

    In addition, that's potentially confused with the name of the Canvas item type:

    $cvsA->create('image', ...); $cvsB->create('image', ...);

    A quick fix would be to name them 'imageA' and 'imageB'. I've tested that and it works.

    You have a more insidious problem waiting to happen: &Add_B relies on a variable not passed to that subroutine. This is one of the most common problems with Tk programs; fortunately, it is easily avoided. Consider changing the code after defining your XPMs to something like this (which I've successfully tested):

    my %image_data_for = ( A => { name => 'ImageA', data => $LtrA, }, B => { name => 'ImageB', data => $LtrB, }, ); # Image A holder in Main Window $mw->Label(-text => 'Image A:')->pack(); my $cvsA = $mw->Canvas(-background=>'yellow', -height => 40, -width => + 40)->pack(); # Image B holder in Main Window $mw->Label(-text => 'Image B:')->pack(); my $cvsB = $mw->Canvas(-background=>'green', -height => 40, -width => +40)->pack(); # Set Image A create_canvas_image($cvsA, $image_data_for{A}); # Button to make Image B $mw->Button( -text => 'Add Letter B', -command => [\&create_canvas_image, $cvsB, $image_data_for{B}], )->pack(-pady => 5); MainLoop; sub create_canvas_image { my ($canvas, $image_data) = @_; my $img = $mw->Photo($image_data->{name}, -data => $image_data->{d +ata}); $canvas->create('image', 30, 30, -image => $img); }

    Now you only have one routine (&create_canvas_image) to create all images: your example, which I'm guessing is just a proof-of-concept, only has two; but this will work for whatever number of images you want in your real-world application.

    Please note that I've only shown an example for demonstrating a technique. For production-grade code, I'd be limiting the scope of most of the variables: giving them all file-scope is not a good idea as any subsequent code after their definition can change their values.

    — Ken

      Ah. I didn't catch the naming of the Photo widgets. Thank you.
      Yes, this was just a proof of problem code, so I removed as much as I could, and just put in the button part so that I could see a "before and after" of trying to set Image-B.
      Thank you again for the naming tip. I didn't realize the given name had such significance.
Re: Tk::Photo XPM images being copied
by choroba (Cardinal) on Dec 28, 2018 at 07:31 UTC
    I'm on a cellphone so can't test myself, but I'd guess it's because you used the same name for both the images. Try using different ones or let Tk create the names for you.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]