FE 'tkGooie' Utilities

'IMAGEtools' group

Find-and-View
a batch of Images

(a 'front-end' for the 'find' command and
a user-selected image viewer program)
(FE = Freedom Environment)

FE Home Page > FE Downloads Page >

FE 'tkGooies' Description Page >

FE 'tkGooies' 'IMAGEtools' Page >

This
'Batch-Find-and-View-Images'
tkGooie Page

INTRODUCTION to
'tkBatchImageFindAndView'

I have a Tk-scripts 'to-do list'.

In that 'to do' list, I have a category of Tk scripts that I call 'Front Ends'.

The Tk scripts in that section are front ends for utility programs such as 'mplayer', 'ffmpeg', 'xrandr', 'du' (directory usage), and others.

In considering the GUI layouts for front-ends to programs like 'mplayer', 'ffmeg', and 'xrandr', I found that there are so many command-line options for these programs that the GUI's are going to contain a lot of widgets --- and they will probably require multiple 'panels' of 'prompting widgets'.

In doing my first 'Front End' script, I wanted to start out with a GUI that was not quite so complex.

In the past year, I have made some shell scripts for sweeping through sub-directories and selecting image files to display with a simple image display program --- like Image Magick 'display' --- or 'ffplay' --- or 'eog' (Eye of Gnome) --- on Linux.

These scripts use the 'find' command to sweep through sub-directories, looking for image files.

I decided to layout a Tk GUI as a 'front end' for such an image-viewing utility.

It turned out that the GUI could fit on one screen --- without using 'multiple panels of options'.

My 'text-sketch' for the GUI (after several revisions) was as follows.



  ------------------------------------------------------------------
  Batch-Find-and-View Images Front End  --- a Tk Image Viewer Utility
  [window title]
  ------------------------------------------------------------------

  {Exit} {Help} {LaunchViewerJob}      {CountFilenames} {ShowFilenames}
  
  Full Filename Mask (for image/s): ___________________  {Browse...}
  
  Viewer program : O ImageMagick 'display'    O 'ffplay'   O 'eog'
  
  Search Levels for Mask:  O ONE   O ALL subdirectories of selected dir
  
  Case Sense for Mask Search:  O case-sensitive  O case-INsensitive
  
  Files Size (MegaBytes):  _____  O bigger-than  O smaller-than
  
  Files Age (Days) : ______ O older-than  O younger-than

  --------------------------------------------------------

where

   Square brackets indicate a comment (not to be placed on the GUI).
   Braces indicate a Tk 'button' widget.
   Underscores indicate a Tk 'entry' widget.
   A colon indicates that the text before the colon is on a 'label' widget.
   Capital-O indicates a Tk 'radiobutton' widget.
   Capital-X indicates a Tk 'checkbutton' widget.


GUI Components

From the GUI 'sketch' above, it is seen that the GUI consists of about

  • 5 button widgets
  • 6 label widgets
  • 3 entry widgets
  • 11 radiobutton widgets in 5 groups
  • 0 checkbutton widgets
  • 0 scale widgets
  • 0 listbox widgets
  • 0 canvas widgets

All but the 'label' widgets provide operating parameters/options in this utility.

Hence there are about 5 + 3 + 11 = 19 user-specifiable options via the GUI of this utility.

This is relatively simple compared to the front end GUI's that I plan to use for 'ffmpeg' and 'mplayer'.

---

Front-End-for-Two

This 'Front End' GUI is essentially a 'wrapper' for TWO commands --- the 'find' command and the command that implements the image viewer.

    I was seeking to use suitable commands that are available on my operating system (Ubuntu 9.10, 2009 October, 'Karmic Koala').

    I found that the 'find' command in combination with a simple, 'light-weight' image viewer program would 'fill the bill'.

On the GUI, NOTE that only 'Viewer Program' is a parameter involving the image viewer.

The other parameters are for the 'find' command.

The Image Viewers

The image viewer programs 'eog' (Eye of Gnome), ImageMagick 'display', and 'ffplay' (that comes with the 'ffmpeg' package) come close to working OK as an image viewer --- but each one has a few drawbacks.

So I still have my eye out for another simple image viewer program to use, as mentioned further below (in some comments in the code).

You may wish to take advantage of certain features of image viewers --- or avoid certain features.

For example:

