FE 'tkGooie' Utilities

'IMAGEcreators - Shaded3D' group

Tk GUI to draw
a 2-color

with color-shaded
3D-like edges

(FE = Freedom Environment)

FE color-shaded, 3D-like,
'tkGooie' interface.

FE Home Page > FE Downloads Page >

FE 'tkGooies' Description Page >

FE 'tkGooies' 'IMAGEcreatorsShaded3D' Page >

This 'draw-2color-XorYgradient_RECTANGLE-BUTTON colorShaded3D Page

Tcl-Tk Code to
'Draw a 2-color-XorY-gradient RECTANGLE/BUTTON
with color-shaded, 3D-like edges'

I am interested in making nice images for 'toolchest' and 'drawer' backgrounds (and other GUI embellishments), as I have indicated at wiki.tcl.tk (and on this freedomenv.com site) --- as indicated by


On the page that presents code for a GUI for Drawing 'Super-ellipses', with nice shaded edges on this site (and at wiki.tcl.tk), I presented code for a GUI that uses 'create image' on a Tk canvas widget, along with 'put' commands, to implement the drawing of a 'super-ellipse' with nice 'edge shading' --- shading from a user-specified color for the super-ellipse to a user-specified color for a surrounding background.

    (Thanks to 'ulis', deceased in 2008, for his donated script that led to that much-enhanced script. R.I.P.)

The shading technique was based on using a 'color-metric' scalar parameter given by the equation for the super-ellipse:

v = |x/a|^n + |y/b|^n

I began thinking about this shading technique in conjunction with the color gradient rectangles ('buttons') that were made by using canvas 'create line'.

See, for example, code of any of at least five versions of a color-gradient-button-maker GUI.

The code in those Tk scripts makes 'flat' (not 3D-like) buttons with a 2-color gradient across the button.

I realized that I should be able to make rectangular buttons with nice shading at the edges by using a 'create image' technique, instead of 'create line'.

A 'color-metric' for rectangular 'buttons'

I just needed a 'color-metric' for the rectangle, similar to the one above for the super-ellipse.

I realized that I could use the 'max' function to make a suitable metric, as follows.

Let us say that x,y coordinates in the rectangle are measured from the center of the rectangle. I.e. the origin (0,0) is the center of the rectangle.

Let 'xhalf' denote the x-distance from the center of the rectangle to the left and right edges, and let 'yhalf' denote the y-distance from the center of the rectangle to the top and bottom edges.

Then we can define a suitable metric by means of the expression:

v = max(abs(x/xhalf), abs(y/yhalf))

where x and y are measured from an 'origin' in the middle of the rectangle, and xhalf and yhalf represent the half-width and half-height of the rectangle.

Note that for a point x,y in the interior of the rectangle, both abs(x/xhalf) and abs(y/yhalf) are less than one --- and the metric is zero at the origin (x,y)=(0,0).

Furthermore, on the edges of the rectangle, either abs(x/xhalf) or abs(y/yhalf) is equal to 1.0 --- so the metric is 1.0 on the edges of the rectangle.

And for (x,y) points outside the rectangle, v is greater than 1.0.

Assembling the pieces

Now it was a matter of putting the pieces together. I decided that:

I would merge code from GUI for Drawing 'Super-ellipses', with nice shaded edges and code from one of the several GUI's to make a 'flat' color-gradient-button --- and I would change the 'color-metric' being used.

In the process of merging the two scripts, I decided I would preserve the capability of the 2nd script that allows the user to specify 2 colors to use for a color gradient across the button --- in either the x or the y directions.

So I would use 3 color buttons --- for gradient-color1, gradient-color2, and a background-color.

And I would keep the 2 radiobuttons of the 2nd script for specifying the x or y gradient-direction.

Furthermore, I would add a checkbutton widget so that I could turn the 'edge-shading' on or off.

After a lot of work in trying to minimize the number of 'put' commands issued and in trying lists-versus-strings, I ended up with the following GUI --- and the code presented below.

Note that I provided a scale widget on the GUI to allow the user to control an exponent that is used to control the 'extent'-or-'intensity' of the shading at the edges of the rectangle.

I also provided a display of 'elapsed time' for each redraw --- by using the Tcl 'clock milliseconds' command.

When I developed the script that I posted at wiki.tcl.tk, and later on this site, at GUI for Drawing 'Super-ellipses', with nice shaded edges, I learned my lesson about needing to use braces with 'expr' statements --- for much better execution times.

    (Brent Welch et. al. point this out before page 8 in the 4th edition of 'Practical Programming in Tcl and Tk' --- although they do not use this advice in many 'expr' examples later in the book.)

It made a huge difference, so, in this script (and in all my Tk scripts henceforth), I consistently use braces with ALL 'expr' commands --- in particular, in the compute-intensive 'ReDraw' proc and in the procs that are called by 'ReDraw'.


Note that I have supplied 3 buttons on the GUI with which to set the 2 'gradient' colors and the 'background' color.

Those 3 buttons call on a color-selector-GUI script to set those colors.

You can make that color-selector script by cutting-and-pasting the code from the page that offers a non-obfuscated color selector GUI on this site.


Below is the code that produced this GUI.

There are comments at the top of the code, in a section titled 'USING THE GENERATED IMAGE', that describe how one could make use of images produced by this GUI.

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.
  1b) Pack   ALL frames and sub-frames.

  2) Define & pack all widgets in the frames.

  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 makes it easy for me to find code sections --- while generating and testing this script, and when looking for code snippets to include in other scripts (code re-use).

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', and '-expand' --- on all the 'pack' commands for the frames and widgets.

I think I have found a good setting of the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets of this GUI. In particular ...

