Updated 2014-06-07 20:21:07 by uniquename

uniquename - 2013sep05

I recently posted an angle selector utility on this wiki --- at 'tkAngle-Convert-Select - radians, degrees, percents-of-circumference-of-circle' [1].

I based that GUI on my color-selector GUI (with 3 'slider buttons') --- whose code I contributed at A non-obfuscated color selector GUI.

I watch a lot of tennis and the various tournaments around the world usually have a speed gun that measures the speed of serves --- and occasionally the speedgun picks up the speed of ground strokes.

In some countries, the speed guns report the speed in kilometers per hour --- in other countries, in miles per hour.

Some tennis announcers pride themselves on being able to convert quickly from kph to mph and vice versa. I don't do the conversion frequently enough to make it worth committing a technique to memory --- BUT I realized that I could easily make a 'tkSpeedGun' conversion utility --- based on the code I used for the 'tkAngle-Convert-Select' utility.

Like the 'angle converter' GUI, for the 'speed converter' GUI, the 3 sliders would need to move together. And the Tk 'scale' widget handles that nicely. In Tk, a variable is associated with each 'slider', and any time the value of that variable changes, the slider moves to reflect the changed value.

I just needed to make sure that when any of the 3 variables (containing the value of a speed in 3 different units) changed, the other 2 variables were changed correspondingly.

---

No Canvas on This One:

In addition to the 3 'scale' widgets, on the 'color selector' utility there was a 'color swatch' (which was done with a 'frame' widget) whose color changed as any of the 3 scales were changed.

For the 'angle selector' utility, I used a 'canvas' widget, on which a representation of the current angle could be drawn --- as a circle and a filled-arc on the circle.

For this 'speed selector' utility, I was not imaginative enough to think of something to draw on a 'canvas' widget to represent the current speed settings. So there is no canvas on this 'speed gun' GUI.

---

Some Fun with the 3rd Speed:

I knew I wanted to use kilometers/hour and miles/hour for 2 of the scales on the GUI. I decided to have a little fun with the 3rd scale and have it present the speed of the other 2 scales in a rather unusual unit of measure.

I thought of light-years for the distance, and needed to figure out what time-unit gave a value somewhat in the realm of comprehension --- i.e. not some huge number involving, say, 10 to the twelfth.

It turns out that a billion years gives some almost-mentally-digestable units --- even though the LPB (Light-years Per Billion-years) units are, in themselves, out of the realm of everyday experience.

But here was a chance to show LPB speed values that correspond to everyday KPH and MPH values.

So I set to work converting the code of the angle-converter-selector GUI to a 'tkSpeedGun' GUI, and I ended up with the GUI seen in the following image.

Whenever ONE of the 'sliders' is moved with mouse-button1 :

  • the other TWO sliders move (showing the converted values)
  • the 3 text areas change to present the current 3 values for the speed (available for copy-paste into another window on the desktop)

The new values show as soon as mouse-button1 is released.

The 'Help' button on the GUI provides pretty complete and detailed help for using the GUI.

Here is most of the Help:

*** HELP for this tkSpeedGun-Convert-Select GUI ****
This TkGUI script provides a GUI for showing speeds
between zero and 2,000 kilometers-per-hour (this max
is easy to change) --- in three different units:

      - mph (miles-per-hour)
      - kph (kilometers-per-hour)
      - LPB (Lightyears-Per-Billion-years).


*******************************
SOME NOTEWORTHY SPEEDS (in kph):

speed of light in a vacuum = 1.07925285 billion kph

                           = 1,079,252,850 kph

speed of sound in air at sea level = 1,225.044 kph

                                   = 343.2 meters/second

(And sound travels about 4.3 times faster in water,
 and nearly 15 times faster in iron.)

terminal velocity of a skydiver  = about 200 kph

speed limit of 80 mph            =  128.7 kph

max (burst) speed of a cheetah   = about 112 kph

speed limit of 60 mph            =  96.6 kph

max speed of a horse             = about 88 kph

human walking speed of 4 mph     =  6.4 kph


****************************************
CONVERSION FACTORS BETWEEN 'LPB' and KPH:

1 light-year = 9.4605284 × 10^12 kilometers
             = 9.46 trillion kilometers

1 billion years = ? hours
                = 10^9 years * 365 days/year * 24 hours/day
                = 8.760 x 10^12 hours
                = 8.76 trillion hours

So

1 light-year/billion-years (LPB) =  1.0799 kph

or

1 kph =  0.9260 LPB

So multiply kph by 0.926 to get LPB.


****************************
THE CONVERSION FUNCTIONALITY:

Three different (but corresponding) speeds are shown (and
selected for conversion) via 3 'slider-buttons' on 3 Tk
'scale' widgets. 

These 3 different (corresponding) speed numbers are also shown
in 3 'text' widgets, several characters wide --- from which a
user can copy-and-paste the numbers from this GUI window to
some other window. 

For any 'slider' change, this GUI script IMMEDIATELY updates
the location of the other 2 'SLIDERS' --- when you RELEASE
the slider-button that you are moving.

The 3 TEXT widgets, showing the speed in the 3 different
units, are also IMMEDIATELY updated whenever any one of the 3
scale widget 'sliders' are changed.

***************************
FINE CONTROL OF THE SLIDERS:

Most people know that you can drag the sliders by clicking
on the 'slider button' with mouse-button1 and dragging the
slider button. This is a rather coarse way of moving the
slider button.

It is not so obvious that the Tk scale widget also allows
you to move the 'slider button' by clicking in the 'trough'
on EITHER SIDE of the slider button. By repeated clicking
in the trough, the slider can be advanced one scale-resolution
unit per click.

Furthermore, one can RAPIDLY move the slider button ONE
RESOLUTION UNIT per 'auto-click' by clicking in the trough
and HOLDING down the mouse button. The slider moves
one resolution unit repeatedly UNTIL the mouse button
is RELEASED.

**************************
THE SELECTOR FUNCTIONALITY:

By clicking on the 'UseIt' button on the GUI, this script
returns a string containing the current speed (in the
3 different units) to a calling script/application.

When using this script in another script/program,
this script will accept a speed (in kph) as an
argument --- which is used to initialize the
      - setting of the 3 'sliders', and
      - the numbers shown in the 3 small text widgets.

