FE 'tkGooie' Utilities

SELECTORtools' group

tkDistance ConvertSelect

(where distances may be
in meters, yards, inches,
feet, miles, kilometers,
lightyears, nanometers,
etc. --- huge or tiny)
(FE = Freedom Environment)

GUI for conversion between
distances for various
'units of measure'
allowing for distances
at various extremes
sub-atomic to

Large, hi-def images
are below.

FE Home Page > FE Downloads Page >

FE 'tkGooies' Description Page >

FE 'tkGooies' 'SELECTORtools' Page >

tkGooie code Page

INTRODUCTION to Tcl-Tk script

I was planning (in 2016-2017) to make some Tcl-Tk GUI's for converting various kinds of quantities (distances, areas, volumes, weights, densities, velocities, etc.) from one specified unit-of-measure to another.

One of my main goals in creating these 'convert' GUI's is to support conversions over a very wide range of values.

For example, for distances, I wanted to be able to support converting distances that may be astronomically huge (for example, distances up to the diameter of the visible universe, in light-years or whatever) or distances that may be microscopically small (for example, distances at the sub-atomic level, in nanometers or whatever).

To do this, I wanted to allow the user to specify the 'convert-from' distance in 'scientific notation' --- a decimal coefficient and a base-10 exponent (an integer).

And the 'convert-to' distance was also to be expressed in 'scientific notation'.

This is in contrast to the


utility I wrote in 2013, which was intended to convert between kilometers-per-hour and miles-per-hour --- with the intention of handling a restricted range of velocities --- like those encountered by a tennis ball in a tennis match.

That utility had the luxury of knowing that the velocities would be numbers in the range of zero to about 300 (or 1000 or thereabout) as a maximum --- in kilometers-per-hour or miles-per-hour.

Instead of dealing with a range of values FROM about 1 TO about 10 to the third, I wanted to deal with values in a range FROM about 10 to the minus 80 TO about 10 to the plus 80.

Since I have plenty of 'converter-selector' code to use as a starting point, I decided to code this 'converter' utility --- and allow it to be a 'selector' utility also, in the sense that a specified distance (in the specified units) could be written to 'stdout' --- by a click on a button of the GUI.

An example of a previously written 'convert-and-select' utility:

I have written


utility to convert between decimal-degrees and degrees-minutes-seconds.

But that utility, like the 'tkSpeedGun' utility, used 'scale' widgets (slider-bars) instead of entry fields for a coefficient and exponent.

For this GUI, I would need to use an 'edit_inputs' proc to check on decimal and integer values that a user puts in 'entry' widgets.

For that, I could modify some numeric-edit procs I used in Tk GUI scripts such as a


utility in the 'MAPtools' group, that I wrote in 2016.


Following a Tk GUI design procedure that I started using around 2015, I laid out a 'text-sketch' of a proposed layout for the GUI.

In the below sketch of the GUI:

  SQUARE BRACKETS indicate a comment (not to be placed on the GUI).
  BRACES          indicate a Tk 'button' widget.
  A COLON         indicates that the text before the colon is on a 'label' widget.

  <----O---->     indicates a horizontal Tk 'scale' widget (if any).
  UNDERSCORES     indicate a Tk 'entry' widget (if any).
  CAPITAL-O       indicates a Tk 'radiobutton' widget (if any).
  CAPITAL-X       indicates a Tk 'checkbutton' widget (if any).

  The options available to the user are indicated by
  the following 'sketch' of the GUI:

                    tkDistance - Converter/Selector
                    [window title]

 .fRbuttons         {UseIt} {Cancel} {Help} {Calc 2from1} {Calc 1from2}

 .fRmsg             [.... Messages to user are display in a label here ...............................]

 .fRleft                                                             .fRright
 [The sub-frames below are                                           [The scrollable listbox below
  in this '.fRleft' frame.]                                           is in this '.fRright' frame.]

 .fRleft.fRunits1   Units1:[selected units displayed here] O units1  | inches                  |
                                        [in a text widget]           | feet                    |
 .fRleft.fRvalues1  Coefficient: ___________  Exponent: ___          | meters                  |
                                                                     | yards                   |
 .fRleft.fRunits2   Units2:[selected units displayed here] O units2  | ...                     |
                                        [in a text widget]           | kilometers              |
 .fRleft.fRvalues2  Coefficient: ____________ Exponent: ___          | miles                   |
                                                                     |                         |
                                                                     | light-years             |
                                                                     | ...                     |
                                                                     | nanometers              |
                                                                     | etc.                    |