When animated GIF files are displayed, some image viewers behave differently from others.

The ImageMagick 'display' program shows each image within the animated GIF, whereas 'eog' (Eye of Gnome) shows only one image.

When you are searching for GIF files, you may wish to use 'eog', rather than get bogged down looking at every image within an animated GIF file when using 'display'.


Beautification of the GUI

I should point out here that I was not especially interested in coming up with a 'beautiful utility'.

I just wanted a utility that would be able to sweep through a hierarchy of sub-directories and pick out image files to show based on a rather 'rich' set of selection capabilities --- such as 'file-mask' and/or 'file-size' and/or 'file-age'.

    (I may add a 'file-type' capability based on using the 'file' command, in a future enhancement to this utility.

    DONE. See 'UPDATE' notes below.)


SOME GUI IMAGES

On the basis of the sketch above, I ended up with the GUI seen in the following image.

    (This is an old image. I have added a FileType entry field at the bottom of the GUI, as seen in the image at the top of this page.)

Note that there are a couple of radiobuttons that allow you to choose whether application of the file-mask is 'case-sensitive' or 'case-INsensitive'.

For example, if you chose 'case-INsensitive' and the mask were set to '*.jpg', then files with the suffix '.JPG' would also be selected.

And there are a couple of radiobuttons that allow you to choose whether to do the 'mask-search' at the current directory level only --- or to sweep through all sub-directories of the current 'base' directory, looking for images that satisfy the criteria chosen via this GUI.

Here is another place where I MAY make a future enhancement :

I may change the 'ONE' radiobutton to an 'N-levels' radiobutton --- and if that radiobutton is selected, an entry field could be activated where the user can enter a choice of N (with the entry field being initialized with '1').

---

Here is another image of the GUI, showing a different setting of most of the radiobuttons --- and entries placed in the 'file-size' and 'file-age' entry fields.


Note the 'FileSize' and 'FileAge' entry fields.

NOTE that most image-viewers, like 'eog' and more complex image viewers, are oriented toward scanning through ALL image files in a SINGLE directory.

This utility is oriented toward SELECTING image files (based on criteria such as a file-mask, file-size, and/or file-age) from an ENTIRE HIERARCHY OF SUB-DIRECTORIES --- as well as allowing mask-search in a SINGLE directory.

Furthermore, this utility can be used to view a single file.

Just select a full filename and do not change the last part of the filename to a mask.

Then click the 'Launch' button.

---

This utility can be useful without even using any of the viewer programs.

Say you want to know the number or names of the image files satisfying a set of criteria (file-mask, file-size, file-age).

Then set the criteria and click on the 'CountFilenames' or 'ShowFilenames' button.


DESCRIPTION OF THE CODE

Below, I provide the Tk script code for this 'multi-subdirectory tkBatchImageViewer' utility.

I follow my usual 'canonical' structure for Tk code for this Tk script:



  0) Set general window & widget parms (win-name, win-position,
     win-color-scheme, fonts, widget-geometry-parms, win-size-control,
     text-array-for-labels-etc).

  1a) Define ALL frames (and sub-frames, if any).
  1b) Pack   ALL frames and sub-frames.

  2) Define & pack all widgets in the frames, frame by frame.
              Within each frame, define ALL the widgets.
              Then pack the widgets.

  3) Define keyboard and mouse/touchpad/touch-sensitive-screen action
     BINDINGS, if needed.

  4) Define PROCS, if needed.

  5) Additional GUI initialization (typically with one or more of
     the procs), if needed.


This Tk coding structure is discussed in more detail on the page A Canonical Structure for Tk Code --- and variations.

This structure makes it easy for me to find code sections --- while generating and testing a Tk script, and when looking for code snippets to include in other scripts (code re-use).

I call your attention to step-zero.

One thing that I have started doing in 2013 is using a text-array --- named 'aRtext' --- for text in labels, buttons, and other widgets in the GUI.

This can make it easier for people to internationalize my scripts.

I will be using a text-array like this in most of my scripts in the future.


Experimenting with the GUI

As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus scripts, so far), I provide the four main 'pack' parameters --- '-side', '-anchor', '-fill', '-expand' --- on all of the 'pack' commands for the frames and widgets.

That helps me when I am initially testing the behavior of a GUI (the various widgets within it) as I resize the main window.