The 'canvas' widget expands/contracts appropriately when the window size is changed --- and button and label widgets stay fixed in size and relative-location as the window size is changed.

If anyone wants to change the way the GUI configures itself as the main window size is changed, they can experiment with the '-side', '-anchor', '-fill', and '-expand' parameters on the 'pack' commands for the various widgets --- to get the widget behavior that they want.

For example, you may want the scale widget to x-expand, rather than stay fixed in length, whenever the window is expanded in the x-direction.


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

Furthermore, there are variables used to set geometry parameters of widgets --- parameters such as border-widths and padding. And you could change the '-relief' values for frames and widgets. Feel free to experiment with those 'appearance' parameters as well.

Some features of the code

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

See the top of the 'PROCS' section for a list of the procs used in this Tk script.

See comments in the procs for details on the purpose of each proc and for details on the methods by which each proc was implemented.

Below is a quick overview of the procs --- to give an idea of the 'guts' of this utility:

  - ReDraw                - called by button1-release on the 2 gradient-direction
                            radiobutton widgets, by button1-release on the shading
                            checkbox widget, and by the set-color procs below.
                            Also to be called when the window (and thus the canvas
                            and the image on that canvas) is resized.

  - ReDraw_ydir           - called by the ReDraw proc.

  - ReDraw_xdir           - called by the ReDraw proc.

  - set_gradient_color1   - called by the color1 button

  - set_gradient_color2   - called by the color2 button

  - set_background_color  - called by the background color button

Draw time considerations

The most complex code is in the 'ReDraw_ydir' and 'ReDraw_xdir' routines.

I have indicated in comments at the top of the code and in comments in those procs that I attempted to minimize the number of 'put' commands to draw an image by using 'horizontal-scanlines' (of hex-colors) in proc 'ReDraw_ydir' and 'vertical-scanlines' in proc 'ReDraw_xdir'.

Unfortunately, I was unable to get the 'vertical-scanline' technique to work in the 'ReDraw_xdir' proc. So I ended up using a 'put' command for each pixel within the rectangle.

The draw-time for the x-direction then turned out to be about twice the time as for the y-direction (where I was able to 'put' an entire horizontal scanline at a time).

For the default initial size of the GUI, x-gradient draw-times were about 1.7 secs --- versus about 0.85 sec for the y-gradient draw-times.

    In the initial implementation of this utility, the image size is determined by the GUI window size.

    In other words, the user can resize the GUI window, in which case the Tk 'canvas' is resized, and the image size is set from the canvas size.

    The draw-times were more than 4 seconds when I increased the GUI window size to fill the monitor screen.

See the 'Enhancements' section below for some other comments on draw time --- and controlling image size.

Comments in the Code

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

Without the comments --- especially in the 'ReDraw_ydir' and 'ReDraw_xdir' procs, the code might look even more cryptic than it already is.

Without the comments, potential young Tcler's might be tempted to return to their iPhones and iPads and iPods --- to watch America's/Japan's/Germany's/Uzbekistan's Funniest Home Videos.

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

Control of the edge shading

By putting a scale widget on the GUI for adjusting a 'pow' (power) exponent to change the 'extensity' (extent and/or intensity) of the shading at the edge of the rectangle, it was easy to find that low powers (like 1 or 4 or even 6) gave really washed-out edges to the rectangle.

It surprised me that it took a rather high value (like 12) to get a good-looking edge.

That means that v^12 and (1 - v^12) gave better edges when blending the rectangle color at x,y and the background color --- better than using the weighted average of the 2 colors using v and (1-v).


It appears that one could make some quite high-quality 'button', 'bullet', icon-background, and logo-background images with this utility.

And I have the option of enhancing the Tk script on this page, to provide a few more capabilities to this 'button' generator.

There are several items that I can foresee wanting to implement in the future to make this Tk script a little bit better:

  • Add a 'Help' button
    In the help text I would add how-to-use information --- such as:
    The user can control the size of the generated image by resizing the entire GUI window. That causes the Tk 'canvas' to resize, and the size of the image to generate is determined from the canvas size.

  • Add 2 widgets by which to set ImgWidth and ImgHeight (pixels) precisely
    This would allow the user to set the generated image size precisely.

  • Improve the draw-speed, by a factor of 2 or more
    As indicated above, we can improve the draw-speed significantly by saving up the hex-colors for pixels in a Tcl 'list' and then apply those colors to the image 'structure' one horizontal scan-line at a time.

    In fact, there is at least one small demo script on wiki.tcl.tk in which a Tcl-er has saved up all the hex-colors for an entire image (in a list of horizontal scan-line lists --- a list of lists) and applied all of them to the image 'structure' in one 'put' call.

    That may be worth a try with this utility. It should provide the same draw time irrespective of whether the user asks for the color-gradient in the x or the y direction.

I may implement these enhancements sometime in 2016 (or 2017).

(If I use this script as a starting point for another 'image-creator_color-shaded_3D-like' utility, then I will probably implement these enhancements in that new utility --- and then go back to this utility and implement the enhancements.)

You are welcome to take this code and add these enhancements --- and others.


As I have said on several other code-donation pages on this freedomenv.com site and on the Tclers' wiki at wiki.tcl.tk ...

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 this page for
Tcl-Tk Code to
Draw a 2-color X-or-Y-gradient
RECTANGLE/BUTTON with color-shaded 3D-edges

--- a utility in the FE 'tkGooies' system,
in the 'IMAGEcreators - Shaded3D' 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 2012 --- and posted 2012 Oct 15 22 at http://wiki.tcl.tk/37143.

This FE web page was created 2014 May 10 --- as a backup and alternative to the wiki.tcl.tk page.

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

Page was changed 2015 Dec 30.
(Added some paragraphs and some links.)

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

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

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.