GUI components:

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

  • 5 button widgets
  • 7 label widgets
  • 2 text widgets
  • 4 entry widgets
  • 1 listbox widget
  • 2 radiobutton widgets
    (1 pair on 2 separate 'units' lines of the GUI)
  • 0 checkbutton widgets
  • 0 scale widgets
  • 0 canvas widgets


So I set to work converting the code from other converter/selector GUI's to this proposed GUI, and I ended up with the GUI seen in the following image.

This is the GUI as it appears on startup --- the 'Units2' coefficient entry widget is empty and the 'Units2' exponent entry widget is also empty.

'Units1' is initialized to 'meters' and 'Units2' is initialized to 'yards'.

And the 'Units1' coefficient is initialized to 100.0 and the 'Units1' exponent is initialized to zero.

    These initial values can be easily changed by changing some 'set' statements at the bottom of the script, in the 'Additional GUI Initialization' section.

At this point, the user can simply click on the 'Calc 2from1' button to have the conversion of 100.0 meters to yards performed --- with the result showing in the 'Units2' coefficient and exponent entry widgets.


Note that '-' and '+' buttons appear on either side of the 2 exponent entry fields.

After implementing the GUI and trying it out, I found that it would be advisable to allow the user to adjust the 'scientific notation' to a combination of coefficient and exponent that would be most 'meaningful' to the user.

So the four '+' and '-' buttons were added to the GUI --- along with proc's to adjust a coefficient and exponent pair for each click on one of the buttons.

Each click adjusts the exponent up or down one unit while moving the decimal point appropriately in the coefficient.


The message ('advice') area on the GUI lets the user know that the unit-of-measure for 'Units1' and 'Units2' can be changed by using the 2 radiobutton widgets on the GUI --- in conjunction with the listbox.

After clicking on one of the 2 radiobuttons, the user selects a unit-of-measure by a click on a line of the listbox.

After setting 'Units1' to 'miles' and 'Units2' to 'kilometers' and setting miles to 1, the 'Calc 2from1' button was clicked to yield the image seen in the following screenshot.

The 'Selector' function of this utility:

If this converter-selector utility is embedded in another 'app', such as a shell script or another Tcl-Tk script, the 'UseIt' button can be clicked to send the two sets of units-coefficient-exponent to 'stdout' --- so that the calling script can use the entered data and/or the calculated data.

An example of how the 'stdout' text can be captured in a script variable is shown in comments near the top of the script.

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

A proc named 'popup_msgVarWithScroll' presents the Help text in a popup window.

Anyone who implements this script can easily change the Help text, which is defined in a 'set' statement for variable 'HELPtext' near the bottom of the script.


Below, I provide the Tk script code for this 'tkDistanceConvertSelect' 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,

  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 from other scripts (code re-use).

I call your attention to step-zero.

One new thing that I started doing around 2014 is using a text-array variable --- 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.

All the 'set' statements for the text array, 'aRtext', are in one contiguous section toward the top of the code.

Experimenting with the GUI
--- its behavior

As in all my scripts that use the 'pack' geometry manager (which is all of my 100-plus Tk 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, I have chosen to allow the window to be re-sized --- so that the listbox can be re-sized easily by 'pulling' on the lower-right corner of the GUI.

I also used '-fill x' and '-expand 1' for the two coefficient entry fields so that those fields will expand if the user x-expands the GUI window.

However, one could un-comment the statement

wm   resizable   .   0   0

to make the window fixed at its initial size.

With 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.


Additional experimentation with the GUI
--- its appearance:

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

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.

Below is a quick view of how each of the procs are 'triggered'.

   'listbox_select_units'    - called by a button1-release binding on the listbox widget.

   'distance_update'         - called by the two 'Calc' buttons

   'adjust_values1'          - called by the '+' and '-' buttons for exponent1
   'adjust_values2'          - called by the '+' and '-' buttons for exponent2
   'edit_inputs'             - called by the 'distance_update' proc
   'decimal_check'           - called by the 'edit_inputs' proc

   'put_vars'                - called by the 'UseIt' button

   'advise_user'             - called in the 'Additional GUI Initialization' section
                               at the bottom of this script.  Could also be called by
                               some procs such as 'distance_update'.

   'popup_msgVarWithScroll'  - called by the 'Help' button and by the 'edit_inputs' proc.

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 other equivalents) --- to surf the web looking for the latest news about the 'Real Housewives of [some city in the USA goes here]' TV shows.

    The 'Real' descriptor seems unreal --- a misnomer.

    These ladies are about as 'unreal' or 're-constructed' as it gets.)

