- a SEMI-TRANSPARENT, SOLID-COLOR rectangle with TRANSPARENT CORNERSOR
- a SEMI-TRANSPARENT, NON-SOLID-COLOR rectangle (with optional TRANSPARENT CORNERS) --- by using the captured image as a 'mask'There is also a note in the comments that points out:For a variety of toolchests, the toolchests (at least ones in my software systems) will generally require a DIFFERENT WIDTH button/drawer FOR EACH TOOLCHEST.In that case, the various types of rounded rectangle files indicated above (SOLIDcolor-NONtransparent, SOLIDcolor-SEMItransparent, NONsolidColor-NONtransparent, NONsolidColor-SEMItransparent) could be STRETCHED-OUT (by any one of several means) to make images of the required width for each toolchest.___________________________________________________________________________As in all my other Tk scripts, I use a 'canonical' structuring of the code:
0) Set general window parms (win-name, win-position, win-color-scheme, fonts, widget-geometry-parms, win-size-control). 1) Define ALL frames (and sub-frames). Pack them. 2) Define and pack all widgets in the frames. 3) Define keyboard or mouse 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._____________________________________________________________I probably should point out a couple of changes that I made to the 'roundRect2' proc to make the 'DrawRoundRect' proc of this Tk Script. Namely:
- I changed the setting of X,Y (the location of the upper left corner of the rectangle) and the setting of W,H (the width and height of the rectangle) to be based on the current size of the canvas. - I fixed some offset calculations for the ovals and rectangles to fix a rectangle-slightly-off-center problem._________________________________________________________________As in all my scripts that use the 'pack' geometry manager (which is all of my 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. 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.One thing I did that some people might find disconcerting is that I have allowed the 'scale' widget to expand/contract in the x-direction as the window x-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.
Code for the Tk script 'makeRectangle_withRoundedCorners_solidColors.tk' :
#!/usr/bin/wish -f ## ## SCRIPT: makeRectangle_withRoundedCorners_solidColors.tk ## ## PURPOSE: This Tk GUI script facilitates the creation of ## rectangular solid-color images with rounded corners, ## on a canvas widget. ## ## The image consists of two colors - one color inside the ## rectangle (with round corners) and a different color ## outside the rounded rectangle. ## ## Such images can be useful in creating rounded wide buttons ## for 'toolchest' GUI's, for example. ## ## METHOD: The GUI contains a rectangular canvas widget on which the ## solid-color rectangle with rounded corners is drawn. ## ## The GUI includes a 'scale' widget whose slider-bar can ## be used to change the radius of the corners dynamically. ## That is, the 4 corners change radius as the slider-bar ## is dragged in either direction. ## ## The GUI also includes the capability to set the 2 colors ## of the image. (Any number of methods could be used to ## set the two colors: two entry fields OR 2 buttons which ## call on an external script to allow the user to set each ## color via a color-selector-GUI. We use the latter.) ## ## (A set of 6 spinboxes or 6 scales could be put on the GUI ## to set the RGB values of the 2 colors --- but those widgets ## take a lot of space on the GUI.) ## ## There is a '-command' parameter on the radius-setting 'scale' ## widget. That parameter is used to call a 'DrawRoundRect' proc ## to redraw the solid-colored rectangle with round corners --- ## as the sliderbar is used to change the value of a radius variable. ## ## The redraw includes redrawing 4 ovals (circular disks) and ## 2 rectangles on the canvas for each detected change in radius. ## ## Since erasing these items from the canvas and redrawing them ## completes within a very small fraction of a second, it is ## feasible to do the redraws 'dynamically' with the sliderbar. ## ## Currently the 'DrawRoundRect' proc works as follows. ## The rounded rectangle is centered in the canvas. ## The rectangle dimensions are set to a fixed percent of ## the dimensions of the canvas. Furthermore ... ## ## The '-fill' and '-expand' pack parameters are set so that ## the canvas expands/contracts as the window is increased or ## decreased in size. Hence the size (and aspect ratio) of the ## rounded rectangle is controlled by resizing the window. ## ## USING THE GENERATED IMAGE: ## A screen/window capture utility (like 'gnome-screenshot' ## on Linux) can be used to capture the GUI image in a GIF file, say. ## ## 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 image, with the outer-color only ## at the rounded corners --- or with a border of the outer-color ## all around the rectangle. ## ## Several 'use cases' for the captured-cropped image file: ## ## 1) The 2-color image could be used, directly, for the background of ## 'buttons'/'drawers' in GUIs such as 'toolchests'. ## ## 2) The 2-color image file could be used with a utility (like the ## ImageMagick 'convert' command) to change the outer color ## to transparent, making a partially transparent GIF ## (or PNG) file --- with the rounded corners being transparent. ## Then the SEMI-TRANSPARENT, SOLID-COLOR image file could be used ## for the background of 'buttons'/'drawers' in GUI's --- ## such as 'toolchests'. ## ## 3) The semi-transparent, solid-color image file from use-case 2 ## could be used as a *MASK* on a NON-SOLID-COLOR image file of ## the same size. ## A utility (like the ImageMagick 'convert' or 'composite' command) ## could be used to 'apply' the mask to the NON-solid-color image ## file, making a rounded-corner semi-transparent image file ## (GIF or PNG) from the NON-solid-color image. ## Then the SEMI-TRANSPARENT, NON-SOLID-COLOR image file could be ## used, for the background of 'buttons'/'drawers' in GUIs such as ## 'toolchests'. ## ## 4) For a variety of toolchests, the toolchests will generally ## require a DIFFERENT WIDTH button/drawer FOR EACH TOOLCHEST. ## In that case, the semi-transparent, NON-solid-color image file ## from use-case 3 could be STRETCHED-OUT (by any one of several means) ## to make a semi-transparent, NON-solid-color image of the required ## width for each toolchest. ## ## REFERENCE: ## http://wiki.tcl.tk/1416 - 'Drawing rounded rectangles' ## (downloaded 14aug 2012) ## Author: ??????? (and GNJ for alternate proc 'roundRect2') ## The original 'roundRect' proc approximated the rounded corners ## with polugons with small sides. The 'roundRect2' of GNJ draws ## the corners with 'create oval' commands on the Tk canvas widget, ## thus yielding higher-quality rounded corners. ## ##+###################################################################### ## 'CANONICAL' STRUCTURE OF THIS CODE: ## ## 0) Set general window parms (win-name,win-position,win-size-control, ## win-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. ## ## ## Some detail of the code structure for this particular script: ## ## 1a) Define ALL frames: ## ## Top-level : '.fRbuttons' and '.fRcan' ## ## 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 buttons (for setting the 2 colors), and ## 1 scale widget (with label widget) ## ## - In '.fRcan': one 'canvas' widget ## ## 3) Define bindings: none ## ## 4) Define procs: ## - 'DrawRoundRect' invoked when the scale widget sliderbar moves ## ## Variables calculated from current window size: ## X x-location of upper left corner of rectangle ## Y y-location of upper left corner of rectangle ## W width of the rectangle ## H height of the rectangle ## The rectangle is centered in the current window ## such that it occupies about 80% of the window. ## ## Global variables: ## curRADIUS radius of the 4 corners, from the scale widget ## CINhex color inside the rectangle ## COUThex color outside the rectangle ## ## - 'set_color_inside' shows a color selector GUI and uses the user-selected ## color to redraw the ovals & rectangles on the canvas ## in the specified color ## ## - 'set_color_inside' shows a color selector GUI and uses the user-selected ## color to reset the color of the canvas ## ## 5) Additional GUI initialization: Execute 'DrawRoundRect' once with ## an initial, example set of parms ## --- curRADIUS CINhex COUThex --- to start ## with a rounded rectangle on 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 ## after Tcl-Tk 8.4 was replaced by 8.5. ##+####################################################################### ## MAINTENANCE HISTORY: ## Created by: Blaise Montandon 2012aug14 ## Changed by: ...... ......... 2012 ##+####################################################################### ##+####################################################################### ## Set general window parms (title,position,size,color-scheme,fonts,etc.). ##+####################################################################### wm title . "Rectangle with Round Corners on a Canvas" wm iconname . "RoundRect" wm geometry . +15+30 ## We allow the window to be resizable and we pack the canvas with ## '-fill both -expand 1' so that the canvas can be enlarged by enlarging ## the window. The user can move the sliderbar of the scale widget ## to re-draw the color-filled rectangle on the canvas. ## 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 --- ## radiobuttons and spinboxes. ##+###################################################### tk_setPalette "#e0e0e0" # set entryBKGD "#f0f0f0" ## Initialize the 'inside' and 'outside' colors for the canvas. set CINr 255 set CINg 255 set CINb 255 set CINhex [format "#%02X%02X%02X" $CINr $CINg $CINb] set COUTr 0 set COUTg 0 set COUTb 0 set COUThex [format "#%02X%02X%02X" $COUTr $COUTg $COUTb] ##+######################################################## ## Use a variable-width font for label and button widgets ## --- and for scale labels. ## ## Use a fixed-width font for entry fields, if any. ##+######################################################## 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) ##+########################################################### set initCanWidthPx 400 set initCanHeightPx 300 set minCanHeightPx 24 # set BDwidthPx_canvas 2 set BDwidthPx_canvas 0 ## BUTTON (and LABEL) geom parameters: set PADXpx_button 0 set PADYpx_button 0 set BDwidthPx_button 2 ## SCALE geom parameters: set BDwidthPx_scale 2 set initScaleLengthPx 200 ##+###################################################### ## Set a minsize of the window. ## For width, allow for about 3 buttons (Exit,Color1,Color2) ## and scale label (Radius:) and length of slider bar. ## For height, allow for a canvas at least 24 pixels high ## and for the scale widget height below the ## canvas. ##+###################################################### set minWinWidthPx [font measure fontTEMP_fixedwidth \ "ExitInsideOutsideRadius"] ## Add some pixels to account for right-left-size window decoration ## (about 8 pixels), about 4x8 pixels for borders/padding for ## 4 buttons/labels, and about 200 pixels for the scale sliderbar. set minWinWidthPx [expr 240 + $minWinWidthPx] set minCharHeightPx [font metrics fontTEMP_fixedwidth -linespace] ## Allow 2 characters high for the scale widget, with its label area above ## the sliderbar, and about 28 pixels for top-bottom window decoration, ## about 8 pixels for frame borders and widget (button/label/scale) borders. ## And add in the min-canvas-height. set minWinHeightPx [expr $minCanHeightPx + 36 + 2 * $minCharHeightPx] ## FOR TESTING: # puts "minWinWidthPx = $minWinWidthPx" # puts "minWinHeightPx = $minWinHeightPx" wm minsize . $minWinWidthPx $minWinHeightPx ##+################################################################ ## DEFINE *ALL* THE FRAMES: ## ## Top-level : 'fRcan' , 'fRbuttons' ## ## Sub-frames: none ##+################################################################ # set BDwidth_frame 0 set BDwidth_frame 2 # set RELIEF_frame raised set RELIEF_frame flat frame .fRbuttons -relief $RELIEF_frame -borderwidth $BDwidth_frame frame .fRcan -relief $RELIEF_frame -borderwidth $BDwidth_frame ##+############################## ## PACK the 2 top-level FRAMES. ##+############################## pack .fRbuttons \ -side top \ -anchor nw \ -fill x \ -expand 0 pack .fRcan \ -side top \ -anchor nw \ -fill both \ -expand 1 ##+################################################################ ## IN THE '.fRbuttons' frame -- DEFINE the 'Exit' button --- also ## 2 radiobuttons (with a label button). ##+################################################################ button .fRbuttons.buttEXIT \ -text "Exit" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {exit} button .fRbuttons.buttCIN \ -text "\ Inside Color" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {set_color_inside} button .fRbuttons.buttCOUT \ -text "\ Outside Color" \ -font fontTEMP_varwidth \ -padx $PADXpx_button \ -pady $PADYpx_button \ -relief raised \ -bd $BDwidthPx_button \ -command {set_color_outside} ## Define label for the scale: label .fRbuttons.labelSCALE \ -text "\ Radius (pixels)" \ -font fontTEMP_varwidth \ -justify left \ -anchor w \ -relief flat \ -bd $BDwidthPx_button ## Set the init value for the scale var. set curRADIUS 25 # set scaleMaxUnits 200 # update # set scaleMaxUnits [expr [winfo height .fRcan.can] / 2] # set scaleMaxUnits [expr $initCanHeightPx / 2] set scaleMaxUnits $initCanHeightPx ## FOR TESTING: # puts "scaleMaxUnits: $scaleMaxUnits" scale .fRbuttons.scale \ -orient horizontal \ -digits 0 \ -from 0 -to $scaleMaxUnits \ -length $initScaleLengthPx \ -variable curRADIUS \ -command "DrawRoundRect .fRcan.can" ##+########################################### ## Pack the widgets in the 'fRbuttons1' frame. ##+########################################### pack .fRbuttons.buttEXIT \ .fRbuttons.buttCIN \ .fRbuttons.buttCOUT \ .fRbuttons.labelSCALE \ -side left \ -anchor w \ -fill none \ -expand 0 pack .fRbuttons.scale \ -side left \ -anchor w \ -fill x \ -expand 1 ##+############################### ## DEFINE-and-PACK CANVAS WIDGET: ##+############################### canvas .fRcan.can \ -width $initCanWidthPx \ -height $initCanHeightPx \ -relief raised \ -borderwidth $BDwidthPx_canvas pack .fRcan.can \ -side top \ -anchor nw \ -fill both \ -expand 1 ##+################################# ## END OF THE DEFINITION OF THE GUI ## --- frames and widgets. ##+################################# ##+################################# ## BINDINGS SECTION: none ##+################################# ##+############################################################### ## PROCS SECTION: three procs ## - DrawRoundRect - called by '-command' of the scale widget ## - set_color_inside - called by '-command' of a button widget ## - set_color_outside - called by '-command' of a button widget ##+############################################################### ##+##################################################################### ## proc DrawRoundRect: ## ## Draws a rounded rectangle in a canvas. ## ## Arguments: ## w - Path name of the canvas ## ## Global parms: ## ## curRADIUS - radius of the bend at the corners, in any form ## acceptable to Tk_GetPixels ## --- the variable for the scale widget ## ## tag - a tag for all the elements put on the canvas ## ## Calculated within this proc: ## ## X, Y - Co-ordinates of the upper left corner of the rectangle, in pixels ## W, H - width and height of the rectangle, in pixels ## ## X,Y,W,H are based on the current size of the canvas, based on: ## centering the rectangle in the canvas and ## making the width & height of the rectangle about 3/4 the ## width & height of the canvas. ## ## Based on the 'roundRect2' proc by GNJ = ? ## - Changed to calc X,Y,W,H based on the current size of the canvas. ## - Fixed some offset calcs for the ovals and rectangles ## to fix a slightly off-center problem. ##+##################################################################### ## We set a factor used to size the rectangle within the canvas. # set rectFactor 0.8 set rectFactor 0.6 ## We put the name of the tag in a variable rather than ## hard-coding the tag name on the 'create oval' and ## 'create rectangle' statements. set geomTAG canElement proc DrawRoundRect {w rad} { ## NOTE: The '-command' parm of the 'scale' widget passes ## the current value of the scale to the proc it calls. ## We need the 'rad' argument as a place holder to ## avoid a syntax error. ## ## We hold the current value of the scale in the global ## var 'curRADIUS', and use that var in the ## 'set_color_inside' proc as well as in this proc. global curRADIUS geomTAG rectFactor CINhex COUThex set canWidth [winfo width $w] set canHeight [winfo height $w] set W [expr $canWidth * $rectFactor] set H [expr $canHeight * $rectFactor] set X [expr ( $canWidth - $W ) / 2 ] set Y [expr ( $canHeight - $H ) / 2 ] set diam [expr 2 * $curRADIUS] ## Delete all the tagged items on the canvas. $w delete $geomTAG ## Create the upper-left round corner - a disk $w create oval \ $X $Y \ [expr $X + $diam] [expr $Y + $diam] \ -fill $CINhex -outline $CINhex -tag $geomTAG ## Create the upper-right round corner - a disk $w create oval \ [expr ($X + $W) - $diam] $Y \ [expr $X + $W] [expr $Y + $diam] \ -fill $CINhex -outline $CINhex -tag $geomTAG ## Create the lower-left round corner - a disk $w create \ oval $X [expr ($Y + $H) - $diam] \ [expr $X + $diam] [expr $Y + $H] \ -fill $CINhex -outline $CINhex -tag $geomTAG ## Create the lower-right round corner - a disk $w create oval \ [expr $X + $W - $diam] [expr ($Y + $H) - $diam] \ [expr $X + $W] [expr $Y + $H] \ -fill $CINhex -outline $CINhex -tag $geomTAG ## Create the vertical-strip rectangle - up the middle of the interior $w create rectangle \ [expr $X + $curRADIUS] $Y \ [expr $X + $W - $curRADIUS] [expr $Y + $H] \ -fill $CINhex -outline $CINhex -tag $geomTAG ## Create the horizontal-strip rectangle - across the middle of the interior $w create rectangle \ $X [expr $Y + $curRADIUS] \ [expr $X + $W] [expr $Y + $H - $curRADIUS] \ -fill $CINhex -outline $CINhex -tag $geomTAG } ## END OF proc DrawRoundRect ##+##################################################################### ## proc 'set_color_inside' ##+##################################################################### ## 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 the color of all the tagged items ## (ovals and rectangles) on the canvas. ## ## Arguments: none ## ## CALLED BY: .fRbuttons.buttCIN button ##+##################################################################### proc set_color_inside {} { global CINr CINg CINb CINhex curRADIUS # global feDIR_tkguis ## FOR TESTING: # puts "CINr: $CINr" # puts "CINg: $CINg" # puts "CINb: $CINb" set TEMPrgb [ exec \ ./sho_colorvals_via_sliders3rgb.tk \ $CINr $CINg $CINb] # $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 ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" set CINhex "#$hexRGB" ## Call proc roundRect to redraw the geometry in the new interior color. DrawRoundRect .fRcan.can $curRADIUS } ## END OF proc 'set_color_inside' ##+##################################################################### ## proc 'set_color_outside' ##+##################################################################### ## 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 the color of the canvas --- ## on which all the tagged items (ovals and rectangles) lie. ## ## Arguments: none ## ## CALLED BY: .fRbuttons.buttCOUT button ##+##################################################################### proc set_color_outside {} { global COUTr COUTg COUTb COUThex # global feDIR_tkguis ## FOR TESTING: # puts "COUTr: $COUTr" # puts "COUTg: $COUTb" # puts "COUTb: $COUTb" set TEMPrgb [ exec \ ./sho_colorvals_via_sliders3rgb.tk \ $COUTr $COUTg $COUTb] # $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 ## FOR TESTING: # puts "TEMPrgb: $TEMPrgb" set COUThex "#$hexRGB" ## Set the color of the canvas. .fRcan.can config -bg $COUThex } ## END OF proc 'set_color_outside' ##+##################################################### ## Additional GUI initialization, if needed (or wanted). ##+##################################################### DrawRoundRect .fRcan.can $curRADIUS .fRcan.can config -bg $COUThex
Now I have a way to make rounded-button 'masks' to use with the 'IMAGEtools' utilities in my 'feNautilusScripts' system --- to make rounded rectangles to use as background images in the 'drawers' and 'toolchests' of my 'feAppMenus' and 'feHandyTools' systems.As I mentioned at the bottom of the Experiments in making embellished GUI's page, perhaps we can start a gallery page showing some particularly well-embellished toolchests/GUI's ...Or perhaps a gallery page of particularly nice buttons and backgrounds and icons that can be used by Tcler's for backgrounds/embellishments in their GUI's.