I think that I have used a pretty nice choice of the 'pack' parameters.

The label and button and radiobutton widgets stay fixed in size and relative-location if the window is re-sized --- while the entry widgets expand/contract horizontally whenever the window is re-sized horizontally.

You can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various frames and widgets --- to get the widget behavior that you want.

---

Additional experimentation with the GUI:

You might want to change the fonts used for the various GUI widgets.

For example, you could change '-weight' from 'bold' to 'normal' --- or '-slant' from 'roman' to 'italic'.

Or change font families.

In fact, you may NEED to change the font families, because the families I used may not be available on your computer --- and the default font that the 'wish' interpreter chooses may not be very pleasing.

I use variables to set geometry parameters of widgets --- parameters such as border-widths and padding.

And I have included the '-relief' parameter on the definitions of frames and widgets.

Feel free to experiment with those 'appearance' parameters as well.

If you find the gray 'palette' of the GUI is not to your liking, you can change the value of the RGB parameter supplied to the 'tk_setPalette' command near the top of the code.


Some features in the code

There are plenty of comments in the code to describe what most of the code-sections are doing.

You can look at the top of the PROCS section of the code to see a list of the procs used in this script, along with brief descriptions of how they are called and what they do.

The main procs are :



  'get_filemask'         - called by the 'Browse...' button
                           next to the filemask entry field

  'getImages_andCountPrintOrView'
                         - called by the 'LaunchViewJob', 'CountFilenames',
                           and 'ShowFilenames' buttons

  'popup_msgVarWithScroll' - called by 'Help' button to show HELPtext var.
                             Also used via the 'CountFilenames' and
                             'ShowFilenames' buttons.


One unique thing about this Tk GUI that is different from the 40-plus scripts that I have contributed (so far) to the Tclers' Wiki :

I used the following statement to allow the GUI to be expanded in the x-direction, but NOT the y-direction.

wm resizable . 1 0


Comments in the code

It is my hope that the copious comments in the code will help Tcl-Tk coding 'newbies' get started in making GUI's like this.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to watch videos of puppies and kittens.

That's nice. BUT ... How is that going to help the world develop the engineers, computer-scientists, and other scientists that are needed in a very challenging future world?

For example, we need people to help deal with that as-yet-undetected next-huge-asteroid that is on a collision course with the Earth --- perhaps sooner than most people think.

    Imagine what is going to happen when a medium-sized space-rock hits near one of the 100-plus nuclear power plants we have in the U.S.

    Of course, it may happen that an earthquake, from fracking --- or a flood, like the one that recently almost inundated a nuke plant in Nebraska --- may be more likely than a space-rock hit.

    We need properly trained and educated people to handle those distinct possibilities as well.


The Tcl-Tk CODE

Here is a link to CODE for the script

'find_and_imageViewer_FrontEnd.tk'.


Shell script #1
(called by the Tk script) :

And here is the code for the shell script called by this Tk script.

This is a 'wrapper script' for the 'find' command.

You can put this script in the same directory with the Tk script.

The Tk script includes some code (involving the 'argv0' variable) to determine the location of the shell script by extracting the name of the directory in which the Tk script lies.

Here is a link to CODE for the SHELL script

'findImages_forCriteria.sh'.


Shell script #2
(called by the Tk script) :

And here is the code for the shell script that provides the 'for' loop that feeds each image filename to the chosen viewer program.

You can put this script in the same directory with the Tk script.

Shell script #1 includes some code (involving the '$0' variable) to determine the location of the directory containing this shell script (and all 3 scripts) by extracting the name of the directory in which shell-script-1 lies.

Here is a link to CODE for the SHELL script

'forLoop_displayImgsInFile.sh'.


INSTALLING THESE SCRIPTS:

This set of 3 scripts could be put in a sub-directory of the user's home directory, such as

$HOME/apps/tkBatchImageViewer

Then the user can use their desktop system (such as Gnome or MATE or KDE) to set up the Tk script as an icon on the desktop.

Then the user can click on the icon to startup the 'front end'.


SOME ENHANCEMENTS :

This set of Tcl-Tk and shell scripts allows me to check off one of the 'front end' projects in the 'IMAGEtools' section of my 'to-do' list.

In the future, I plan to work on front ends for 'mplayer', 'ffmpeg', and 'xrandr'.