*************************
SOME USES of this utility:

   1) Useful for helping math-science students get a visual
      'feel' for the relation between mph, kph, and LPB.

   2) Also could be useful for a person wanting to convert
      from one unit to another --- for example, a tennis serve
      in miles-per-hour to kilometers-per-hour --- or vice versa.

   3) IN A SHELL SCRIPT or ANOTHER TK SCRIPT, this Tk script can
      ACT AS AN SPEED SELECTOR by passing the current speed
      (in the 3 different units) to stdout, when the 'UseIt' button
      is clicked.
            Example output string:  60.0  96.6  89.5

                                    (mph , kph , LPB)

Note:
The user can set up this script as an icon on a desktop so that
the GUI can be started up by a click (or two) on the icon ---
say, while you are watching a tennis tournament.

The code

Below, I provide the Tk script code for this 'tkSpeedGun-Convert-Select' 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 new thing that I have started doing recently is using a text-array 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.

In this particular GUI, like for the 'color selector' GUI on which it was based, I have chosen to make the window stay at the same size that it takes when it is initially 'packed'.

However, one could comment the statement
   wm resizable . 0 0

and let the statements that set the min-width and min-height values take effect, along with
   wm minsize . $minWinWidthPx $minWinHeightPx

If you want to make the window resizable, 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.

... and think of a nice canvas widget to add, with some appropriate dynamic image placed upon it.

___

Additional experimentation: 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.

Some features in the code

That said, here's the code --- with plenty of comments 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 simply

  • speed_update - called once initially, and then by button1-release bindings on the scale widgets
  • put_vars - called by the 'UseIt' button, to return the 3 speed values to stdout
  • popup_msgVarWithScroll - called by the 'Help' button

The main proc is the 'speed_update' proc. As any of the 3 sliders is changed, it

  • sets the value for the other 2 sliders
  • updates the small text widgets that hold the speed in 3 different units.

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 amazing tennis shots.

 Code for Tk script 'tkSpeedGun-Convert-Select_kph-mph-etc.tk' :

#!/usr/bin/wish -f
##
##+#######################################################################
## NOTE:
##   If the 'wish' interpreter is in another directory, like
##   /usr/local/bin, you, as root, can make a soft-link from 'wish' there
##   to /usr/bin/wish --- with a command like
##             ln -s /usr/local/bin/wish  /usr/bin/wish
##   The form of this command:
##             ln -s <filename-of-existing-file> <name-of-new-link-file>
##+#######################################################################
## Tk SCRIPT NAME:   tkSpeedGun-Convert-Select_kph-mph-etc.tk           
##
##+#######################################################################
## PURPOSE:  This TkGUI script provides a GUI for showing speeds
##           between absolute zero and several thousand kilometers-per-hour
##           --- in at least three different units:
##             - kilometers-per-hour (kph)
##             - miles-per-hour (mph)
##             - 'wild' units, like lightyears-per-byr(billion years), say
##               LPB for short, where we can convert kph to LPB with the
##               factor 0.926 LPB/kph. In other words, one kph is approx.
##               equal to one lightyear-per-billion-years.
##
##           (We could add other units, such as meters-per-second.)
##
##           These 3 different units are shown (and selected for conversion)
##           via 3 'sliders' of 3 Tk 'scale' widgets. 
##
##           These 3 different (corresponding) numbers are also shown
##           in 3 'text' widgets, a few characters wide --- from which
##           a user can copy-and-paste the numbers from this GUI window 
##           to some other window. 
##
##           For any 'slider' change, this GUI script IMMEDIATELY updates
##           the location of the other 2 'SLIDERS'.
##
##           The 3 TEXT widgets, showing the speed in the 3 different
##           units, are also IMMEDIATELY updated whenever any one of the 3
##           scale widget 'sliders' are changed.
##
##           By clicking on a 'UseIt' button on the GUI, this script
##           returns a string containing the current speed (in the
##           3 different units) to a calling script/application.
##
##           This script will accept a speed (in kph) which is
##           used to initialize the
##             - setting of the 3 'sliders', and
##             - the numbers shown in the 3 small text widgets.
##
## SOME USES for this utility:
##
##       1)  Useful for helping math-science students get a visual
##           'feel' for the relation between mph, kph, and LPB.
##
##       2)  Could be useful for a person wanting to convert
##           from one unit to another --- for example, a tennis serve
##           in miles-per-hour to kilometers-per-hour --- or vice versa.
##
##       3)  IN A SHELL SCRIPT OR ANOTHER TK SCRIPT, this Tk script can
##           ACT AS AN SPEED/VELOCITY SELECTOR by passing the current speed
##           (in the 3 different units) to stdout, when the 'UseIt' button
##           is clicked.
##           Example output string:  60.0  ?    ?
##                                   (mph,kph,LPB)
##+########################################################################
## 'CANONICAL' STRUCTURE OF THIS CODE:
##
##  0) Set general window parms (win-name, win-position, win-color-scheme,
##     fonts, widget-geom-parms, win-size-control, text-array-for-labels-etc).
##  1a) Define ALL frames (and sub-frames).
##  1b) Pack   ALL the frames and sub-frames.
##  2) Define & pack all widgets in the frames, frame by frame.
##
##  3) Define key and mouse/touchpad/touch-sensitive-screen 'event'
##     BINDINGS, if needed.
##  4) Define PROCS, if needed.
##  5) Additional GUI INITIALIZATION (typically with one or two
##                procs in section 4), if needed.
##
##+#################################
## The code structure in more detail, for this particular script:
##
##  1a) Define ALL frames: 
##        Top-level : 'fRbuttons'  , 'fRsliders'
##
##        Sub-frames: 'fRsliders.fRmph' , 'fRsliders.fRkph' , 'fRsliders.fRlpb'
##
##        'fRbuttons' is to be on the top of the GUI, and
##        'fRsliders' is to be on the bottom of the GUI.
##
##        The 'fRmph', 'fRkph', 'fRlpb' sub-frames of the 'fRsliders' frame
##        are to be packed top to bottom.
##
##        The 3 scale widgets are to be oriented horizontally in the
##        3 sub-frames.
##
##  1b) Pack ALL frames.
##
##  2) Define & pack all widgets in the frames -- basically going through
##     frames & their interiors in top-to-bottom and/or left-to-right order:
##
##      'fRbuttons'    - to contain several buttons --- and 3 pairs of
##                       label-and-text widgets to display the current
##                       speed, in the 3 different units, in the
##                       3 text widgets.
##
##      'fRsliders'    - to contain 3 sliders - 'scale' widgets, along with
##                       3 'label' widgets.
##
##  3) Define BINDINGS:  button1-release on the 3 sliders calls the proc
##                       'speed_update'.
##
##  4) Define PROCS:
##     'speed_update'   - called by button1-release bindings on 3 scale widgets.
##                        (One could someday try calling this proc in the
##                         '-command' options on the 3 scales.)
##     'put_vars'               - called by the 'UseIt' button
##     'popup_msgVarWithScroll' - called by the 'Help' button
##
##  5) Additional GUI INITIALIZATION:  none, except for setting
##                                     the HELPtext var for the Help button.
##
##+#######################################################################
## DEVELOPED WITH:
##   Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october release, 'Karmic Koala').
##
##   $ wish
##   % puts "$tcl_version $tk_version"
##                                  showed   8.5 8.5   on Ubuntu 9.10
##    after Tcl-Tk 8.4 was replaced by 8.5 --- to get anti-aliased fonts.
##+########################################################################
## MAINTENANCE HISTORY:
## Created by: Blaise Montandon 2013aug22 Started on Ubuntu 9.10, based
##                                        on the color-selector script
##                                        of the FE (Freedom Environment)
##                                        subsystems. Ref: www.freedomenv.com   
## Changed by: Blaise Montandon 20.......
##+############################################################################

