A color-gradient-button-maker GUI using a separate color-selector script

uniquename - 2012nov03

I am interested in making nice images for 'toolchest' and 'drawer' backgrounds (and other GUI embellishments), as I have indicated at Experiments in making embellished GUI's and at A color-gradient-button-maker GUI.

I have created several different 'color-gradient-button-maker GUI' scripts, trying to find a fastest-way to set the 2 gradient colors, since one might wish to experiment with a large number of different color combinations.

The main 'drawing' proc in all these scripts is based on a 'DrawGradient' proc at Drawing Gradients on a Canvas which uses 'create line' commands on a 'canvas' widget to generate the color gradients --- with either horizontal or vertical lines.

The script variations that I devised were

These scripts can be used to make small or large rectangular image files (like GIF or PNG files) that contain a color gradient, given 2 colors.

Probably the script that is fastest at setting colors is the one that uses 6 scale widgets --- BUT that is the one that takes the most 'screen real-estate'.

The script with 6 spinboxes offers a fairly compact GUI, but the spinboxes 'turn over' rather slowly, in going from 0 to 255.

The script with 6 'miniscale' widgets offered a way of getting fast 'turn over' without using as much real-estate as 6 scale widgets.

The script using a single entry widget is compact, but it suffers from the need to provide rigorous editing of the input to make sure the user enters valid data --- AND it is a slow way of entering the 6 RGB color numbers.

On this page, I offer one more way of setting the colors --- it is reasonably fast and is quite conservative with screen real-estate.

This method depends on using an EXTERNAL color selector GUI --- such as the one presented on the page A non-obfuscated color selector GUI on this site.

Here is an image of the resulting 2-color-buttons GUI.

gradientAcrossCanvasGUI_2colorButtons_screenshot_677x111.jpg

This GUI shows the two currently selected colors as hex-color-codes in a label at the top of the GUI --- to the right of the two color selector buttons.

Since hex-codes may not be (quickly) meaningful to users, the labels holding the two hex-codes are given the color of the hex-code displayed. (In addition to putting the colors on label widgets, we could put the colors on the buttons. Or, if all those colors look too 'busy', we could put the color on the buttons INSTEAD OF on the labels.)

___________________________________________________________

I present the code for the '2-color-buttons' GUI below.

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 framesand sub-frames.

  2) Define & pack all widgets in the frames, frame by frame.

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

_________________________________________________________________

As in all my scripts that use the 'pack' geometry manager (which is all of my scripts, so far), I have put the four main pack parameters --- '-side', '-anchor', '-fill', '-expand' --- on the pack command for the various frames and widgets. So Tcler's can experiment with these parameters if they want to change the behavior of the GUI when window size is changed.

Alternatively, Tcler's can activate the commented statement

wm resizeable . 0 0

to make the canvas a fixed size and avoid any confusion that might be caused by allowing the window to be resized.

However, I wanted to be able to make a rectangle/button of almost any desired size, by resizing the window and having the canvas resize automatically. So I did not fix the size of the window.


 Code for the Tk script 'make_gradient-on-canvas_externalColorSelector_2buttons.tk' :