But I may return to the 'IMAGEtools' set of scripts to provide some enhancements.

For example:

sort

It would be convenient to simply call on the viewer program via the '-exec' option of 'find', which is how the viewer program was implemented in the initial version of this utility.

However, one finds that the sequence in which the image files are shown is not what the user will typically want.

The files seem to show in a rather random sequence, rather than showing up according to a filename sort.

This is probably because the 'find' command searches through files according to their 'inode' numbers rather than according to an alphanumeric sort order of their filenames.

Similarly, the 'ShowFilenames' option shows the files in a seemingly random order, rather than in an alphanumeric order by filename.

A sort is not needed with the 'CountFilenames' option, but I find that it is going to be desirable to incur the extra processing of the 'sort' command and insert a 'sort-pipe' after the 'find' command --- for the 'LaunchViewer' and the 'ShowFilenames' options.

For the 'view-images' option, one way to implement the 'pipe' is to pipe '-print' output from the 'find' command into the 'sort' command and then into the 'xargs' command, which will call on the viewer program.

But there can be problems in using the 'xargs' command when there are embedded spaces in filenames and when filenames are separated by line-feeds --- as is discussed on page 169-170 of the book 'Unix Power Tools' from publisher O'Reilly and Associates.

The output of 'man xargs' on my machine says that

find ... -print | xargs ...

"will work incorrectly if there are any filenames containing newlines or spaces".

It suggests using

find ... -print0 | xargs -0 ...

but I am not having success with that.

Since different versions of 'xargs' may behave differently, I may find that it is better to process the sorted filenames from 'find' with a 'for' loop, rather than using 'xargs'.

I will update the shell script presented on this page when I have an improvement to offer.

(DONE, as documented in an 'UPDATE' below.)


File-type

As I indicated near the top of this page, I may add another 'entry' widget to the GUI --- to support a 'file-type' search capability, based on using the 'file' command.

(DONE, as documented in an 'UPDATE' below.)

In that 'entry' widget, the user could enter keywords such as 'JPEG' or 'GIF' or 'PNG' to retrieve files for which the 'file' command returns text strings like the following:



 Typical
 file suffix  'file' command output
 -----------  ---------------------------------------

 jpg or jpeg  JPEG image data, JFIF standard 1.01

 gif          GIF image data, version 89a, 256 x 352

 png          PNG image, 1024 x 768, 8-bit/color RGB, non-interlaced

        JPEG = Joint Photographic Experts Group
        GIF = Graphics Interchange Format
        PNG = Portable Network Graphics

 Other, less-used image formats:

 pgm          Netpbm PGM "rawbits" image data

 ppm          Netpbm PPM "rawbits" image data

 tga          Targa image data - RGB - RLE 2000 x 2000

 tif or tiff  TIFF image data, big-endian

 xpm          X pixmap image text

 bmp          ASCII C program text
              [not very distinctive, but 'BM' is in the first 2 chars of this binary file]
  
 svg          ASCII English text
              [not very distinctive, but '>svg' is in the top few lines of this text file] 

 xbm          ASCII C program text
              [not very distinctive, but '#define' is in the top line of this text file]


The file-mask could be set to '*' --- to look for files of a specified type (JPEG, GIF, PNG, PGM, PPM, TIFF, Targa, 'X pixmap') , in one or more sub-directory levels --- no matter what suffix someone has used in naming the files.

Adding 'file' command processing to every file processed by the 'find' command will add a lot of processing to the find-search.

But this capability is worth implementing when one is dealing with image files for which the wrong suffix was supplied, or image files that were not even provided with a suffix like '.jpg' or '.gif' or '.png'.


maxdepth N

I also indicated near the top of this page that I may change the 'ONE' radiobutton to an 'N-levels' radiobutton.

If that radiobutton is selected, a small 'entry' field could be activated where the user can enter a choice of N (with the entry field being initialized with '1').

This capability would be implemented via the '-maxdepth' parameter of the 'find' command.

There is also a '-mindepth' parameter of the 'find' command. But I have never encountered a situation where I felt I needed to use that parameter.

---

There are a lot of parameters available with the 'find' command, but I think I have probably implemented the ones that are most useful to use for this 'multiple-subdirectory image-select-and-display' utility.

    (On second thought, a '-prune' capability might be handy --- to allow the user to avoid sub-directories with a user-specified name or mask-match.)