##+#################################
## SET THE TOP WINDOW NAME.
##+#################################

wm title . \
   "tkSpeedGun-Convert-Select -  mph, kph, LPB"

wm iconname . "SpeedConvert"

# catch { wm title    . "$env(FE_WIN_TITLE)" }
# catch { wm iconname . "$env(FE_ICON_TITLE)" }


##+###################################
##  SET THE TOP WINDOW POSITION.
##+###################################

wm geometry . +15+30

# catch {eval wm geometry . "$env(FE_SPEEDSEL_GEOM)" }


##+#######################################################################
## SET COLOR SCHEME (palette) FOR THE WINDOW.
##+#######################################################################

if {0} {
##  Gray palette 
set Rpal255 210
set Gpal255 210
set Bpal255 210
}

if {0} {
##  Bluish palette 
set Rpal255 100
set Gpal255 0
set Bpal255 255
}

if {1} {
##  Greenish palette 
set Rpal255 160
set Gpal255 255
set Bpal255 0
}


if {0} {
##  Redish palette 
set Rpal255 255
set Gpal255 0
set Bpal255 100
}
     
set hexCOLORpal [format "#%02X%02X%02X" $Rpal255 $Gpal255 $Bpal255]

tk_setPalette $hexCOLORpal


## Set color background for some widgets.

# set radbuttBKGD "#c0c0c0"
# set chkbuttBKGD "#c0c0c0"
# set listboxBKGD "#f0f0f0"
# set entryBKGD   "#f0f0f0"
set scaleBKGD   "#f0f0f0"
set textBKGD    "#f0f0f0"


##+#######################################################################
## SET FONT ATTRIBUTE VARS to use in the 'font create' statements below.
##+#######################################################################

set FONTsize 14
set FONT_SMALLsize 12

## For variable width:

set FONT_varwidth \
   " -family {comic sans ms} -size -$FONTsize -weight bold -slant roman "

set FONT_SMALL_varwidth \
   " -family {comic sans ms} -size -$FONT_SMALLsize -weight normal -slant roman "


## For fixed width:

set FONT_fixedwidth \
   " -family {dejavu sans mono} -size -$FONTsize -weight bold -slant roman "


set FONT_SMALL_fixedwidth \
   " -family {dejavu sans mono} -size -$FONT_SMALLsize -weight normal -slant roman "


##+#####################################################################
## DEFINE (temporary) FONT NAMES to be used in '-font' widget specs below.
##
## We use VARIABLE WIDTH fonts for LABEL and BUTTON widgets.
##
## We generally use FIXED WIDTH fonts for LISTBOX text,
## ENTRY widget text, and, often, for TEXT widget text.
##+#####################################################################

eval font create fontTEMP_button  $FONT_varwidth
eval font create fontTEMP_label   $FONT_varwidth
eval font create fontTEMP_scale   $FONT_varwidth

# eval font create fontTEMP_entry   $FONT_fixedwidth
# eval font create fontTEMP_listbox $FONT_fixedwidth
# eval font create fontTEMP_msg     $FONT_fixedwidth

eval font create fontTEMP_text    $FONT_fixedwidth


# eval font create fontTEMP_SMALL_button  $FONT_SMALL_varwidth
# eval font create fontTEMP_SMALL_label   $FONT_SMALL_varwidth
# eval font create fontTEMP_SMALL_scale   $FONT_SMALL_varwidth

# eval font create fontTEMP_SMALL_entry   $FONT_SMALL_fixedwidth
# eval font create fontTEMP_SMALL_listbox $FONT_SMALL_fixedwidth
# eval font create fontTEMP_SMALL_msg     $FONT_SMALL_fixedwidth

# eval font create fontTEMP_SMALL_text    $FONT_SMALL_fixedwidth


##+#######################################################################
## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS.
## (e.g. padx,pady for buttons)
##+#######################################################################

## For BUTTON widgets:
   
set PADY_button 0
set PADX_button 0

set BDwidth_button 2


## For LABEL widgets:

set PADXpx_label 0
set PADYpx_label 0

set BDwidthPx_label 2


## SCALE geom parameters:

set BDwidthPx_scale 2
set initScaleLengthPx 300
set scaleWidthPx 10


## For TEXT widgets:

set BDwidth_text 2


if {0} {

## CANVAS geom parms:

set initCanWidthPx  200
set initCanHeightPx 200

# set BDwidthPx_canvas 2
  set BDwidthPx_canvas 0


## For ENTRY widgets:

set BDwidth_entry 2


## For LISTBOX widgets:

set BDwidth_listbox 2


## For MESSAGE widgets:

set BDwidth_msg 2

}
## END OF if {0}