#!/usr/bin/wish -f
##
## SCRIPT: make_gradient-on-canvas_externalColorSelector_2buttons.tk
##
## PURPOSE:  This TkGUI script facilitates the creation of
##           rectangular color-gradient images that can be used, for example,
##           for the background of 'buttons' in GUIs such as 'toolchests'.
##
##           A screen/window capture utility (like 'gnome-screenshot' on Linux)
##           can be used to capture the image in a GIF or PNG file, say.
##
##           Then, if necessary, an image editor (like 'mtpaint' on Linux)
##           can be used to crop the window capture image to get only the
##           rectangular area of the canvas containing the color-gradient
##           --- or some sub-rectangle of that area.
##
##           Furthermore, utilities (such as the ImageMagick 'convert' command
##           on Linux) can be used to 'mirror' or 'flip' a gradient image in
##           an image file (PNG or JPEG or GIF). The 'mirror'  and 'flip'
##           operations can be applied vertically or horizontally ---  and
##           can be applied multiple times, for various visual effects.
##
##           Also decorations such as bevels could be applied with scripts
##           using 'convert' or with interactive image editors such as 'mtpaint'.
##
##           The resulting rectangular color-gradient image can then be used as a
##           background in Tk widgets, such as button or canvas or label widgets
##           in 'toolchests' or other types of GUIs. 
##
##+##########
## GUI DESIGN:
##
##           The GUI contains a rectangular CANVAS WIDGET into which the
##           color gradient is drawn with canvas 'create line' commands,
##           where the lines can be either horizontal (in the x direction)
##           or vertical (in the y direction).
##
##           In addition to the canvas widget (in a frame of the GUI window),
##           in a 'buttons' frame of the GUI window are:
##              - an 'Exit' button
##              - 2 radiobuttons --- to indicate x or y direction for the
##                color gradient
##              - 2 buttons which call on an external color-selector GUI,
##                to allow the user to select the 2 colors involved.
##
##           The the 2 'color' buttons are used to set 2 pairs of RGB values ---
##           of the form  r1 g1 b1 r2 g2 b2 --- for the left-color (or top-color)
##           and right-color (bottom-color) of the gradient.
##
##           Examples of 2 settings using the two radiobuttons and the
##           two color buttons:
##             x 255 255 0 255 0 0
##             y 255 0 255 0 0 255
##
##           The first example says draw the lines horizontally starting
##           from yellow on the left to red on the right.
##
##           The second example says draw the lines vertically starting
##           from magenta at the top to blue on the bottom.
##+#######
## METHOD:
##           The seven parms (x/y r1 g1 b1 r2 g2 b2)
##           are passed into a 'DrawGradient' proc that draws the lines
##           within the canvas, filling the canvas with colored pixels.
##
##           The 'DrawGradient' proc is called in the case of 5 'events':
##               - button1-release on radiobutton 'x'
##               - button1-release on radiobutton 'y'
##               - a click on the color1 button
##               - a click on the color2 button
##               - GUI initialization
##
##           The 'create line' commands issued 'across' the button
##           (rectangular canvas) proceed fast enough that the canvas
##           is colored with the 'gradient-of-colors' within 1 second.
##
##+#########
## REFERENCE (and credit):
## The 'DrawGradient' proc is based on a Tcl-Tk script by B. Oakley and
## Damon Courtney --- published at https://wiki.tcl-lang.org/6100 -
## 'Drawing Gradients on a Canvas'.  (downloaded 2011sep26)
## That script draws gradients on multiple rectangular canvases, packed
## top to bottom. You need to edit that script to change colors or
## gradient direction. No GUI for entry of those parameters is provided.
##+######################################################################
## 'CANONICAL' STRUCTURE OF THIS CODE:
##
##  0) Set general window parms (win-name,win-position,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 all widgets in the frames. Pack all the widgets for a frame,
##                     as one finishes defining the widgets in each frame.
##
##  3) Define keyboard or mouse/touchpad/touch-sensitive-screen action
##     BINDINGS, if needed.
##  4) Define PROCS, if needed.
##  5) Additional GUI INITIALIZATION (typically with one or two of
##                                    the procs), if needed.
##
##----------------------------------
## The code structure in more detail, for this particular script:
##
##  1a) Define ALL frames:
## 
##      Top-level : '.fRbuttons' and  '.fRcanvas'
##
##      Sub-frames: none
##
##  1b) Pack ALL frames.
##
##  2) Define all widgets in the frames (and pack them):
##
##       - In '.fRbuttons':
##            - 1 button widget ('Exit')
##            - 2 radiobuttons (for x or y gradient direction)
##            - 2 'color' buttons (to call an external color selector)
##
##       - In '.fRcanvas': one 'canvas' widget
##
##  3) Define bindings:
##       2 button1-release bindings -- on the 2 radiobuttons
##
##  4) Define procs:
##     - 'DrawGradient'    invoked by the 2 bindings and the
##                                        2 'color' buttons
##
##  5) Additional GUI initialization:  Execute 'DrawGradient' once with
##                                     an initial, example set of 7 parms
##                                     --- x/y r1 g1 b1 r2 g2 b2 --- to start
##                                     with a color-gradient in the canvas
##                                     rather than a blank canvas.
##+########################################################################
## DEVELOPED WITH: Tcl-Tk 8.5 on Ubuntu 9.10 (2009-october, 'Karmic Koala')
##
##   $ wish
##   % puts "$tcl_version $tk_version"
##
## showed
##     8.5 8.5
## but this script should work in most previous 8.x versions, and probably
## even in some 7.x versions (if font handling is made 'old-style').
##+#######################################################################
## MAINTENANCE HISTORY:
## Created by: Blaise Montandon 2012nov02
## Changed by: ...... ......... 2012
##+#######################################################################


