FE 'tkGooie' Utilities

---

'MATHtools' group

---

tkBMIcalc
Body Mass Index calculator

(where height may be entered in inches,
centimeters, or meters --- and weight
may be entered in pounds or kilograms)

(FE = Freedom Environment)

FE Home Page > FE Downloads Page > FE 'tkGooies' Description Page >

FE 'tkGooies' 'MATHtools' Page > This Page

INTRODUCTION to 'tkBMIcalc'

In 2017, I ran across a couple of short articles on BMI (Body Mass Index) which included instructions on how to do the simple calculation of BMI from a person's height and weight --- in inches and pounds.

    The formula for calculating the BMI is given by

        BMI = (704.5 * POUNDS) / (INCHES * INCHES)
    

    One article gave the coefficient as 703, the other gave 704.5. I decided to use 704.5.

I decided that this would make a nice little Tk GUI script --- where I could include the option of presenting some dietary advice depending on the outcome of the BMI calculation.

Furthermore, I could allow the GUI to pass the output (BMI index) and the inputs (height and weight) from the script to 'stdout'. This would allow this script to be called from other 'apps' --- such as shell scripts or other Tcl-Tk scripts --- to get those numbers for use in the calling 'app'.

I decided to keep the GUI rather compact by using two 'entry' widgets for entering the height and weight --- rather than using a couple of 'scale' (slider-bar) widgets.

    I may someday provide an alternate GUI using 'scale' widgets instead of 'entry' widgets. I have plenty of 'converter' and 'selector' code to use as a starting point,

    An example of a 'scale' widget utility:
    In 2016, I wrote the tkDegreesMinSecConvertSelect utility to convert between decimal-degrees and degrees-minutes-seconds. I could use some of the code from that script to (relatively) quickly make a 'scale' widget version of the BMI calculator.

For the 'entry'-widgets GUI, I need to use an 'edit_inputs' proc to check on numeric values that a user puts in the height and weight 'entry' widgets. For that, I could modify some numeric-edit procs I used in Tk GUI scripts such as a tkFetchOSMtiles utility in the 'MAPtools' group, that I wrote in 2016.

    One of the advantages of using 'scale' widgets (or 'spinboxes' or some equivalent) instead of 'entry' widgets is there is no need for an 'edit_inputs' proc. The values returned by 'scale' widgets are always numeric. There is no chance the user will enter 'garbage' characters.


THE GUI DESIGN

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---->     would indicate a horizontal Tk 'scale' widget (if any).
  UNDERSCORES     would indicate a Tk 'entry' widget (if any).
  CAPITAL-O       would indicates a Tk 'radiobutton' widget (if any).
  CAPITAL-X       would indicates a Tk 'checkbutton' widget (if any).

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

 FRAMEnames
 VVVVVVVVVV
           
             ---------------------------------------------------------------------------
             tkBMIcalc ... calculate Body Mass Index
             [window title]
             ---------------------------------------------------------------------------
             
.fRbuttons   {UseIt} {Exit} {Help} {Calc}
             
.fRheight    Height: ______  O centimeters    O inches   O meters
             
.fRweight    Weight: ______  O kilograms   O pounds
           
.fRbmi       BMI: [text widget goes here]
           
.fRadvice    Advice:
             [multi-line text widget goes here]


---

GUI components:

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

   -  4 button widgets
   -  4 label widgets
   -  2 entry widgets
   -  5 radiobutton widgets (in 2 groups)
   -  2 text widgets
   -  0 checkbutton widgets
   -  0 scale widgets
   -  0 listbox widgets


A SCREENSHOT

I set to work converting the code from a couple of 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 height units-of-measure (radiobuttons) are set to 'inches' and the weight units-of-measure (radiobuttons) are set to 'pounds'.

The height and weight values are set to relatively healthy values --- 70 inches (5 feet 10 inches) and 170 pounds.

    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 change the height and/or weight entries (and the radiobutton settings if one wishes to use metric units), and click on the 'Calc' button to see the new BMI value.