##+###################################################################
## Set a MINSIZE of the window (roughly). (OR fix the window size.)
##
## For WIDTH, allow for a minwidth of the '.fRbuttons' frame:
##            about 3 buttons (UseIt,Cancel,Help) and 3 pairs
##            of label-and-text widgets.
##
## For HEIGHT, allow about
##             2 chars  high for the '.fRbuttons' frame
##           300 pixels high for the '.fRsliders' frame.
##+#######################################################################
## We allow the window to be resizable and we pack the 'fRsliders' frame
## with '-fill both -expand 1' so that the sliders frame can be enlarged by
## enlarging the window.

set minWinWidthPx [font measure fontTEMP_button \
   " UseIt  Cancel  Help  MPH:     ??.?  KPH:      ??.?  LPB:     ??.?"]

## Add some pixels to account for right-left-side window decoration
## (about 8 pixels), about 8 widgets x 4 pixels/widget for borders/padding
## for 8 widgets --- buttons and labels.

set minWinWidthPx [expr {40 + $minWinWidthPx}]


## MIN HEIGHT ---
##     2 chars  high for the '.fRbuttons' frame
##     2 chars  high for each of the 3 scales in the '.fRsliders' frame

set CharHeightPx [font metrics fontTEMP_varwidth -linespace]

set minWinHeightPx [expr {8 * $CharHeightPx}]

## Add about 28 pixels for top-bottom window decoration,
## about 4 frames x 4 pixels/frame for each of the 4 stacked frames
## and their widgets (their borders/padding).

set minWinHeightPx [expr {44 + $minWinHeightPx}]


## FOR TESTING:
#   puts "minWinWidthPx = $minWinWidthPx"
#   puts "minWinHeightPx = $minWinHeightPx"

wm minsize . $minWinWidthPx $minWinHeightPx


## If you want to make the window un-resizable, 
## you can use the following statement.
  wm resizable . 0 0


##+########################################################################
## Set a TEXT-ARRAY to hold text for buttons & labels on the GUI.
##     NOTE: This can aid INTERNATIONALIZATION. This array can
##           be set according to a nation/region parameter.
##+########################################################################

## if { "$VARlocale" == "en"}

## For '.fRsliders' frame:

set aRtext(labelSCALEmph) "miles-per-hour (mph):"
set aRtext(labelSCALEkph) "kilometers-per-hour (kph):"
set aRtext(labelSCALElpb) "Lightyears-Per-Billion-years (LPB):"


## For '.fRbuttons' frame:

set aRtext(buttonUSEIT)  "UseIt"
set aRtext(buttonCANCEL) "Cancel"
set aRtext(buttonHELP)   "Help"

set aRtext(labelTEXTmph) "  MPH:"
set aRtext(labelTEXTkph) "  KPH:"
set aRtext(labelTEXTlpb) "  LPB:"


## END OF  if { "$VARlocale" == "en"


##+########################################################################
##
##  GET INPUT PARM VALUE -- 
##  i.e. set VARkph from
##
##         1) an argument passed to this script
##      OR 
##         2)  environment var VAR_KPH
##
##+########################################################################
##+########################################################################
##  Example argc/argv processing:
##
## if {$argc == 0} {
##    set VARtext "$env(CONFIRM_TEXT)"   
## } else {
##    set VARtext [lindex $argv 0]
## }
##+########################################################################

if {$argc == 1} {
   set VARkph [lindex $argv 0]
} else {
   set VARkph 100.0
   catch { set VARkph "$env(VAR_KPH)" }
}

set VARmph [expr {0.6214 * $VARkph}]
set VARlpb [expr {0.926 * $VARkph}]


##+####################################################################
## DEFINE *ALL* THE FRAMES:
##   TOP-LEVEL FRAMES:
##     - 'fRbuttons'  - to contain several buttons (UseIt,Cancel,Help), 
##                      as well as 3 pairs of label-and-text widgets.
##     - 'fRsliders'  - to contain 3 sliderbars, with 3 labels.
##
##  'fRsliders' is packed below the 'fRbuttons' frame.
##
##   SUB-FRAMES:
##     - 'fRsliders.fRmph'  (to contain 1 label-and-scale widgets pair)
##     - 'fRsliders.fRkph'  (to contain 1 label-and-scale widgets pair)
##     - 'fRsliders.fRlpb'  (to contain 1 label-and-scale widgets pair)
##
##  These 3 sub-frames are packed top to bottom.
##+####################################################################

## FOR TESTING:  (like expansion of frames, during window expansion)
# set RELIEF_frame raised
# set BDwidth_frame 2

set RELIEF_frame flat
set BDwidth_frame 0

frame .fRsliders  -relief $RELIEF_frame  -borderwidth $BDwidth_frame
frame .fRbuttons  -relief $RELIEF_frame  -borderwidth $BDwidth_frame

set RELIEF_frame raised
set BDwidth_frame 2

frame .fRsliders.fRmph -relief $RELIEF_frame  -borderwidth $BDwidth_frame
frame .fRsliders.fRkph -relief $RELIEF_frame  -borderwidth $BDwidth_frame
frame .fRsliders.fRlpb -relief $RELIEF_frame  -borderwidth $BDwidth_frame


##+########################################################
## PACK *ALL* the FRAMES.
##+########################################################

pack  .fRbuttons \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0

pack .fRsliders \
   -side top \
   -anchor nw \
   -fill x \
   -expand 1

## Pack the sub-frames.

pack .fRsliders.fRmph \
     .fRsliders.fRkph \
     .fRsliders.fRlpb \
   -side top \
   -anchor nw \
   -fill x \
   -expand 0


##+################################################################
## The frames are now defined and packed.
##+################################################################
## START DEFINING & PACKING WIDGETS WITHIN THEIR FRAMES. 
##+################################################################
##+################################################################


##+########################################################
## IN THE 'fRbuttons' frame -- DEFINE several BUTTONS ---
## 1 'UseIt' BUTTON, 1 'Cancel' BUTTON,
## 1 'Help' BUTTON, and
## 3 'TEXT' WIDGETS (rather than a 'label' or 'message' widget,
## so that it is possible to paste the text values
## to another window). Each text widget with a label widget.
##  THEN PACK THE WIDGETS.
##+########################################################

button .fRbuttons.buttUSEIT \
   -text "$aRtext(buttonUSEIT)" \
   -font fontTEMP_button \
   -padx $PADX_button \
   -pady $PADY_button \
   -relief raised \
   -bd $BDwidth_button \
   -command {put_vars}
 