---

Note that, by editing these scripts, it is quite easy for you to switch out any of these viewer programs/commands to replace them with another image viewer that is available in your operating environment.

Simply change a 'radiobutton-text' assignment statement in the Tk script, and change an 'if-statement' in the 'forLoop' shell script --- to change the image-viewer-program-and-optional-viewer-arguments in an assignment statement for the 'IMGVIEWER' variable.


IN CONCLUSION

As I have said on several other code-donation pages on this wiki ...

There's a lot to like about a utility that is 'free freedom' --- that is, no-cost and open-source so that you can modify/enhance/fix it without having to wait for someone else to do it for you (which may be never).

A BIG THANK YOU to Ousterhout for starting Tcl-Tk, and a BIG THANK YOU to the Tcl-Tk developers and maintainers who have kept the simply MAH-velous 'wish' interpreter going.


UPDATE 2013dec13

I have added the 'File-Type' entry field to the GUI, as I indicated I might do in discussing 'SOME ENHANCEMENTS', above.

At the same time, I handled the 'sort' issue discussed above -- by using a 'for' loop technique rather than a 'pipe-to-xargs' technique.

The 'xargs' technique was problematic, and is likely to be problematic in various Linux/BSD/Mac/Unix operating system environments.

The following image shows the new 'File-Type' entry field being employed.

See the 'entry' field at the bottom of the GUI --- and the file-mask '*' being used in the 'entry' field near the top of the GUI.

I put a high priority on solving the 'sort' issue --- and decided to go ahead and add the File-Type-filter feature at the same time.

In order to implement the 'for' loop (to handle passing SORTED filenames to the user-selected image viewer program), I employed an additional shell script, which is called after the 'find' command gathers together a sorted list of filenames --- in the case that the 'LaunchViewer' button is used.

I have provided the new 'forLoop' shell script above.

This new set of 3 scripts now handle the 'sort' and 'File-type' enhancements that were discussed above.

The Help-text of the GUI has been updated to discuss the File-Type feature.

I leave the 'N-levels' and '-prune' enhancements to a future date.

These two features are similar in that they allow the user avoid 'dropping into' a sub-directory of image files which the user does not wish to process.

To implement the '-prune' feature would require adding yet another entry widget to the GUI --- to allow for entering one or more sub-directory names (or masks).

    I was wondering if one could actually use a mask in specifying directories to prune.

    Most 'find' command examples do not show using a mask-name for a prune-directory --- only complete directory-names.

    But I did a web search and found an example that indicates masks should be allowed :

    find   .   -type d   -name '.git*'   -prune \
    -o   -type f   -print

This example prunes (skips) any directories whose names match the '.git*' mask. Otherwise, any file name encountered is printed (sent to 'stdout').

In coming months, if I find a need for either the 'N-levels' or 'prune' features, I may implement them and update the code here.

After the current 'sort' and 'file-type' enhancements, I think this utility has reached a point of being quite useful.


UPDATE 2014jan08

In doing some testing for another 'front end' Tk GUI for the 'find' command, I found that the 'find' command does some unexpected 'round off' stuff when processing a '-size' parameter.

For example, if one has a size parameter like '-size +1M', this asks for files that are greater than 1 Megabyte in size.

However, as the 'find' command checks each file, it apparently rounds off its size to the nearest Megabyte BEFORE the comparison.

Hence any file less than 1.5 Megabytes in size is not included in the 'found' list.

For example, a 1.4 Megabyte file is treated as if it is 1.0 Megabytes in size --- which is not strictly greater than 1 Megabyte in size.

Unlike the age test (example: '-mtime +$Ndays') which does a greater-than-or-equal-to test triggered by the plus sign, the '-size' test with 'plus' sign does a greater-than test --- no equal-to test.

So I have made several changes to the Tk script and the shell script above --- to improve the size-checking :

  • Changed the 'granularity' of the size prompt of the Tk GUI --- from Megabytes to Kilobytes.

  • Changed the '-size +${Nmeg}M' *MEGABYTES* size check in the shell script to a '-size +${Nbytes}c' *CHARACTERS* size check --- by converting the kilobytes (entered by a user) to bytes.

  • Covered the unlikely case of a file being exactly N kilobytes in size when the user enters N in the Kilobytes entry field --- by adding an 'equal to' check to the 'greater than' (plus) check of the size parameter.

    More precisely, I changed the statement

    -size +${SIZEinBYTES}c

    to

    ( -size +${SIZEinBYTES}c   -o   -size ${SIZEinBYTES}c ).