##+#######################################################################
## Set general window parms (title,position).
##+#######################################################################

wm title    . "Draw-Color-Gradient in a Canvas"
wm iconname . "DrawGradient"

wm geometry . +15+30


##+######################################################
## Set the color scheme for the window and its widgets ---
## radiobuttons and spinboxes.
##+######################################################

tk_setPalette "#e0e0e0"

set radbuttBKGD "#ffffff"


##+########################################################
## Use a variable-width font for labels for the 6 spinboxes
## and the 2 radiobuttons and the Exit button text.
## Use a    fixed-width font for the spinbox entry field.
##+########################################################

font create fontTEMP_varwidth \
   -family {comic sans ms} \
   -size -14 \
   -weight bold \
   -slant roman

font create fontTEMP_SMALL_varwidth \
   -family {comic sans ms} \
   -size -12 \
   -weight bold \
   -slant roman


## Some other possible (similar) variable width fonts:
##  Arial
##  Bitstream Vera Sans
##  DejaVu Sans
##  Droid Sans
##  FreeSans
##  Liberation Sans
##  Nimbus Sans L
##  Trebuchet MS
##  Verdana

font create fontTEMP_fixedwidth  \
   -family {liberation mono} \
   -size -14 \
   -weight bold \
   -slant roman

font create fontTEMP_SMALL_fixedwidth  \
   -family {liberation mono} \
   -size -12 \
   -weight bold \
   -slant roman

## Some other possible fixed width fonts (esp. on Linux):
##  Andale Mono
##  Bitstream Vera Sans Mono
##  Courier 10 Pitch
##  DejaVu Sans Mono
##  Droid Sans Mono
##  FreeMono
##  Nimbus Mono L
##  TlwgMono


##+###########################################################
## SET GEOM VARS FOR THE VARIOUS WIDGET DEFINITIONS.
## (e.g. width and height of canvas, and padding for Buttons)
##+###########################################################

set initCanWidthPx 300
set initCanHeightPx 24
set minCanHeightPx 24

# set BDwidthPx_canvas 2
  set BDwidthPx_canvas 0


## For BUTTONS:

set PADXpx_button 0
set PADYpx_button 0
set BDwidthPx_button 2


## For LABELS:

set PADXpx_label 0
set PADYpx_label 0
set BDwidthPx_label 2


##+######################################################
## Set a MINSIZE of the window (roughly) according to the
## approx max WIDTH of the chars in the 'fRbuttons' frame
## --- 1 exit button, 2 radiobuttons, 2 color buttons,
## and 3 labels.
##
## --- and according to the approx HEIGHT of the 2 frames
## --- 'fRbuttons' and  'fRcanvas'.
##+######################################################

set minWinWidthPx [font measure fontTEMP_varwidth \
   "Exit Direction:  x  y  Color1  Color2  Color1: #FFFF00  Color2: #FF0000"]

## Add some pixels to account for right-left-size window/widget
## border-widths (about 6 pixels) --- and borderwidths and
## padding for about 6 widgets x 4 pixels/widget.
set minWinWidthPx [expr 30 + $minWinWidthPx]

## For MIN-HEIGHT:
## Allow 1 char   high for 'fRbuttons',
##      24 pixels high for 'fRcanvas'.

set minCharHeightPx [font metrics fontTEMP_SMALL_fixedwidth -linespace]

set minWinHeightPx [expr 24 + $minCharHeightPx]

## Add some to account for top-bottom window decoration (about 20 pixels)
## and frame/widget padding (about 3 pixels/frame x 2 frames).

set minWinHeightPx [expr 26 + $minWinHeightPx]

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

wm minsize . $minWinWidthPx $minWinHeightPx