button .fRbuttons.buttCANCEL \
   -text "$aRtext(buttonCANCEL)" \
   -font fontTEMP_button \
   -padx $PADX_button \
   -pady $PADY_button \
   -relief raised \
   -bd $BDwidth_button \
   -command {exit}

button .fRbuttons.buttHELP \
   -text "$aRtext(buttonHELP)" \
   -font fontTEMP_button \
   -padx $PADX_button \
   -pady $PADY_button \
   -relief raised \
   -bd $BDwidth_button \
   -command {popup_msgVarWithScroll .topHelp "$HELPtext"}


## Provide label-and-text widgets for the speed values
## in several different units.

set widthChars 10
set widthFiller "          "

## MPH:

label .fRbuttons.labTEXTmph \
   -text "$aRtext(labelTEXTmph)" \
   -font fontTEMP_label \
   -justify left \
   -anchor w \
   -relief flat \
   -padx $PADXpx_label \
   -pady $PADYpx_label \
   -bd $BDwidthPx_label

text .fRbuttons.txtVARmph \
   -font fontTEMP_text \
   -height 1 \
   -width $widthChars \
   -wrap none \
   -relief raised \
   -borderwidth $BDwidth_text \
   -bg $scaleBKGD


## KPH:

label .fRbuttons.labTEXTkph \
   -text "$aRtext(labelTEXTkph)" \
   -font fontTEMP_label \
   -justify left \
   -anchor w \
   -relief flat \
   -padx $PADXpx_label \
   -pady $PADYpx_label \
   -bd $BDwidthPx_label

text .fRbuttons.txtVARkph \
   -font fontTEMP_text \
   -height 1 \
   -width $widthChars \
   -wrap none \
   -relief raised \
   -borderwidth $BDwidth_text \
   -bg $scaleBKGD


## LPB:

label .fRbuttons.labTEXTlpb \
   -text "$aRtext(labelTEXTlpb)" \
   -font fontTEMP_label \
   -justify left \
   -anchor w \
   -relief flat \
   -padx $PADXpx_label \
   -pady $PADYpx_label \
   -bd $BDwidthPx_label

text .fRbuttons.txtVARlpb \
   -font fontTEMP_text \
   -height 1 \
   -width $widthChars \
   -wrap none \
   -relief raised \
   -borderwidth $BDwidth_text \
   -bg $scaleBKGD


## Pack the widgets in frame '.fRbuttons'.

pack .fRbuttons.buttUSEIT \
     .fRbuttons.buttCANCEL \
     .fRbuttons.buttHELP \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


pack .fRbuttons.txtVARlpb \
     .fRbuttons.labTEXTlpb \
     .fRbuttons.txtVARkph \
     .fRbuttons.labTEXTkph \
     .fRbuttons.txtVARmph \
     .fRbuttons.labTEXTmph \
   -side right \
   -anchor e \
   -fill none \
   -expand 0


##+########################################################
## Prepare some scale-parameter variables for use in
## defining the 3 scales below.
##+########################################################

# set scaleLenPx 350
# set scaleLenPx [expr {$minWinWidthPx - 40}]
set scaleLenPx $minWinWidthPx

set scaleThickPx 10

set KPHmin 0.0
set KPHmax 2000.0

set MPHmin 0.0
set MPHmax [expr {0.6214 * $KPHmax}]

set LPBmin 0.0
set LPBmax [expr {0.926 * $KPHmax}]

# set resolution 1
# set digits 4

set resolution 0.1
set digits 5

set labelChars 29


##+########################################################
## IN THE 'fRsliders.fRmph' frame -- DEFINE 
## a LABEL widget and a SCALE widget.
## The scale is oriented horizontally.
## THEN PACK THEM --- the label above the scale.
##+########################################################

## MPH:

label .fRsliders.fRmph.label \
   -text "$aRtext(labelSCALEmph)" \
   -font fontTEMP_label \
   -width $labelChars \
   -justify left \
   -anchor w \
   -relief flat \
   -padx $PADXpx_label \
   -pady $PADYpx_label \
   -bd 0 \
   -highlightthickness 0 \
   -bg $scaleBKGD

scale .fRsliders.fRmph.scale \
   -orient horizontal \
   -from $MPHmin -to $MPHmax \
   -resolution $resolution \
   -digits $digits \
   -length $scaleLenPx \
   -variable VARmph \
   -font fontTEMP_scale \
   -showvalue true \
   -bd $BDwidthPx_scale \
   -highlightthickness 0 \
   -width $scaleThickPx \
   -bg $scaleBKGD

##   -command {speed_update}

.fRsliders.fRmph.scale set $VARmph

##+#################################################
## Pack the widgets in the frame '.fRsliders.fRmph'.
##+#################################################

pack .fRsliders.fRmph.label \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRsliders.fRmph.scale \
   -side top \
   -anchor nw \
   -fill y \
   -expand 1


##+########################################################
## IN THE 'fRsliders.fRkph' frame -- DEFINE 
## a LABEL widget and a SCALE widget.
## The scale is oriented horizontally.
## THEN PACK THEM --- the label above the scale.
##+########################################################

## KPH:

label .fRsliders.fRkph.label \
   -text "$aRtext(labelSCALEkph)" \
   -font fontTEMP_label \
   -width $labelChars \
   -justify left \
   -anchor w \
   -relief flat \
   -padx $PADXpx_label \
   -pady $PADYpx_label \
   -bd 0 \
   -highlightthickness 0 \
   -bg $scaleBKGD

scale .fRsliders.fRkph.scale \
   -orient horizontal \
   -from $KPHmin -to $KPHmax \
   -resolution $resolution \
   -digits $digits \
   -length $scaleLenPx \
   -variable VARkph \
   -font fontTEMP_scale \
   -showvalue true \
   -bd $BDwidthPx_scale \
   -highlightthickness 0 \
   -width $scaleThickPx \
   -bg $scaleBKGD

##   -command {speed_update}

.fRsliders.fRkph.scale set $VARkph

##+#################################################
## Pack the widgets in the frame '.fRsliders.fRkph'.
##+#################################################

pack .fRsliders.fRkph.label \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRsliders.fRkph.scale \
   -side top \
   -anchor nw \
   -fill y \
   -expand 1