Now there should be no 'holes' in the search for files of a 'bigger or smaller' size.

I have replaced the code for the Tk script and the shell script above with the new code with the few lines of changes.


UPDATE 2014apr26

In using this 'tkBatchImageViewer' on 'deep' directories --- that is, a 'find' search on about 200-plus subdirectories with 2,000-plus files in those subdirectories --- I found a few improvements that I needed to make in this Tk script and 2 associated shell scripts.

I found the following 'needs'.

  • Save filenames to temporary file

    When I used the 'CountFilenames' and 'ShowFilenames' and 'LaunchViewerJob' buttons with the same 'find' criteria, the same long 'find' search would have to be repeated --- unnecessarily.

    I needed to save the 'found-filenames' in an output file, and work off of that list of files when the 'find' criteria had not been changed by the user.

  • Progress indicator

    On a long 'find' search, a 'progress indicator' was needed to let the user know if the 'find' command was doing its job --- and to let the user know how far/fast the search was proceeding.

    Similarly, a 'progress indicator' was needed to let the user know which 'found-image' was being shown when hundreds of image files were being displayed.

To handle these needs, I made the following changes to the 3 scripts.

  • ***
    In the Tk script, set the filename of a temporary file to be used to hold the names of image files found by the 'find' search --- in variable 'outFILE'.

  • ***
    In the Tk script, added 'PREV' variables to be used to hold about 8 previous 'find' search criteria --- to be used to indicate when the user has changed a 'find' criterion.

  • ***
    In the Tk script, added a proc called 'check_for_criterion_change' --- to determine if a criterion variable has been changed by the user.

  • ***
    In the Tk script, replaced the 'getImages_andCountPrintOrView.sh' shell script --- that had 'count', 'print', and 'view' sections --- by a 'findImages_forCriteria.sh' shell script that performs just the 'find' search and puts the found-files in a temporary '$outFILE' file --- only if one of the 'find' search criteria was changed by the user.

  • ***
    Made the 'findImages_forCriteria.sh' shell script from the old 'getImages_andCountPrintOrView.sh' shell script.

    Changed the arguments passed to the shell script to be just the 'find' search criteria variables --- not the image-viewer variables.

  • ***
    In the Tk script, provided an 'xterm' call in the 'exec' statement for the 'findImages_forCriteria.sh' shell script, to allow for better visibility of how a lengthy 'find' is progressing.

    The 'find' command in the 'findImages_forCriteria.sh' shell script was changed to show directories being searched, as well as files being found, in order to provide a better 'progress indicator'.

  • ***
    In the 'forLoop_displayImgsInFile.sh' script, added 'CNT' and 'TOTALfiles' variables and an 'echo' statement --- so that the 'xterm' window that is used to 'exec' this script in the Tk script will display to the user a count of how many of the 'found-image-files' have been displayed so far.

I have made these changes and replaced the Tk script and the 2 shell scripts above.

Now I am feeling like this is a quite robust utility.

Bottom of this page for
Batch-Find-and-View Images
--- a utility in the FE 'tkGooies' system,
in the 'IMAGEtools' group.

To return to a previously visited web page location, click on the Back button of your web browser a sufficient number of times. OR, use the History-list option of your web browser.
OR ...

< Go to Top of Page, above. >

Page history:

The code was created in 2013 --- and posted 2013 Dec 10 at http://wiki.tcl.tk/39053.

This FE web page was created 2014 May 13.
(as a backup and alternative to the wiki.tcl.tk page)

This page was changed 2015 Oct 05.
(Small changes.)

Page was changed 2019 Feb 25.
(Added css and javascript to try to handle text-size for smartphones, esp. in portrait orientation.)

Page was changed 2019 Jun 25.
(Specified image widths in percents to size the images according to width of the browser window.)


NOTE:
The code here MAY BECOME more 'up-to-date' than the code posted on the Tcler's Wiki ---
wiki.tcl-lang.org --- formerly wiki.tcl.tk.