The Tcl-Tk script CODE

Here is a link to CODE for the script


With your web browser, you can 'right-click' on this link --- and in the menu that pops up, select an option like

' Save Link Target As ... '

--- to save this file to your local computer.

Then you can rename the file to remove the '.txt' suffix.

Make sure that you have execute permission set on the file --- in order to execute the script.


Several possible enhancements come to mind:

  • Format of the decimal (coefficient) output:

    Currently, the 'precision' (number of decimal places) displayed in the output is hard-coded in a variable named 'FORMATforCOEF' near the bottom of the script, in the 'Additonal GUI Initialization' section.

    A widget (such as a 'scale' widget --- or an 'entry' widget, to be more compact) could be added to the GUI to allow for specifying the number of decimal places to be displayed in a computed coefficient.

  • More distance units:

    Some other distance units could be added, such as:

    • nautical-miles
    • leagues
    • fathoms

    Each new distance unit added would require adding 3 new setting statements near the bottom of the script, in the 'Additonal GUI Initialization' section.

    Example 'set' statements follow.

   .fRright.listbox insert end "fathoms"
   set aRcoef(fathoms/meter) [a decimal number goes here]
   set aRexp(fathoms/meter) [an integer goes here]

  • Change the underlying conversion method:

    I have used the 'aRcoef' and 'aRexp' arrays to hold conversion factors based on using 'meters' for a common unit-of-measure to which all other units-of-measure are 'tied'.

    There are precision errors that are revealed in this approach.

    For example, converting 1 'mile' to 'feet' may yield a value like 5279.99993402 instead of 5280.

    Various techniques might be used to eliminate 'hiccups' like this.

    Since this utility does essentially all of what I had hoped that it would do, I prefer to go ahead and release the code rather than spending more time trying to deal with precision and round-off issues.

Since I have not used this script for a large number of tests over widely varying distance magnitudes, there are probably some other enhancements that may be suggested by futher usage.

If I ever find that I am using this utility and I find that any of the features above are highly advisable to add, then I may return to this script to provide that feature.

Some additional ideas to include in this Tk GUI may be inspired by various on-line distance/length calculators on the internet, such as


As I have said on other Tcl-Tk code-donation pages on this site ...

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 2017 Aug 25:

After implementing a


and a


utility, I learned a few things that I have used to improve the initial release of this 'tkDistance ConvertSelect' utility.

The main changes are

  • changed a <ButtonPress-1> event to a <KeyPress> event in the BINDINGS section of the code

  • implemented some coefficient 'clearing' logic in the 'listbox_select_units' proc

  • added 'Clear2' and 'Clear1' buttons to the GUI

  • put the units-of-measure in alphabetical order, in the listbox

  • added a few units-of-measure to the listbox

  • made corresponding changes to the comments in the code.

I replaced the code in the link above with the new code.

Bottom of this web page for
presenting Tcl-Tk code for
--- a utility in the FE 'tkGooies' system,
in the 'SELECTOR/CONVERTER-tools' 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:

This FE web page was created 2017 Aug 22.

Page was changed 2017 Aug 25.
(See 'UPDATE 2017 Aug 25'.)

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

Page was changed 2019 Jul 09.
(Specified image widths in percents to size the images according to width of the browser window. Also added some web links.)

This code and description has NOT been posted on a Tcler's Wiki page --- at wiki.tcl-lang.org --- formerly wiki.tcl.tk.

If I ever do so, as a backup and alternative to this page, I plan to add a link to that Wiki page here.