##+########################################################
## IN THE 'fRsliders.fRlpb' frame -- DEFINE 
## a LABEL widget and a SCALE widget.
## The scale is oriented horizontally.
## THEN PACK THEM --- the label above the scale.
##+########################################################

## LPB:

label .fRsliders.fRlpb.label \
   -text "$aRtext(labelSCALElpb)" \
   -font fontTEMP_label \
   -width $labelChars \
   -justify left \
   -anchor w \
   -relief flat \
   -padx $PADXpx_label \
   -pady $PADYpx_label \
   -bd 0 \
   -highlightthickness 0 \
   -bg $scaleBKGD

scale .fRsliders.fRlpb.scale \
   -orient horizontal \
   -from $LPBmin -to $LPBmax \
   -resolution $resolution \
   -digits $digits \
   -length $scaleLenPx \
   -variable VARlpb \
   -font fontTEMP_scale \
   -showvalue true \
   -bd $BDwidthPx_scale \
   -highlightthickness 0 \
   -width $scaleThickPx \
   -bg $scaleBKGD

##   -command {speed_update}

.fRsliders.fRlpb.scale set $VARlpb


##+#################################################
## Pack the widgets in the frame '.fRsliders.fRlpb'.
##+#################################################

pack .fRsliders.fRlpb.label \
   -side top \
   -anchor nw \
   -fill none \
   -expand 0

pack .fRsliders.fRlpb.scale \
   -side top \
   -anchor nw \
   -fill y \
   -expand 1


##+#######################################
## END OF MAIN SECTION TO SETUP THE GUI.
## FRAMES AND WIDGETS ARE DEFINED.
##+#######################################

##+#######################################################################
##+#######################################################################
## BINDINGS section: 3 bindings on button1-release on the sliders (scales).
##+#######################################################################
##+#######################################################################

bind .fRsliders.fRmph.scale  <ButtonRelease-1>  \
   {set TYPEchanged "MPH" ; speed_update 0}

bind .fRsliders.fRkph.scale  <ButtonRelease-1>  \
   {set TYPEchanged "KPH" ; speed_update 0}

bind .fRsliders.fRlpb.scale  <ButtonRelease-1>  \
   {set TYPEchanged "LPB" ; speed_update 0}


##+#####################################################################
##+#####################################################################
## PROCS section:
##    'speed_update'     - called by button1-release bindings
##    'put_vars'               - called by the 'UseIt' button
##    'popup_msgVarWithScroll' - called by the 'Help' button
##+#####################################################################
##+#####################################################################


##+#####################################################################
## proc 'speed_update'
##+##################################################################### 
## PURPOSE: As any of the 3 sliders is changed, 
##          1) set the other 2 sliders, and
##          2) update the text widgets that hold the speed in 3
##             different units. 
##
## CALLED BY:  button1-release on 3 scale widgets:
##               - .fRsliders.fRmph.scale
##               - .fRsliders.fRkph.scale
##               - .fRsliders.fRlpb.scale
##+#####################################################################

proc speed_update {x} {

   global TYPEchanged VARmph VARkph VARlpb \
      widthChars widthFiller KPHmin KPHmax

   ########################################################
   ## Reset the scale values of 2 scales from another scale.
   ########################################################

   if {"$TYPEchanged" == "MPH"} {
      set VARmph [.fRsliders.fRmph.scale  get]
      set VARkph [expr {$VARmph / 0.6214}]
      set VARlpb [expr {0.926 * $VARkph}]
   }

   if {"$TYPEchanged" == "KPH"} {
      set VARkph [.fRsliders.fRkph.scale  get]
      set VARlpb [expr {0.926 * $VARkph}]
      set VARmph [expr {0.6214 * $VARkph}]
   }

   if {"$TYPEchanged" == "LPB"} {
      set VARlpb  [.fRsliders.fRlpb.scale get]
      set VARkph  [expr {$VARlpb / 0.926}]
      set VARmph  [expr {0.6214 * $VARkph}]
   }


   ######################################################
   ## Update the text numbers in the 3 text widgets.
   ######################################################

   #######################################################
   ## Show the current speed in MPH in a small text widget.
   ## Right-justify the number in the text widget.
   #######################################################

   .fRbuttons.txtVARmph delete 1.0 end
   .fRbuttons.txtVARmph insert 1.0 "$widthFiller"
   set insertIDX [expr {$widthChars - [string length "$VARmph"]}]
   .fRbuttons.txtVARmph insert 1.$insertIDX $VARmph

   ## FOR TESTING:
   #   puts "insertIDX: $insertIDX"

   ########################################################
   ## Show the current speed in KPH in a small text widget.
   ## Right-justify the number in the text widget.
   ########################################################

   .fRbuttons.txtVARkph delete 1.0 end
   .fRbuttons.txtVARkph insert 1.0 "$widthFiller"
   set insertIDX [expr {$widthChars - [string length "$VARkph"]}]
   .fRbuttons.txtVARkph insert 1.$insertIDX $VARkph

   ## FOR TESTING:
   #   puts "insertIDX: $insertIDX"

   ########################################################
   ## Show the current speed in LPB in a small text widget.
   ## Right-justify the number in the text widget.
   ########################################################

   .fRbuttons.txtVARlpb delete 1.0 end
   .fRbuttons.txtVARlpb insert 1.0 "$widthFiller"
   set insertIDX [expr {$widthChars - [string length "$VARlpb"]}]
   .fRbuttons.txtVARlpb insert 1.$insertIDX $VARlpb

   ## FOR TESTING:
   #   puts "insertIDX: $insertIDX"


   ######################################################
   ## Reset the color-palette of the window --- between
   ## green (low-speed) and white (high-speed) --- according
   ## to the KPH value between the min and max KPH values.
   ######################################################
   ## We want the white contribution to go from 0 to 255 as
   ## VARkph goes from 0 to KPHmax.
   ## We want the green contribution to go from 255 to 0 as
   ## VARkph goes from 0 to KPHmax.
   ######################################################
   ##COMMENTED, for now.
   ######################################################

   if {0} {

   set Rpal255 [expr {int(255 * $VARkph / $KPHmax)}]
   # set Gpal255 0
   set Gpal255 100
   set Bpal255 [expr {int(255 * ($KPHmax - $VARkph) / $KPHmax)}]

   set hexCOLORpal [format "#%02X%02X%02X" $Rpal255 $Gpal255 $Bpal255]

   tk_setPalette $hexCOLORpal

   }
   ## END OF if {0}

}
## END of proc 'speed_update'