## NOTE:
## We allow the window to be resizable and we pack the canvas with
## '-fill both' so that the canvas can be enlarged by enlarging the
## window. The user can simply click-release any of the buttons
## (2 radiobuttons or 2 'color' buttons) to re-fill the canvas
## with the user-specified color gradient.

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

# wm resizable . 0 0


##+################################################################
## DEFINE *ALL* THE FRAMES:
##
##   Top-level :  'fRbuttons', 'fRcanvas'
##
##   Sub-frames: none
##+################################################################

## FOR TESTING: (to check behavior of frames during window expansion)
# set RELIEF_frame raised
# set BDwidth_frame 2

set RELIEF_frame flat
set BDwidth_frame 0


frame .fRbuttons  -relief $RELIEF_frame  -borderwidth $BDwidth_frame

frame .fRcanvas   -relief $RELIEF_frame  -borderwidth $BDwidth_frame


##+##############################
## PACK the 2 top-level FRAMES. 
##+##############################

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

pack .fRcanvas \
   -side top \
   -anchor nw \
   -fill both \
   -expand 1

## OK, the frames are defined and packed.

##+#####################################
##+#####################################
## DEFINE-AND-PACK WIDGETS WITHIN FRAMES.
##+#####################################
##+#####################################


##+################################################################
## IN THE '.fRbuttons' FRAME --
## DEFINE an 'Exit' BUTTON, 2 RADIOBUTTONS, 2 'color' BUTTONS,
## and 3 LABELS.
##+################################################################

button .fRbuttons.buttEXIT \
   -text "Exit" \
   -font fontTEMP_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command {exit}


## Define a label and 2 radiobuttons:

label .fRbuttons.lab_radbutts \
   -text "  Gradient direction:" \
   -font fontTEMP_varwidth \
   -justify left \
   -anchor w \
   -relief flat \
   -bd $BDwidthPx_button

## We set this widget-variable in the 
## GUI-initialization section at the
## bottom of this script.
# set curDIRECTION "x"

radiobutton  .fRbuttons.radbuttX \
   -text "x" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable curDIRECTION \
   -value "x" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_button
   
radiobutton  .fRbuttons.radbuttY \
   -text "y" \
   -font fontTEMP_varwidth \
   -anchor w \
   -variable curDIRECTION \
   -value "y" \
   -selectcolor "$radbuttBKGD" \
   -relief flat \
   -bd $BDwidthPx_button


## Define the 2 color buttons.

button .fRbuttons.buttCOLOR1 \
   -text "Gradient
Color1" \
   -font fontTEMP_SMALL_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command "set_color1"

button .fRbuttons.buttCOLOR2 \
   -text "Gradient
Color2" \
   -font fontTEMP_SMALL_varwidth \
   -padx $PADXpx_button \
   -pady $PADYpx_button \
   -relief raised \
   -bd $BDwidthPx_button \
   -command "set_color2"


## Define 3 labels for displaying the 2 gradient colors
## --- as hex-values and by setting background and
## foreground color of 2 of the labels.

label .fRbuttons.labelCOLORS \
   -text "Gradient" \
   -font fontTEMP_SMALL_varwidth \
   -justify left \
   -anchor w \
   -relief flat \
   -bd $BDwidthPx_label

label .fRbuttons.labelCOLOR1 \
   -text "" \
   -font fontTEMP_SMALL_varwidth \
   -justify left \
   -anchor w \
   -relief flat \
   -bd $BDwidthPx_label

label .fRbuttons.labelCOLOR2 \
   -text "" \
   -font fontTEMP_SMALL_varwidth \
   -justify left \
   -anchor w \
   -relief flat \
   -bd $BDwidthPx_label

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

pack .fRbuttons.buttEXIT \
     .fRbuttons.lab_radbutts \
     .fRbuttons.radbuttX \
     .fRbuttons.radbuttY \
     .fRbuttons.buttCOLOR1 \
     .fRbuttons.buttCOLOR2 \
     .fRbuttons.labelCOLORS \
     .fRbuttons.labelCOLOR1 \
     .fRbuttons.labelCOLOR2 \
   -side left \
   -anchor w \
   -fill none \
   -expand 0


