We could go on about Tk for another few hundred pages, but that's
another book. The following program is our final Tk example---a
simple GIF image viewer. You can select a GIF filename from the
scrolling list, and a thumb nail version of the image will be
displayed. There are just a
few more things we'd like to point
out.
Have you ever seen an application that creates a ``busy cursor'' and
then forgets to reset it to normal? There's a neat trick in
Ruby that will prevent this from happening. Remember how
File.new
uses a block to ensure that the file is closed after it
is used? We can do a similar thing with the method
busy
, as shown
in the next example.
This program also demonstrates some simple
TkListbox
manipulations---adding elements to the list, setting up a callback on a
mouse button release,
[You probably want the button release,
not the press, as the widget gets selected on the button press.] and
retrieving the current selection.
So far, we've used
TkPhotoImage
to only display icons directly,
but you can also zoom, subsample, and show portions of images as
well. Here we use the subsample feature to scale down the image for
viewing.
require 'tk'
def busy
begin
$root.cursor "watch" # Set a watch cursor
$root.update # Make sure it updates the screen
yield # Call the associated block
ensure
$root.cursor "" # Back to original
$root.update
end
end
$root = TkRoot.new {title 'Scroll List'}
frame = TkFrame.new($root)
list_w = TkListbox.new(frame, 'selectmode' => 'single')
scroll_bar = TkScrollbar.new(frame,
'command' => proc { |*args| list_w.yview *args })
scroll_bar.pack('side' => 'left', 'fill' => 'y')
list_w.yscrollcommand(proc { |first,last|
scroll_bar.set(first,last) })
list_w.pack('side'=>'left')
image_w = TkPhotoImage.new
TkLabel.new(frame, 'image' => image_w).pack('side'=>'left')
frame.pack
list_contents = Dir["screenshots/gifs/*.gif"]
list_contents.each {|x|
list_w.insert('end',x) # Insert each file name into the list
}
list_w.bind("ButtonRelease-1") {
index = list_w.curselection[0]
busy {
tmp_img = TkPhotoImage.new('file'=> list_contents[index])
scale = tmp_img.height / 100
scale = 1 if scale < 1
image_w.copy(tmp_img, 'subsample' => [scale,scale])
tmp_img = nil # Be sure to remove it, the
GC.start # image may have been large
}
}
Tk.mainloop
|
Finally, a word about garbage collection---we happened to have a few
very large GIF files lying about
[They were technical
documents! Really!] while testing this code. We didn't want to
carry these huge images around in memory any longer then necessary, so
we set the image reference to
nil
and call the garbage collector
immediately to remove the trash.