Book HomeMastering Perl/TkSearch this book

17.5. The Bitmap Image Type

The Bitmap command can read XBM data from a file or directly from data embedded in your Perl/Tk program. Suppose we have a bitmap of a circle. The following code creates the bitmap image from the XBM file and gives it a black foreground (the circle) and a white background. The image is placed inside a Label with a gray background, and then it's packed:

my $b = $mw->Bitmap(-file       => 'circle.xbm',
                    -foreground => 'black',
                    -background => 'white',
);

my $l = $mw->Label(-image => $b, -background => 'gray')->pack;

Since the Label shrink-wraps around the image, all we see is the picture shown in Figure 17-5. Notice also that we've omitted any mask file.

Figure 17-5

Figure 17-5. A bitmap of a circle without a mask

Suppose we copy the original bitmap and invert it (that is, toggle all the bits so ones become zeros and zeros become ones) and save the result as a mask file. This statement reconfigures the Bitmap image and adds a -maskfile option, producing a transparent area where the circle used to be (Figure 17-6), allowing the Label's gray color to show through:

$b->configure(-maskfile => 'images/circle.msk');

Notice the bitmap's background color appears wherever the mask has an on bit and the original source bit is off.

Figure 17-6

Figure 17-6. Mask that's an inverted version of bitmap makes the bitmap's foreground transparent

Figure 17-7 shows a similar mask that has some bits set where the original source bits are also set, allowing the source foreground to show through.

Figure 17-7

Figure 17-7. Mask bits set over on source bits show the foreground color

The Bitmap command can read data inline instead of from a file, using the -data and -maskdata options.

17.5.1. Cool Tricks with an Empty Bitmap

We can make the cursor totally invisible by assigning it an empty, or transparent, bitmap such as this:

#define trans_cur_width 1
#define trans_cur_height 1
#define trans_cur_x_hot 0
#define trans_cur_y_hot 0
static unsigned char trans_cur_bits[] = {
   0x00};

a mask such as this:

#define trans_cur_width 1
#define trans_cur_height 1
static unsigned char trans_cur_bits[] = {
   0x01};

and a -cursor specification similar to this:

my $c = $mw->Canvas->grid;
$c->configure(-cursor =>
 ['@trans_cur.xbm', 'trans_cur.msk', 'black', 'white']);

How can this possibly be useful? Just wait and see.

17.5.1.1. An invisible cursor

The tiny mote that represents the display's cursor is an X11 bitmap. For some applications (mostly games), the built-in cursors are not sufficient. Playing Doom with an X pointer just won't work! But if we use a transparent bitmap, the cursor is completely invisible when it's over the Canvas, although it's possible to track it programmatically with a simple <Motion> binding:

$c->CanvasBind('<Motion>' => sub {
    my($c) = @_;
    my($x, $y) = ($Tk::event->x, $Tk::event->y);
    print "cursor at canvas coordinate ($x,$y)\n";
});

17.5.1.2. Filling a transparent Canvas item

An interesting problem cropped up on the pTk mailing list. The task at hand was to create a series of transparent Canvas items that also responded to bound events. Creating a transparent item such as an oval, polygon, or rectangle is simple enough: just don't give it a -fill color. Then all we see is the item's outline, and the Canvas background color or image shows through. Unfortunately, events such as <Motion> aren't generated unless the cursor is precisely over the item's outline. Waggling the cursor in the item's interior has no effect. To verify, run this code and notice that the print statement is executed only if we carefully and deliberately position the cursor over the oval's red outline.

my $cb = sub {
    print "Over circle, args = @_!\n";
};

my $c = $mw->Canvas->grid;
my $o1 = $c->createOval(25, 25, 100, 100,
    -outline => 'red',
);
$c->bind($o1, '<Motion>' => $cb);

If we give the oval a -fill color, the binding is triggered anywhere over the item, as we'd like, but the transparent effect is lost, and the Canvas background is obscured. But we can surmount this problem with an empty stipple bitmap (even a cursor bitmap!) coupled with any -fill color.

my $o2 = $c->createOval(155, 25, 225, 100,
    -outline => 'red',
    -fill    => 'blue',
    -stipple => '@trans_cur.xbm',
);
$c->bind($o2, '<Motion>' => $cb);

This oval has a red outline just like the first but is transparently filled such that it generates events anywhere, yet allows us to see through it. This feature was deemed important enough that a new built-in bitmap named transparent was added to Tk 800.020, which means that we can say -stipple => 'transparent' in newer Tks.



Library Navigation Links

Copyright © 2002 O'Reilly & Associates. All rights reserved.