[uniquename] - 2012aug14 On the page [A color-gradient-button-maker GUI] and the page [A color-gradient-button-maker GUI with 6 spinboxes], I presented code that can be used to make small or large rectangular image files (like GIF or PNG files) that contain a color gradient, given 2 colors. Those GUI's are based on a 'DrawGradient' proc at [Drawing Gradients on a Canvas]. That proc uses 'create line' commands on a 'canvas' widget to generate the color gradients --- using either horizontal or vertical lines. As I pointed out on the [A color-gradient-button-maker GUI with 6 spinboxes] page, the changing of the 6 RGB colors involved cannot be performed as quickly as I would like --- in using either the entry-widget method or the 6-spinboxes method to provide for changing the 6 RGB values for the 2 colors. I should be able to experiment with color parameter changes much more rapidly if I use 6 'scale' widgets, instead of 6 'spinbox' widgets. The main drawback is that the GUI will have to be larger, to accomodate 6 'scale' widgets, instead of 6 'spinbox' widgets. Here is an image of the resulting 6-scales GUI. [draw-color-gradient-GUI_6sliders_screenshot_426x393.png] The 6-scales GUI takes a LOT more screen space than the 6-spinbox GUI. (See an image of the 6-spinbox GUI on the [A color-gradient-button-maker GUI with 6 spinboxes] page.) But the speed of changing a color to do a re-draw of the gradient is greatly improved. There is a lot better 'feel' to the 6-scale GUI as one experiments with color changes. I present the code for the 6-scale GUI below. ------ Draw speed: Since the 'DrawGradient' proc takes about half a second to redraw the color-gradient in the canvas, I probably would get a rather 'jumpy' re-drawing of the color-gradient canvas if I tried 'binding' the redraw to ANY change in one of the 6 RGB values, as a slider is moved with the mouse. Like with the 6-spinbox implementation, I realized that if I triggered the re-draw on a mouse-button RELEASE, I could get a pretty pleasing color change on the GUI --- while allowing me to quickly change any of the 6 RGB color values. However, if you want to see what will happen if you try letting the color-gradient-canvas be redrawn as the scale sliders are rapidly moved from one position to another, you can try activating the '-command' statements that appear as comment lines at each of the 6 'scale' definition statements in the code below. ------ Color change speed: Unlike the 6-spinbox implementation, I can rapidly make BIG changes in any of the 6 RGB colors --- by quick drags of the mouse, rather than watching a spinbox relatively slowly roll from one color setting to a quite different setting. And moving a slider is a lot faster than changing an entry in a spinbox with the keyboard. So now I can experiment quickly with redrawing the color gradient by using mouse-only. The color changes can be performed quickly even for a big color change in any of the 6 RGB values. To do BIG color changes relatively rapidly with the entry-widget or 6-spinboxes implementation of the GUI, I needed to use the keyboard --- either keyboard-and-mouse or keyboard-and-Enter-key. The 6-scales take a lot of space on the GUI, but I could use a 'scale' size parameter ('-width') to reduce the height of the horizontal scales somewhat. (I leave that as an exercise for the reader.) _________________________________________________________________ As promised above, here is the code for the '6 scales' implementation of the color-gradient-BACKGROUND-maker GUI. Like with the 'entry widget' version and the '6-spinboxes' version, 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. Furthermore, you can experiment with different font families, font weights, widget geometry (padding, borderwidth), widget and frame relief (raised, flat, ...). Tailor the GUI to your liking. ====== #!/usr/bin/wish -f ## ## SCRIPT: make_gradient-on-canvas_6scales-2radiobuttons.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. ## ######################## ## GUI LAYOUT and 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 bottom frame of the GUI ## window), there are other frames of the GUI window: ## - one frame for 2 radiobuttons and an 'Exit' button. ## - 6 frames for 6 'scale' (slider) widgets. ## ## The 2 radiobuttons are to set the direction of the gradient --- ## in the x direction or the y direction. ## ## The 6 scales are 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 of the radiobuttons and the 6 scales: ## 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. ## ## There is a '-command' parameter on the scale widget ## which could be used to call the 'DrawGradient' proc to redraw ## the color-gradient in the canvas as any scale (slider) changes. ## ## However, the 'DrawGradient' proc may not be fast enough to ## re-draw all the gradient-lines in a smooth fashion as the ## scale sliders are moved. ## ## In that case, we can use a button1-release binding on each ## scale widget to trigger a call to the 'DrawGradient' proc. ## ## By the time the user mouse-releases one scale and goes to ## move-and-release another scale, the 'DrawGradient' proc ## can complete the re-draw. ## ## Thus we get a 'semi-dynamic' (not quite immediate) GUI-update ## action from the scales, rather than a fully 'dynamic' ## (immediate) GUI-update action. ## ## However, the user/programmer can experiment by commenting ## out the 12 button1-release 'bind ' statements, and ## adding a '-command DrawGradient' parm to the 6 scale ## definition statements. ## ## REFERENCE: ## The 'DrawGradient' proc is based on a Tcl-Tk script by GPS and ## Damon Courtney --- published at http://wiki.tcl.tk/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,text-array-for-labels-etc). ## 1a) Define ALL frames (and sub-frames, if any). ## 1b) Pack the frames and sub-frames. ## 2) Define all widgets in the frames, frame-by-frame. ## When all the widgets for a frame are defined, pack them. ## ## 3) Define keyboard and mouse/touchpad/touch-sensitive-screen 'event' ## BINDINGS, if needed. ## 4) Define PROCS, if needed. ## 5) Additional GUI INITIALIZATION (typically with one or two procs), ## if needed. ## ## ## Some detail of the code structure for this particular script: ## ## 1a) Define ALL frames: ## ## Top-level : '.fRbuttons' ## '.fRsliderR1' '.fRsliderG1' '.fRsliderB1' ## '.fRsliderR2' '.fRsliderG2' '.fRsliderB2' ## '.fRcanvas' ## ## Sub-frames: none ## ## 1b) Pack ALL frames. ## ## 2) Define all widgets in the frames (and pack them): ## ## - In '.fRbuttons': 1 button widget ('Exit') and ## 2 radiobuttons (for x or y), ## ## - In each '.fRslider' frame: 1 scale widget (with label widget) ## ## - In '.fRcanvas': one 'canvas' widget ## ## 3) Define bindings: six, for button1-release on the scale widgets ## two, for button1-release on the radiobutton widgets ## ## 4) Define procs: ## - 'DrawGradient' invoked by the 8 bindings and by a call in the ## additional-GUI-initialization section, next ## ## 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 on Ubuntu 9.10. ##+####################################################################### ## MAINTENANCE HISTORY: ## Created by: Blaise Montandon 2012aug10 ## Changed by: Blaise Montandon 2012nov18 Added braces to 9 'expr' statements. ## Provided more consistent indenting ## of the code. Touched up the comments ## to match the final code. Added a ## text-array for labels,buttons,etc. ## Improved calc of minsize of window. ## Moved canvas to bottom of GUI. ##+####################################################################### ##+####################################################################### ## Set WINDOW TITLES. ##+####################################################################### wm title . "Draw-Color-Gradient in a Canvas" wm iconname . "DrawGradient" ##+###################################################################### ## Set WINDOW POSITION. ##+###################################################################### wm geometry . +15+30 ##+###################################################### ## Set the COLOR SCHEME for the window and its widgets --- ## radiobuttons. ##+###################################################### tk_setPalette "#e0e0e0" set radbuttBKGD "#ffffff" ##+########################################################### ## Set FONT-NAMES. ## We use a variable-width font for buttons and labels. ## ## We use a fixed-width font for entry fields, for easy access ## to narrow characters like i, j, l, and the number 1 --- ## in listboxes so that character columns in the list line up, ## and for text in a help window, so that columns will line up. ## However we do not have entry,listbox, or text widgets in ## this GUI --- unless we add a Help button. ##+########################################################### font create fontTEMP_varwidth \ -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_fixedwidth \ -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, and padding for Buttons) ##+########################################################### ## CANVAS parms: set initCanWidthPx 300 set initCanHeightPx 24 set minCanHeightPx 24 # set BDwidthPx_canvas 2 set BDwidthPx_canvas 0 ## BUTTON (and RADIOBUTTON) parms: set PADXpx_button 0 set PADYpx_button 0 set BDwidthPx_button 2 ## LABEL parms: set PADXpx_label 0 set PADYpx_label 0 set BDwidthPx_label 2 ## SCALE parms: set BDwidthPx_scale 2 set scaleLengthPx 200 ##+###################################################### ## Set a MINSIZE of the window according to the ## approx max WIDTH of the chars in the Exit button frame ## --- and according to the approx HEIGHT of the 8 frames. ##+################################################################# ## We allow the window to be resizable. We pack the canvas with ## '-fill both' so that the canvas can be enlarged by enlarging the ## window. The 'Draw' proc can be used to re-fill the canvas with ## the user-specified color gradient. ##+################################################################# set minWinWidthPx [font measure fontTEMP_fixedwidth \ " Exit Gradient direction: x y"] ## Add some to account for right-left-side window border-widths ## (about 2x3=6 pixels) and widget border-widths --- about ## 4 widgets x 4 pixels/widget = 16 pixels. set minWinWidthPx [expr {22 + $minWinWidthPx}] ## For MIN-HEIGHT, allow: ## 1 char high for frame 'fRbuttons', ## 2 chars high for each of the 6 scale frames, ## 24 pixels high for frame 'fRcanvas'. set minWinHeightPx [font metrics fontTEMP_fixedwidth -linespace] set minWinHeightPx [expr {24 + 13 * $minWinHeightPx}] ## Add some to account for top-bottom window decoration (about 23 pixels) ## and frame/widget padding/borders (about ## 14 frames/widgets x 4 pixels/frame-widget = 56 pixels). set minWinHeightPx [expr {79 + $minWinHeightPx}] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ## If you want to make the window un-resizable, ## you can use the following statement. # wm resizable . 0 0 ##+################################################ ## Load a TEXT-ARRAY variable with text for ## labels and other GUI widgets --- to facilitate ## 'internationalization' of this script. ##+################################################ ## if { "$VARlocale" == "en"} set aRtext(buttonEXIT) "Exit" set aRtext(labelDIR) "Gradient direction:" set scaleLabelWidthChars 15 set aRtext(labelSCALEGRP1) "\ Left/top Color r1:" set aRtext(labelSCALEGRP2) "\ Right/bottom Color r2:" ## END OF if { "$VARlocale" == "en"} ##+################################################################ ## DEFINE *ALL* THE FRAMES: ## ## Top-level : 'fRbuttons', ## 'fRsliderR1' , 'fRsliderG1' , 'fRsliderB1' ## 'fRsliderR2' , 'fRsliderG2' , 'fRsliderB2' ## 'fRcanvas' ## ## Sub-frames: none ##+################################################################ ## FOR TESTING: (of expansion of frames, esp. 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 set RELIEF_frame2 raised set BDwidth_frame2 2 frame .fRsliderR1 -relief $RELIEF_frame2 -borderwidth $BDwidth_frame2 frame .fRsliderG1 -relief $RELIEF_frame2 -borderwidth $BDwidth_frame2 frame .fRsliderB1 -relief $RELIEF_frame2 -borderwidth $BDwidth_frame2 frame .fRsliderR2 -relief $RELIEF_frame2 -borderwidth $BDwidth_frame2 frame .fRsliderG2 -relief $RELIEF_frame2 -borderwidth $BDwidth_frame2 frame .fRsliderB2 -relief $RELIEF_frame2 -borderwidth $BDwidth_frame2 frame .fRcanvas -relief $RELIEF_frame -borderwidth $BDwidth_frame ##+############################## ## PACK the top-level FRAMES. ##+############################## pack .fRbuttons \ .fRsliderR1 \ .fRsliderG1 \ .fRsliderB1 \ .fRsliderR2 \ .fRsliderG2 \ .fRsliderB2 \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRcanvas \ -side top \ -anchor nw \ -fill both \ -expand 1 ## OK. All frames are defined and packed. ## Now define the widgets within the frames. ##+################################################################ ## IN THE '.fRbuttons' frame - ## DEFINE the 'Exit' button --- and ## 2 radiobuttons (with a label button). ##+################################################################ button .fRbuttons.buttEXIT \ -text "$aRtext(buttonEXIT)" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {exit} ## Define label and 2 radiobuttons: label .fRbuttons.labDIR \ -text "$aRtext(labelDIR)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_button 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 ##+############################################## ## Pack ALL the widgets in the 'fRbuttons' frame. ##+############################################## pack .fRbuttons.buttEXIT \ .fRbuttons.labDIR \ .fRbuttons.radbuttX \ .fRbuttons.radbuttY \ -side left \ -anchor w \ -fill none \ -expand 0 ##+######################################################## ## In the FIRST 3 RGB 'slider' FRAMES - ## DEFINE a LABEL and a SLIDERBAR WIDGET in each one. ##+######################################################## set JUSTIFYlabel_scale left ## RED1 label .fRsliderR1.label \ -text "$aRtext(labelSCALEGRP1)" \ -width $scaleLabelWidthChars \ -font fontTEMP_varwidth \ -justify $JUSTIFYlabel_scale \ -anchor w \ -relief flat \ -bd $BDwidthPx_label scale .fRsliderR1.scale \ -orient h \ -digits 0 \ -from 0 -to 255 \ -length $scaleLengthPx \ -variable curR1 # -command {eval DrawGradient .fRcanvas.can $curDIRECTION \ # $curR1 $curG1 $curB1 $curR2 $curG2$curB2 } ## GREEN1 label .fRsliderG1.label \ -text "\ g1:" \ -width $scaleLabelWidthChars \ -font fontTEMP_varwidth \ -justify $JUSTIFYlabel_scale \ -anchor w \ -relief flat \ -bd $BDwidthPx_label scale .fRsliderG1.scale \ -orient h \ -digits 0 \ -from 0 -to 255 \ -length $scaleLengthPx \ -variable curG1 # -command {eval DrawGradient .fRcanvas.can $curDIRECTION \ # $curR1 $curG1 $curB1 $curR2 $curG2$curB2 } ## BLUE1 label .fRsliderB1.label \ -text "\ b1:" \ -width $scaleLabelWidthChars \ -font fontTEMP_varwidth \ -justify $JUSTIFYlabel_scale \ -anchor w \ -relief flat \ -bd $BDwidthPx_label scale .fRsliderB1.scale \ -orient h \ -digits 0 \ -from 0 -to 255 \ -length $scaleLengthPx \ -variable curB1 # -command {eval DrawGradient .fRcanvas.can $curDIRECTION \ # $curR1 $curG1 $curB1 $curR2 $curG2$curB2 } ##+######################################################## ## In the SECOND 3 RGB 'slider' frames - ## DEFINE a LABEL and a SLIDERBAR WIDGET in each one. ##+######################################################## ## RED2 label .fRsliderR2.label \ -text "$aRtext(labelSCALEGRP2)" \ -width $scaleLabelWidthChars \ -font fontTEMP_varwidth \ -justify $JUSTIFYlabel_scale \ -anchor w \ -relief flat \ -bd $BDwidthPx_label scale .fRsliderR2.scale \ -orient h \ -digits 0 \ -from 0 -to 255 \ -length $scaleLengthPx \ -variable curR2 # -command {eval DrawGradient .fRcanvas.can $curDIRECTION \ # $curR1 $curG1 $curB1 $curR2 $curG2$curB2 } ## GREEN2 label .fRsliderG2.label \ -text "\ g2:" \ -width $scaleLabelWidthChars \ -font fontTEMP_varwidth \ -justify $JUSTIFYlabel_scale \ -anchor w \ -relief flat \ -bd $BDwidthPx_label scale .fRsliderG2.scale \ -orient h \ -digits 0 \ -from 0 -to 255 \ -length $scaleLengthPx \ -variable curG2 # -command {eval DrawGradient .fRcanvas.can $curDIRECTION \ # $curR1 $curG1 $curB1 $curR2 $curG2$curB2 } ## BLUE2 label .fRsliderB2.label \ -text "\ b2:" \ -width $scaleLabelWidthChars \ -font fontTEMP_varwidth \ -justify $JUSTIFYlabel_scale \ -anchor w \ -relief flat \ -bd $BDwidthPx_label scale .fRsliderB2.scale \ -orient h \ -digits 0 \ -from 0 -to 255 \ -length $scaleLengthPx \ -variable curB2 # -command {eval DrawGradient .fRcanvas.can $curDIRECTION \ # $curR1 $curG1 $curB1 $curR2 $curG2$curB2 } ##+########################################################## ## Pack ALL the widgets in the 6 'fRslider' frames. ##+########################################################## ## We pack them separately in case we want to experiment with ## the pack parms, such as '-expand 1' on the scales. ############################################################# pack .fRsliderR1.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderR1.scale \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderG1.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderG1.scale \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderB1.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderB1.scale \ -side left \ -anchor w \ -fill none \ -expand 0 ## Pack the 2nd group of 3 scales. pack .fRsliderR2.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderR2.scale \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderG2.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderG2.scale \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderB2.label \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRsliderB2.scale \ -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.can \ -width $initCanWidthPx \ -height $initCanHeightPx \ -relief flat \ -highlightthickness 0 \ -borderwidth 0 pack .fRcanvas.can \ -side top \ -anchor nw \ -fill both \ -expand 1 ## OK. All widgets are defined and packed. ## Now define bindings and procs. ##+####################################################################### ## BINDINGS SECTION: ## - one for button1-release on each of the 6 scales ## - one for button1-release on each of the 2 radiobuttons ##+####################################################################### if {1} { bind .fRsliderR1.scale {DrawGradient \ .fRcanvas.can $curDIRECTION $curR1 $curG1 $curB1 $curR2 $curG2 $curB2} bind .fRsliderG1.scale {DrawGradient \ .fRcanvas.can $curDIRECTION $curR1 $curG1 $curB1 $curR2 $curG2 $curB2} bind .fRsliderB1.scale {DrawGradient \ .fRcanvas.can $curDIRECTION $curR1 $curG1 $curB1 $curR2 $curG2 $curB2} bind .fRsliderR2.scale {DrawGradient \ .fRcanvas.can $curDIRECTION $curR1 $curG1 $curB1 $curR2 $curG2 $curB2} bind .fRsliderG2.scale {DrawGradient \ .fRcanvas.can $curDIRECTION $curR1 $curG1 $curB1 $curR2 $curG2 $curB2} bind .fRsliderB2.scale {DrawGradient \ .fRcanvas.can $curDIRECTION $curR1 $curG1 $curB1 $curR2 $curG2 $curB2} ## button1 release bindings on 2 radiobuttons: bind .fRbuttons.radbuttX {DrawGradient \ .fRcanvas.can $curDIRECTION $curR1 $curG1 $curB1 $curR2 $curG2 $curB2} bind .fRbuttons.radbuttY {DrawGradient \ .fRcanvas.can $curDIRECTION $curR1 $curG1 $curB1 $curR2 $curG2 $curB2} } ## END OF 'if {1/0}' SECTION ## To easily disable the bindings. ##+###################################################################### ## PROCS SECTION: ## - 'DrawGradient' to fill the specified canvas according to the ## 7 parms --- x/y r1 g1 b1 r2 g2 b2 ##+###################################################################### ##+##################################################################### ## proc DrawGradient - ## ## PURPOSE: ## Draws the gradient on the canvas using canvas 'create line' ## commands. Draws vertical or horizontal lines according to ## the axis-specification: 'x' or 'y'. Interpolates between ## 2 RGB colors. ## ## CALLED BY: button1-release bindings on 6 scales and 2 radiobuttons, ## and in the additional-GUI-initialization section at ## the bottom of this script. ##+#################################################################### proc DrawGradient {win axis r1 g1 b1 r2 g2 b2} { global ENTRYstring # $win delete TAGgradient 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 { ## We could put the error msg on the end of the user-entry ## in the entry-field. # 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 - double($r1)}] set gRange [expr {$g2 - double($g1)}] set bRange [expr {$b2 - double($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 TAGgradient -fill "#$col" } else { $win create line 0 $i $width $i -tags TAGgradient -fill "#$col" } } } ## END OF proc 'DrawGradient' ##+##################################################### ## Additional GUI initialization, if needed (or wanted). ## ## We draw a gradient on the canvas, rather than letting the ## GUI come up with an empty canvas. ##+##################################################### ##+################################################################ ## Set the init values for the 2 radiobuttons and the 6 scales. ##+################################################################ set curDIRECTION "x" set curR1 255 set curG1 255 set curB1 0 set curR2 255 set curG2 0 set curB2 0 update ## 'update' is needed before DrawGradient so that the ## canvas width and height are implemented. ## DrawGradient uses 'winfo' to get those dimensions. DrawGradient .fRcanvas.can $curDIRECTION \ $curR1 $curG1 $curB1 $curR2 $curG2 $curB2 ====== Like I said at the bottom of the [A color-gradient-button-maker GUI] page: Make one enhancement to a Tk script and it leads to other enhancements or completely new scripts. It never ends. But, hopefully, this ends (at least for a few months) my attempts to make a better color-gradient-maker GUI. ______ [uniquename] 2012sep08 '''Update''': It did not end my attempts for long. See my [A color-gradient-button-maker GUI with 6 'miniscale' widgets] page. ------ [uniquename] 2012nov19 '''Update''': I am going through some of my old scripts making a few changes based on experiences gained over the past few months. Changes to this script: * Added braces to 9 'expr' statements. (Should increase the draw speed some. It might be feasible to use the '-command' option on the scale widgets, instead of the button1-release bindings.) * Provided more consistent indenting of the code (removed some whitespace from the front of many lines). * Touched up the comments to match the final code. * Added a text-array for text in labels,buttons,etc. --- to facilitate 'internationalization' of the GUI. * Improved calculation of 'minsize' of window. * Moved canvas from top of GUI to bottom. Replaced the code above with the tested script containing these changes. <> GUI | Graphics