##+#####################################################################
## PROCEDURE -- put_vars
##
## PURPOSE: Puts a string containing the 3 speeds
##          (VARmph, VARkph, VARlpb)
##          to standard output. Then exits this GUI.
##
## Called by:  button .fRbuttons.buttOK
##+#####################################################################

proc put_vars { } {

   global VARmph VARkph VARlpb

   puts "$VARmph $VARkph $VARlpb"

   ## Exit this GUI after returning the speeds to stdout.

   exit

}
## END of proc  'puts_vars'


##+########################################################################
## PROC 'popup_msgVarWithScroll'
##+########################################################################
## PURPOSE: Report help or error conditions to the user.
##
##       We do not use focus,grab,tkwait in this proc,
##       because we use it to show help when the GUI is idle,
##       and we may want the user to be able to keep the Help
##       window open while doing some other things with the GUI
##       such as putting a filename in the filename entry field
##       or clicking on a radiobutton.
##
##       For a similar proc with focus-grab-tkwait added,
##       see the proc 'popup_msgVarWithScroll_wait' in a
##       3DterrainGeneratorExaminer Tk script.
##
## REFERENCE: page 602 of 'Practical Programming in Tcl and Tk',
##            4th edition, by Welch, Jones, Hobbs.
##
## ARGUMENTS: A toplevel frame name (such as .fRhelp or .fRerrmsg)
##            and a variable holding text (many lines, if needed).
##
## CALLED BY: 'help' button
##+########################################################################
## To have more control over the formatting of the message (esp.
## words per line), we use this 'toplevel-text' method, 
## rather than the 'tk_dialog' method -- like on page 574 of the book 
## by Hattie Schroeder & Mike Doyel,'Interactive Web Applications
## with Tcl/Tk', Appendix A "ED, the Tcl Code Editor".
##+########################################################################

proc popup_msgVarWithScroll { toplevName VARtext } {

   ## global fontTEMP_varwidth #; Not needed. 'wish' makes this global.
   ## global env

   # bell
   # bell
  
   #################################################
   ## Set VARwidth & VARheight from $VARtext.
   #################################################
   ## To get VARheight,
   ##    split at '\n' (newlines) and count 'lines'.
   #################################################
 
   set VARlist [ split $VARtext "\n" ]

   ## For testing:
   #  puts "VARlist: $VARlist"

   set VARheight [ llength $VARlist ]

   ## For testing:
   #  puts "VARheight: $VARheight"


   #################################################
   ## To get VARwidth,
   ##    loop through the 'lines' getting length
   ##     of each; save max.
   #################################################

   set VARwidth 0

   #############################################
   ## LOOK AT EACH LINE IN THE LIST.
   #############################################
   foreach line $VARlist {

      #############################################
      ## Get the length of the line.
      #############################################
      set LINEwidth [ string length $line ]

      if { $LINEwidth > $VARwidth } {
         set VARwidth $LINEwidth 
      }

   }
   ## END OF foreach line $VARlist

   ## For testing:
   #   puts "VARwidth: $VARwidth"


   ###############################################################
   ## NOTE: VARwidth works for a fixed-width font used for the
   ##       text widget ... BUT the programmer may need to be
   ##       careful that the contents of VARtext are all
   ##       countable characters by the 'string length' command.
   ###############################################################


   #####################################
   ## SETUP 'TOP LEVEL' HELP WINDOW.
   #####################################

   catch {destroy $toplevName}
   toplevel  $toplevName

   # wm geometry $toplevName 600x400+100+50

   wm geometry $toplevName +100+50

   wm title     $toplevName "Note"
   # wm title   $toplevName "Note to $env(USER)"

   wm iconname  $toplevName "Note"


   #####################################
   ## In the frame '$toplevName' -
   ## DEFINE THE TEXT WIDGET and
   ## its two scrollbars --- and
   ## DEFINE an OK BUTTON widget.
   #####################################

   if {$VARheight > 10} {
      text $toplevName.text \
         -wrap none \
         -font fontTEMP_text \
         -width  $VARwidth \
         -height $VARheight \
         -bg "#f0f0f0" \
         -relief raised \
         -bd 2 \
         -yscrollcommand "$toplevName.scrolly set" \
         -xscrollcommand "$toplevName.scrollx set"

      scrollbar $toplevName.scrolly \
         -orient vertical \
         -command "$toplevName.text yview"

      scrollbar $toplevName.scrollx \
         -orient horizontal \
         -command "$toplevName.text xview"
   } else {
      text $toplevName.text \
         -wrap none \
         -font fontTEMP_varwidth \
         -width  $VARwidth \
         -height $VARheight \
         -bg "#f0f0f0" \
         -relief raised \
         -bd 2 
   }

   button $toplevName.butt \
      -text "OK" \
      -font fontTEMP_label  \
      -command  "destroy $toplevName"

   ###############################################
   ## PACK *ALL* the widgets in frame '$toplevName'.
   ###############################################

   ## Pack the bottom button BEFORE the
   ## bottom x-scrollbar widget,

   pack  $toplevName.butt \
      -side bottom \
      -anchor center \
      -fill none \
      -expand 0


   if {$VARheight > 10} {
      ## Pack the scrollbars BEFORE the text widget,
      ## so that the text does not monopolize the space.

      pack $toplevName.scrolly \
         -side right \
         -anchor center \
         -fill y \
         -expand 0

      ## DO NOT USE '-expand 1' HERE on the Y-scrollbar.
      ## THAT ALLOWS Y-SCROLLBAR TO EXPAND AND PUTS
      ## BLANK SPACE BETWEEN Y-SCROLLBAR & THE TEXT AREA.
                
      pack $toplevName.scrollx \
         -side bottom \
         -anchor center \
         -fill x  \
         -expand 0

      ## DO NOT USE '-expand 1' HERE on the X-scrollbar.
      ## THAT KEEPS THE TEXT AREA FROM EXPANDING.

      pack $toplevName.text \
         -side top \
         -anchor center \
         -fill both \
         -expand 1
   } else {
      pack $toplevName.text \
         -side top \
         -anchor center \
         -fill both \
         -expand 1
   }


   #####################################
   ## LOAD MSG INTO TEXT WIDGET.
   #####################################

   ##  $toplevName.text delete 1.0 end
 
   $toplevName.text insert end $VARtext
   
   $toplevName.text configure -state disabled
  
}
## END OF PROC 'popup_msgVarWithScroll'


