[uniquename] - 2012aug04 I tried out the code at [Drawing Gradients on a Canvas] and was surprised how fast it fills large rectangular canvas areas with a color gradient. Apparently the trick is to use 'create line' rather than 'put at x y' --- i.e. make horizontal or vertical lines, rather than poking a color into each x,y location. That drawing-gradients demo ties in with my wish to make nice backgrounds for buttons in application or utility 'toolchests', as indicated at my request to "Implement '-anchor' (something similar) for compound text on image" at the [Tk 9.0 WishList] page. I have enhanced the code at [Drawing Gradients on a Canvas] to provide a GUI with an entry widget (at the bottom of the GUI) to enter 7 parameters of the form 'x/y r1 g1 b1 r2 g2 b2', along with a 'Draw' button --- to draw the specified gradient into the canvas widget at the top of the GUI. Here is a sample image: [draw-color-gradient-GUI_screenshot_544x108.png] Note: I changed the draw-gradient proc at [Drawing Gradients on a Canvas] to use RGB values (in decimal form), rather than color names --- so that a much wider range of color choices is available. Now I can quickly make color-gradient 'button files' by doing screen/window captures of this GUI --- with a screenshot utility, like 'gnome-screenshot' on Linux. Below is the code for this 'gradient-button-maker' GUI. It includes plenty of comments to explain the GUI. One thing to note is that I have put the four main pack parameters --- '-side', '-anchor', '-fill', '-expand' --- on the pack command for the various frames and widgets. This is so that 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. ====== #!/usr/bin/wish -f ## ## SCRIPT: make_gradient-button_rectangular.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 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. ## ## 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. ## ## METHOD: 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 top frame of the GUI window), ## in a bottom frame of the GUI window, there are a couple of ## buttons ('Draw' and 'Exit') and an entry field. ## ## The entry field contains 7 values --- of the format ## x/y r1 g1 b1 r2 g2 b2 ## Examples: ## 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. ## ## 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. ## ########################################################################### ## REFERENCE: ## The 'DrawGradient' proc is based on a Tcl-Tk script by Damon Courtney ## --- published at http://wiki.tcl.tk/6100 . (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 indicators is provided. ## ########################################################################### ## STRUCTURE OF THIS CODE: ## ## 0) Set general window parms (name,position,[size,]color-scheme,fonts, ## widget-geometry-parms,etc.). ## 1) Define ALL frames (and sub-frames). Pack them. ## 2) Define all widgets in the frames. Pack them. ## ## 3) Define keyboard or mouse action BINDINGS, if needed. ## 4) Define PROCS, if needed. ## 5) Additional GUI INITIALIZATION (with procs), if needed. ## ## In more detail: ## ## 1a) Define ALL frames: ## ## Top-level : '.fRtop' and '.fRbottom' ## ## Sub-frames: none ## ## 1b) Pack ALL frames. ## ## 2) Define all widgets in the frames (and pack them): ## ## - In '.fRtop': one 'canvas' widget ## ## - In '.fRbottom': 2 button widgets ('Draw' and 'Exit') and ## an entry widget (for the 7 gradient-drawing parms) ## ## 3) Define bindings: one, for the entry widget ## ## 4) Define procs: ## - 'DrawGradient' invoked by the 'Draw' button ## ## 5) Additional GUI initialization: none ## (or could execute 'DrawGradient' ## once with an initial, example ## set of 7 parms --- to start with ## a color-gradient in the canvas ## rather than a blank canvas) ## ########################################################################## ## DEVELOPED WITH: ## Tcl-Tk 8.5 (or 8.4) on Ubuntu 9.10. ## ## $ wish ## % puts "$tcl_version $tk_version" ## showed 8.4 8.4 or ## 8.5 8.5 on Ubuntu 9.10. ## ########################################################################### ## MAINTENANCE HISTORY: ## Created by: Blaise Montandon 2012aug01 ## Changed by: ...... ......... 2012 ########################################################################### ######################################################################### ## Set general window parms (title,position,size,color-scheme,fonts,etc.). ######################################################################### wm title . "Draw-Color-Gradient in a Rectangular Canvas" wm iconname . "DrawGradient" wm geometry . +15+30 ## 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. Just click the 'Draw' button 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 ## Set the color scheme for the window and its widgets. tk_setPalette "#cfcfcf" ## Use a variable-width font for buttons (and labels). ## Use a fixed-width font for the entry field. font create fontTEMP_button \ -family {comic sans ms} \ -size -14 \ -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_entry \ -family {liberation mono} \ -size -14 \ -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, padding for Buttons) ########################################################################## set initCanWidthPx 400 set initCanHeightPx 24 set PADXpx_button 0 set PADYpx_button 0 set BDwidthPx_button 2 # set BDwidthPx_canvas 2 set BDwidthPx_canvas 0 set BDwidthPx_entry 2 set initENTRYwidthChars 30 ####################################################################### ## DEFINE *ALL* THE FRAMES: ## ## Top-level : 'fRtop' and 'fRbottom' ## ## Sub-frames: none ####################################################################### set BDwidth_frame 2 frame .fRtop -relief raised -borderwidth $BDwidth_frame frame .fRbottom -relief raised -borderwidth $BDwidth_frame ################################################################### ## PACK the 2 top-level FRAMES. ################################################################### pack .fRtop \ -side top \ -anchor nw \ -fill both \ -expand 1 pack .fRbottom \ -side top \ -anchor nw \ -fill x \ -expand 0 ################################ ## DEFINE-and-PACK CANVAS WIDGET: ################################ canvas .fRtop.can \ -width $initCanWidthPx \ -height $initCanHeightPx \ -relief raised \ -borderwidth $BDwidthPx_canvas pack .fRtop.can \ -side top \ -anchor nw \ -fill both \ -expand 1 ########################################################################## ## IN THE '.fRbottom' frame -- DEFINE the 'Draw' and 'Exit' buttons ## --- and a pair of label and entry widgets. ########################################################################## button .fRbottom.buttDRAW \ -text "Draw" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {eval DrawGradient .fRtop.can $ENTRYstring} button .fRbottom.buttEXIT \ -text "Exit" \ -font fontTEMP_button \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {exit} label .fRbottom.lab \ -text "\ Draw-Color-Gradient parms: (x/y r1 g1 b1 r2 g2 b2)" \ -font fontTEMP_button \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_button set ENTRYstring "x 255 255 0 255 0 0" entry .fRbottom.ent \ -textvariable ENTRYstring \ -bg "#f0f0f0" \ -font fontTEMP_entry \ -width $initENTRYwidthChars \ -relief sunken \ -bd $BDwidthPx_entry ############################################# ## Pack the widgets in the 'fRbottom' frame. ############################################# pack .fRbottom.buttEXIT \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbottom.buttDRAW \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbottom.lab \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbottom.ent \ -side left \ -anchor w \ -fill x \ -expand 1 ########################################################################## ## BINDINGS SECTION: one, for Enter key in the entry field. ########################################################################## bind .fRbottom.ent {eval DrawGradient .fRtop.can $ENTRYstring} ########################################################################## ## PROCS SECTION: ## - DrawGradient' to fill the specified canvas according to the ## 7 parms from the ENTRYstring variable ########################################################################## proc DrawGradient {win axis r1 g1 b1 r2 g2 b2} { global ENTRYstring # if {[winfo class $win] != "Canvas"} { # return -code error "$win must be a canvas widget" # } # $win delete gradient set width [winfo width $win] set height [winfo height $win] switch -- $axis { "x" { set max $width; set x 1 } "y" { set max $height; set x 0 } default { # set ENTRYstring "$ENTRYstring ERR: Invalid 1st parm. Must be x or y." # return return -code error "Invalid 1st parm: $axis. Must be x or y" } } if { $r1 > 255 || $r1 < 0 } { return -code error "Invalid color value for r1: $r1" } if { $g1 > 255 || $g1 < 0 } { return -code error "Invalid color value for g1: $g1" } if { $b1 > 255 || $b1 < 0 } { return -code error "Invalid color value for b1: $b1" } if { $r2 > 255 || $r2 < 0 } { return -code error "Invalid color value for r2: $r2" } if { $g2 > 255 || $g2 < 0 } { return -code error "Invalid color value for g2: $g2" } if { $b2 > 255 || $b2 < 0 } { return -code error "Invalid color value for b2: $b2" } set rRange [expr $r2.0 - $r1] set gRange [expr $g2.0 - $g1] set bRange [expr $b2.0 - $b1] set rRatio [expr $rRange / $max] set gRatio [expr $gRange / $max] set bRatio [expr $bRange / $max] for {set i 0} {$i < $max} {incr i} { set nR [expr int( $r1 + ($rRatio * $i) )] set nG [expr int( $g1 + ($gRatio * $i) )] set nB [expr int( $b1 + ($bRatio * $i) )] set col [format {%2.2x} $nR] append col [format {%2.2x} $nG] append col [format {%2.2x} $nB] ## FOR TESTING: # puts "col = $col" if {$x} { $win create line $i 0 $i $height -tags gradient -fill #${col} } else { $win create line 0 $i $width $i -tags gradient -fill #${col} } } # return $win } ## END OF proc DrawGradient ################################################################## ## Additional GUI initialization, if needed (or wanted). ################################################################## update ## 'update' is needed before DrawGradient so that the ## canvas width and height are implemented. ## DrawGradient uses 'winfo' to get those dimensions. eval DrawGradient .fRtop.can $ENTRYstring ====== Now I have a tool to make nice color-gradient buttons for my Freedom Environment toolchests (see [http://www.freedomenv.com]) --- in future releases. I may try using some of the ideas in the [Functional imaging] page (thanks, Suchenwirth, for your many contributions) to make more complex color gradients than simple x-direction or y-direction gradients. But it make take a careful weeding out of the many functions presented there, to find functions that provide nice backgrounds for toolchest buttons (nice subtle gradients that do not distract from the text on the 'toolchest drawer' buttons). For now, I can use the ImageMagick commands 'convert' and 'composite' (as in the 'IMAGEtools' scripts of the 'feNautilusScripts' subsystem of the Freedom Environment software) to combine x and y gradient buttons (and other buttons) to make some additional types of gradient buttons. Make one enhancement to a Tk script and it leads to other enhancements or ideas for completely new scripts. It never ends. Darn you, Ousterhout, for starting all this. :-)