##+########################################################
## In the '.fRcanvas' FRAME -
## DEFINE-and-PACK CANVAS WIDGET.
##+########################################################
## We set highlightthickness & borderwidth of the canvas to
## zero, as suggested on page 558, Chapter 37, 'The Canvas
## Widget', in the 4th edition of the book 'Practical
## Programming in Tcl and Tk'.
##+########################################################

canvas .fRcanvas.canvas \
   -width $initCanWidthPx \
   -height $initCanHeightPx \
   -relief flat \
   -highlightthickness 0 \
   -borderwidth 0

pack .fRcanvas.canvas \
   -side top \
   -anchor nw \
   -fill both \
   -expand 1


##+#######################################################
## END OF DEFINING-and-PACKING ALL WIDGETS and
## END OF DEFINING the GUI.
##+#######################################################


##+#######################################################################
## BINDINGS SECTION:
##        - button1-release on each of the 2 radiobuttons
##+#######################################################################

bind .fRbuttons.radbuttX <ButtonRelease-1>  "DrawGradient"

bind .fRbuttons.radbuttY <ButtonRelease-1>  "DrawGradient"


##+######################################################################
## PROCS SECTION: 
##    'DrawGradient' - to fill the specified canvas according to the
##                     7 parms --- x/y r1 g1 b1 r2 g2 b2
##    'set_color1'   - Calls on external color selector to set a
##                     color1, then call 'DrawGradient'. Also updates
##                     a color1 label in the GUI.
##    'set_color2'   - Calls on external color selector to set a
##                     color2, then call 'DrawGradient'. Also updates
##                     a color2 label in the GUI.
##    'update_color1_label' - to update the color1 label widget with
##                            text and background-foreground colors
##    'update_color2_label' - to update the color2 label widget with
##                            text and background-foreground colors
##+######################################################################


##+#####################################################################
## proc DrawGradient
##+#####################################################################
## PURPOSE:  This procedure is invoked put a color gradient 'across'
##           the canvas --- according to 7 parms --- x or y and
##           two RGB triplets.
##
## ARGUMENTS: see the global statement
##
## CALLED BY: the COLOR1 and COLOR2 buttons (actually the 'set_color1'
##            and 'set_color2' procs), 2 button1-release bindings
##            on the 2 radiobuttons, and called in the GUI initialization
##            section at the bottom of this script.
##+####################################################################

proc DrawGradient {} {

   global curDIRECTION \
      COLOR1r COLOR1g COLOR1b COLOR1hex \
      COLOR2r COLOR2g COLOR2b COLOR2hex

   ## Clear the canvas.

   .fRcanvas.canvas delete all

   ## Get current canvas width and height.

   set canWidthPx  [winfo width  .fRcanvas.canvas]
   set canHeightPx [winfo height .fRcanvas.canvas]

   ## Get the distance 'distPx' (in pixels) over which
   ## the 2 colors are to be gradiated.

   if {"$curDIRECTION" == "x"} {
      set distPx $canWidthPx
   } else {
      set distPx $canHeightPx
   }

   ## Get RGB ranges.

   set rRange [expr {double($COLOR2r - $COLOR1r)}]
   set gRange [expr {double($COLOR2g - $COLOR1g)}]
   set bRange [expr {double($COLOR2b - $COLOR1b)}]

   ## Calc the ratio of RGB-color-ranges to distance
   ## 'across' the canvas.

   set rRatio [expr {$rRange / $distPx}]
   set gRatio [expr {$gRange / $distPx}]
   set bRatio [expr {$bRange / $distPx}]

   ## Increment 'across' the canvas, drawing colored lines
   ## with canvas-'create line'.

   for {set i 0} {$i < $distPx} {incr i} {

      set nR [expr {int( $COLOR1r + ($rRatio * $i) )}]
      set nG [expr {int( $COLOR1g + ($gRatio * $i) )}]
      set nB [expr {int( $COLOR1b + ($bRatio * $i) )}]

      set hexcolor [format "#%02X%02X%02X" $nR $nG $nB]

      ## FOR TESTING:
      #  puts "hexcolor = $hexcolor"

      if {"$curDIRECTION" == "x"} {
         .fRcanvas.canvas create line $i 0 $i $canHeightPx -fill "$hexcolor"
      } else {
         .fRcanvas.canvas create line 0 $i $canWidthPx $i -fill "$hexcolor"
      }
   }
   ## END OF  for {set i 0} {$i < $distPx} {incr i}

}
## END OF proc DrawGradient