##+###############################################
## END OF PROCS SECTION.
##+###############################################
## Setting of HELPtext variable follows.
##+###############################################

set HELPtext "\
*** HELP for this tkSpeedGun-Convert-Select GUI ****

This TkGUI script provides a GUI for showing speeds
between zero and 2,000 kilometers-per-hour (this max
is easy to change) --- in three different units:

      - mph (miles-per-hour)
      - kph (kilometers-per-hour)
      - LPB (Lightyears-Per-Billion-years).


*******************************
SOME NOTEWORTHY SPEEDS (in kph):

speed of light in a vacuum = 1.07925285 billion kph

                           = 1,079,252,850 kph

speed of sound in air at sea level = 1,225.044 kph

                                   = 343.2 meters/second

(And sound travels about 4.3 times faster in water,
 and nearly 15 times faster in iron.)

terminal velocity of a skydiver  = about 200 kph

speed limit of 80 mph            =  128.7 kph

max (burst) speed of a cheetah   = about 112 kph

speed limit of 60 mph            =  96.6 kph

max speed of a horse             = about 88 kph

human walking speed of 4 mph     =  6.4 kph


****************************************
CONVERSION FACTORS BETWEEN 'LPB' and KPH:

1 light-year = 9.4605284 × 10^12 kilometers
             = 9.46 trillion kilometers

1 billion years = ? hours
                = 10^9 years * 365 days/year * 24 hours/day
                = 8.760 x 10^12 hours
                = 8.76 trillion hours

So

1 light-year/billion-years (LPB) =  1.0799 kph

or

1 kph =  0.9260 LPB

So multiply kph by 0.926 to get LPB.


****************************
THE CONVERSION FUNCTIONALITY:

Three different (but corresponding) speeds are shown (and
selected for conversion) via 3 'slider-buttons' on 3 Tk
'scale' widgets. 

These 3 different (corresponding) speed numbers are also shown
in 3 'text' widgets, several characters wide --- from which a
user can copy-and-paste the numbers from this GUI window to
some other window. 

For any 'slider' change, this GUI script IMMEDIATELY updates
the location of the other 2 'SLIDERS' --- when you RELEASE
the slider-button that you are moving.

The 3 TEXT widgets, showing the speed in the 3 different
units, are also IMMEDIATELY updated whenever any one of the 3
scale widget 'sliders' are changed.

***************************
FINE CONTROL OF THE SLIDERS:

Most people know that you can drag the sliders by clicking
on the 'slider button' with mouse-button1 and dragging the
slider button. This is a rather coarse way of moving the
slider button.

It is not so obvious that the Tk scale widget also allows
you to move the 'slider button' by clicking in the 'trough'
on EITHER SIDE of the slider button. By repeated clicking
in the trough, the slider can be advanced one scale-resolution
unit per click.

Furthermore, one can RAPIDLY move the slider button ONE
RESOLUTION UNIT per 'auto-click' by clicking in the trough
and HOLDING down the mouse button. The slider moves
one resolution unit repeatedly UNTIL the mouse button
is RELEASED.

**************************
THE SELECTOR FUNCTIONALITY:

By clicking on the 'UseIt' button on the GUI, this script
returns a string containing the current speed (in the
3 different units) to a calling script/application.

When using this script in another script/program,
this script will accept a speed (in kph) as an
argument --- which is used to initialize the
      - setting of the 3 'sliders', and
      - the numbers shown in the 3 small text widgets.

*************************
SOME USES of this utility:

   1) Useful for helping math-science students get a visual
      'feel' for the relation between mph, kph, and LPB.

   2) Also could be useful for a person wanting to convert
      from one unit to another --- for example, a tennis serve
      in miles-per-hour to kilometers-per-hour --- or vice versa.

   3) IN A SHELL SCRIPT or ANOTHER TK SCRIPT, this Tk script can
      ACT AS AN SPEED SELECTOR by passing the current speed
      (in the 3 different units) to stdout, when the 'UseIt' button
      is clicked.
            Example output string:  60.0  96.6  89.5

                                    (mph , kph , LPB)

Note:
The user can set up this script as an icon on a desktop so that
the GUI can be started up by a click (or two) on the icon ---
say, while you are watching a tennis tournament.
"

##+###############################################
## ADDITONAL GUI INITIALIZATION (if any) FOLLOWS.
##+###############################################

## See the setting of intial speeds --- from an initial KPH
## --- at the 'argv' section near the top of this code ---
## near the frame definitions. Note: You can pass an initial
## KPH value to this script.

# update

set TYPEchanged "kph"
speed_update 0


SOME POTENTIAL ENHANCEMENTS:

In looking up some sample speeds to include in the 'HELPtext' variable, I realized that often high speeds (like the speed of sound) are reported in meters/second as an alternative to kilometers/hour.

So I could have made the 3rd scale 'MPS' instead of 'LPB'. In fact, there are other speed units that I might like to display, like Earth-circumferences Per Week (EPW) or Football-fields Per Minute (FPM).

So, I could add a row of RADIOBUTTONS to the GUI, and allow the user to choose --- from quite a few weird and not-so-weird options --- what units will be used for the 3rd scale.

___

Furthermore, I probably should add a 'ColorMe' button to this GUI --- like I did for a font-selector GUI whose code is at YAFSG - Yet Another Font Selector GUI and a tkPointerSettings GUI whose code I contributed at tkPointerSettings - a Tk GUI 'wrapper' for the 'xinput' command on this wiki.

With a 'ColorMe' button, the user could easily use a color selector, like the one at A non-obfuscated color selector GUI, to change the color of this tkSpeedGun-Convert-Select GUI.

Instead of supplying a 'ColorMe' button to do that, I simply point out that the user can change the RGB values for the 'tk_setPalette' statement near the top of this code.

IN CONCLUSION

The final weekend of the U.S. Open tennis tournament is this weekend. So I have finished this utility just in time to give it a workout as Gasquet, Nadal, Wawrinka, and Djokovic battle it out.

Thanks again to Tcl-Tk --- that is, to Ousterhout and the maintainers of the 'wish' interpreter.