---

If the user chooses metric units for height, the value in the height entry field is converted to inches when the 'Calc' button is pressed.

If the user chooses metric units for weight, the value in the weight entry field is converted to pounds when the 'Calc' button is pressed.

Then the formula presented near the top of this page is used to perform the BMI calculation.

---

I put the BMI calculated value and the 'advice' in 'text' widgets rather than 'label' widgets so that the user can copy-and-paste that text from this GUI window to another window on the user's desktop.

---

The message ('advice') area on the GUI gives the user advice on what to do depending on the range in which the BMI value falls.

The standard advice is

  • BMI less than 25.0 is a healthy value
  • BMI between 25 and 30 indicates the person is nearing obesity (over-weight)
  • BMI greater than 30 indicates the person is obese

The following two images show the GUI's advice for the latter two cases.

On leaving the height set at 70 inches and boosting the weight to 190 pounds, a click on the 'Calc' button yielded the following GUI.

---

On leaving the height set at 70 inches and boosting the weight to 210 pounds, a click on the 'Calc' button yielded the following GUI.

---

For the 'Selector' function of this utility:

If this calculator-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 BMI index and the height and weight (in inches and pounds) to 'stdout' --- so that the calling script can use the calculated data and/or the input data.

An example of how the 'stdout' text can be captured in a script variable is shown in comments near the top of some of the 'tkGooies' scripts --- such as the script for the tkDegreesMinSecConvertSelect utility.


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 near the bottom of the script.


DESCRIPTION OF THE CODE

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

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 fix the y-size of the GUI window, but allow the x-size to vary --- by using the statement

   wm resizable . 1 0

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

    (I do not foresee using this capability. This just demonstrates a combination of window and widget expansion options when this GUI window is resized.)

If you think the GUI window will be usable in all cases with a fixed size, you could use the statement

   wm resizable . 0 0

to keep 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: 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.

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

  'calc_bmi'                - called by the 'Calc' button.

  'edit_inputs'             - called by the 'calc_bmi' proc.

  'decimal_check'           - called by the 'edit_inputs' proc.

  'put_vars'                - called by the 'UseIt' button.

  'popup_msgVarWithScroll'  - called by 'Help' button to show 'HELPtext' var and
                              to present error messages from the 'edit_inputs' proc.


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 'Brangelina' (Brad Pitt and Angelina Jolie) and other 'supercouples'.


THE CODE

Here is a link to CODE for the script 'tkBMIcalc.tk'.

With your web browser, you can 'right-click' on this link --- and in the menu that pops up, select an item 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.


Here is a 2017 September image of the 'tkGooies' 'MATHtools' toolchest --- showing the new 'tkBMIcalc' drawer of the toolchest.


SOME POTENTIAL ENHANCEMENTS:

I mentioned above the option of changing the 'tkBMIcalc' GUI to use 'scale' widgets (or 'spinbox' widgets --- or the equivalent done with an 'entry' widget and a couple of tiny 'button' widgets) --- instead of using 'entry' widgets for the two numeric values.

The only other potential enhancement that comes to my mind at this point:

  • Add more advice for extremely large BMI values:
    At large BMI values --- say, larger than 40 and larger than 50 --- it might be advisable to add even more advice. For example, advice concerning getting a blood test for level of tri-glycerides and information on what various triglyceride levels suggest.

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


IN CONCLUSION

As I have said on quite a few 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.

Bottom of the page for tkBMIcalc --- a utility in the FE 'tkGooies' system, in the 'MATHtools' 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. >
< Go to FE 'tkGooies' 'MATHtools' Page >
< Go to FE 'tkGooies' Description page >
< Go to FE Home page. >

This FE web page was created 2017 Aug 22.
Page was changed 2017 Sep 24. (Added an image of the 'MATHtools' toolchest.)

If I ever post a copy of this code on the Tcler's Wiki site (wiki.tcl.tk) ---
as a backup and alternative to this page, I plan to put a link to that page here.