##+#####################################################################
## proc  'set_color1'
##+##################################################################### 
## PURPOSE:  This procedure is invoked to get an RGB triplet
##           via 3 RGB slider bars on the FE Color Selector GUI.
##
##           Uses that RGB value to set a color to be used for the
##           1st color for a color gradient 'across' the canvas.
##
## ARGUMENTS: see the global statement
##
## OUTPUT: in global vars COLOR1r COLOR1g COLOR1b COLOR1hex
##
## CALLED BY:  the COLOR1  button
##+#####################################################################

proc set_color1 {} {

   global curDIRECTION \
      COLOR1r COLOR1g COLOR1b COLOR1hex \
      COLOR2r COLOR2g COLOR2b COLOR2hex

   # global feDIR_tkguis

   ## FOR TESTING:
   #    puts "COLOR1r: $COLOR1r"
   #    puts "COLOR1g: $COLOR1g"
   #    puts "COLOR1b: $COLOR1b"

   set TEMPrgb [ exec \
       ./sho_colorvals_via_sliders3rgb.tk \
       $COLOR1r $COLOR1g $COLOR1b]

   #   $feDIR_tkguis/sho_colorvals_via_sliders3rgb.tk \

   ## FOR TESTING:
   #    puts "TEMPrgb: $TEMPrgb"

   if { "$TEMPrgb" == "" } { return }
 
   scan $TEMPrgb "%s %s %s %s" r255 g255 b255 hexRGB

   set COLOR1hex "#$hexRGB"
   set COLOR1r $r255
   set COLOR1g $g255
   set COLOR1b $b255


   ## Update the Color1 label.

   update_color1_label


   ## Update the color gradient on the canvas.

   DrawGradient

}
## END OF PROC  'set_color1'


##+#####################################################################
## proc  'set_color2'
##+##################################################################### 
## PURPOSE:  This procedure is invoked to get an RGB triplet
##           via 3 RGB slider bars on the FE Color Selector GUI.
##
##           Uses that RGB value to set a color to be used for the
##           2nd color for a color gradient 'across' the canvas.
##
## ARGUMENTS: see the global statement
##
## OUTPUT: in global vars COLOR2r COLOR2g COLOR2b COLOR2hex
##
## CALLED BY:  the COLOR2  button
##+#####################################################################

proc set_color2 {} {

   global curDIRECTION \
      COLOR1r COLOR1g COLOR1b COLOR1hex \
      COLOR2r COLOR2g COLOR2b COLOR2hex

   # global feDIR_tkguis

   ## FOR TESTING:
   #    puts "COLOR2r: $COLOR2r"
   #    puts "COLOR2g: $COLOR2g"
   #    puts "COLOR2b: $COLOR2b"

   set TEMPrgb [ exec \
       ./sho_colorvals_via_sliders3rgb.tk \
       $COLOR2r $COLOR2g $COLOR2b]

   #   $feDIR_tkguis/sho_colorvals_via_sliders3rgb.tk \

   ## FOR TESTING:
   #    puts "TEMPrgb: $TEMPrgb"

   if { "$TEMPrgb" == "" } { return }
 
   scan $TEMPrgb "%s %s %s %s" r255 g255 b255 hexRGB

   set COLOR2hex "#$hexRGB"
   set COLOR2r $r255
   set COLOR2g $g255
   set COLOR2b $b255


   ## Update the color2 label.

   update_color2_label


   ## Update the color gradient on the canvas.

   DrawGradient

}
## END OF PROC  'set_color2'


##+#####################################################################
## proc  'update_color1_label'
##+##################################################################### 
## PURPOSE:  This procedure is invoked to update the color1 label
##           on the GUI with text and background and foreground colors.
##
## ARGUMENTS: see the global statement
##
## OUTPUT: changed attributes of the colo1 label
##
## CALLED BY:  the 'set_color1' proc and in the GUI initialization
##             section at the bottom of this script.
##+#####################################################################

proc update_color1_label {} {

   global COLOR1r COLOR1g COLOR1b COLOR1hex

   .fRbuttons.labelCOLOR1 configure -text "Color1 - $COLOR1hex"

   .fRbuttons.labelCOLOR1 configure -bg "$COLOR1hex"

   set RGBsum [expr { $COLOR1r + $COLOR1g + $COLOR1b }]

   if {$RGBsum > 400} {
      .fRbuttons.labelCOLOR1 configure -fg "#000000"
   } else {
      .fRbuttons.labelCOLOR1 configure -fg "#f0f0f0"
   }

}
## END OF PROC  'update_color1_label'


##+#####################################################################
## proc  'update_color2_label'
##+##################################################################### 
## PURPOSE:  This procedure is invoked to update the color2 label
##           on the GUI with text and background and foreground colors.
##
## ARGUMENTS: see the global statement
##
## OUTPUT: changed attributes of the colo1 label
##
## CALLED BY:  the 'set_color2' proc and in the GUI initialization
##             section at the bottom of this script.
##+#####################################################################

proc update_color2_label {} {

   global COLOR2r COLOR2g COLOR2b COLOR2hex

   .fRbuttons.labelCOLOR2 configure -text "Color2 - $COLOR2hex"

   .fRbuttons.labelCOLOR2 configure -bg "$COLOR2hex"

   set RGBsum [expr { $COLOR2r + $COLOR2g + $COLOR2b }]

   if {$RGBsum > 400} {
      .fRbuttons.labelCOLOR2 configure -fg "#000000"
   } else {
      .fRbuttons.labelCOLOR2 configure -fg "#f0f0f0"
   }

}
## END OF PROC  'update_color2_label'


##+#############################################################
## proc ReDraw_if_canvas_resized
##
## PURPOSE: To make sure we are only doing redraws if the
##          <Configure> of the canvas resulted in a change
##          in the size of the canvas.
##
## CALLED BY: bind .fRcanvas.canvas <Configure> 
##            at bottom of this script.
##+#############################################################

proc ReDraw_if_canvas_resized {} {

   global  PREVcanWidthPx PREVcanHeightPx

   set CURcanWidthPx  [winfo width  .fRcanvas.canvas]
   set CURcanHeightPx [winfo height .fRcanvas.canvas]

   if { $CURcanWidthPx  != $PREVcanWidthPx || \
        $CURcanHeightPx != $PREVcanHeightPx} {

      DrawGradient

      set PREVcanWidthPx  $CURcanWidthPx
      set PREVcanHeightPx $CURcanHeightPx
   }

}
## END OF ReDraw_if_canvas_resized


##+#####################################################
## Additional GUI initialization, if needed (or wanted).
##+#####################################################

## Set initial values for the 'application variables'
## --- but not widget appearance parameters (those
## are set above).
## 
## Note these variables are declared global in the
## several procs --- DrawGradient, set_color1, set_color2.
## This avoids some extra memory management for temp-vars
## to pass these variables (their locations) to the procs.

set curDIRECTION "x"

set COLOR1r 255
set COLOR1g 255
set COLOR1b 0
set COLOR1hex [format "#%02X%02X%02X" $COLOR1r $COLOR1g $COLOR1b]

set COLOR2r 255
set COLOR2g 0
set COLOR2b 0
set COLOR2hex [format "#%02X%02X%02X" $COLOR2r $COLOR2g $COLOR2b]

update_color1_label
update_color2_label

update

## 'update' is needed before DrawGradient so that the
## canvas width and height are implemented.
## DrawGradient uses 'winfo' to get those dimensions.

DrawGradient


## After this script drops into the Tk event-handling loop,
## this bind command causes redraws whenever the canvas is resized.

set PREVcanWidthPx  [winfo width  .fRcanvas.canvas]
set PREVcanHeightPx [winfo height .fRcanvas.canvas]
bind .fRcanvas.canvas <Configure> "ReDraw_if_canvas_resized"


You may find this rectangle/button rather plain, even though you can get some nice color gradients.

Rectangular buttons with 'shaded edges' may be more to your liking. If so, have a look at

and, if you like 'rounded corners' with those 'shaded edges', try

with a large exponent.

These are done using canvas-'create image', instead of canvas-'create line'.