WJG (2nd January 2005) The various widget libraries around seem to lack a multi-line entry widget. So, seeing as I needed one earlier this week, I cooked up the following offering. The multiline facility is, of course, a text widget. The problem lies in using a text widget like an entry which has a text variable. I got round this matter with a crafty use of pathnames.
Here's the code, I hope that the demo procs illustrate its use.
############################################ # # LabelText.tcl # ------------------------ # # Copyright (C) 2005 William J Giddings # email: [email protected] # ############################################ # # Description: # ----------- # Provide mutliline entry widget. # # Args: # ---- # # base the full pathname of the megawidget. # args # # returns returns the pathname of megawidget created # # Accessing Label and Text Components: # ----------------------------------- # # Note: # ---- # The name of the variable associated witht the text widget is # integrated into the name of the ** TEXT ELEMENT ** of the megawidet. # If there are any changes to the variable, or text, a trace is called # and the name of the variable is then used to modify the content of the # associated widget. # # The assumption made is that this widget will be primarily used as a # form centred multi-line entry widget rather than a text editing box. # Under such cases, a textvariable should always be used. # # Ensure that textvariable exists prior to creations of the widget. # # Caveats: # ------- # This widget has only been tested using array variables in the global # namespace, consequently, some issues may arise if a custom # namespace is used. # # The widget is effectively "hard-coded" to a particular textvariable. # Whilst this is the expected case for most uses of the widget, some code # modification would be required to enable the change of tectvariable to be # reflected in the full pathanme of the text element itself. # # Should any change be made then perhaps the existing text element needs # to be replaced with one in which the textvariable name included in the pathname. # Following this, all bindings and traces need to be unset for the old textvariable # and new bindings and traces set for the new tracevariable. # # No effort has been made to trace array calls to the textvariable. # ############################################ proc LabelText {base {args {}}} { #set default values set txtargs "" set labargs "" set txtpack "" set labpack "" #parse arguments, assign to label/text components foreach {arg val} $args { switch -- $arg { -relief {append frargs " $arg $val " } -borderwidth {append frargs " $arg $val " } -labelfont {append labargs "-font \{$val\} " } -labelwidth {append labargs " -width $val "} -labelheight {append labargs " -height $val "} -labeltext {append labargs " -text \{$val\} "} -labeljustify {append labargs " -justify $val "} -labeltextanchor {append labargs " -anchor $val "} -labelbg - -labelbackground {append labargs " -background $val "} -labelfg - -labelforeground {append labargs " -foreground $val "} -labeltextvariable {append labargs " -textvariable $val" } -labelside { append labpack " -side $val " append txtpack " -side $val " } -labelanchor { append labpack " -anchor $val " append txtpack " -anchor $val " } -width - -height - -background - -foregroung - -bg - -fg - -font {append txtargs " $arg \{$val\} "} -textvariable { #todo: Create variable if one does not exist set variable $val set a $variable puts $a trace add variable ::$a {write unset} _$a set ::${a}_ $base.$variable ################################################### #create bespoke trace handler ################################################### proc _$a {name i op} { # args passed to the fucntion # name variable name # i array index # op operation #upvar 1 $name var if {$::DEBUG} { puts ">> name: $name i: $i op: $op" #puts "[set ::${name}(${i})_]" } #deal with unset variables if { $op == "u" } { if { $i != {} } { rename _$name {} } else { rename _${name}(${i}) {} } return } #assuming variable to be an array, ie $i != NULL if {$i != {} } { #variable is and array [set ::${name}(${i})_] delete 1.0 end [set ::${name}(${i})_] insert end [set ::${name}(${i})] } else { #simple variable [set ::${name}_] delete 1.0 end [set ::${name}_] insert end [set ::${name}] } } ;#end proc ################################################### } ;# end textvariable block } ;#end switch } ;#end foreach # build megawidget eval frame $base $frargs eval label $base.lab $labargs eval pack $base.lab $labpack eval text $base.$variable $txtargs eval pack $base.$variable $txtpack -in $base if {$::DEBUG} { bind "$base.$variable" <Button-1> { # get variable name set tmp %W puts "%W -- [winfo parent %W]" puts "%W -- [winfo pathname [winfo id %W]]" puts [lindex [split %W .] end] } } #update variable when focus is lost bind "$base.$variable" <FocusOut> { set a [%W get 1.0 end] set b [lindex [split %W .] end] #if {$::DEBUG} { puts "a = $a b = $b \n[set $b]" } #remove any blank lines set $b [string trimright [string trimleft $a]] } #return location return $base } ################################################################################ # Demo Block ################################################################################ set ::DEBUG true proc LabelTextDemo_1 {{base {}} } { if {$::DEBUG} { console show } LabelText $base.lt1 \ -relief raised \ -borderwidth 2 \ -labeltext "Prime Minister's\nAddress" \ -labelanchor nw \ -labeltextanchor nw \ -labelside left \ -labelwidth 15 \ -labeltextvariable var1 \ -labeljustify left \ -textvariable pm_address \ -background #ffffdd \ -width 20 \ -height 7 \ -istitle 1 pack $base.lt1 -fill both -expand 1 LabelText $base.lt2 \ -relief raised \ -borderwidth 2 \ -labeltext "Chancellor's\nAddress" \ -labelanchor nw \ -labeltextanchor nw \ -labelside left \ -labelwidth 15 \ -labeltextvariable var2 \ -labeljustify left \ -textvariable ce(address) \ -width 20 \ -height 7 \ -istitle 1 pack $base.lt2 -fill both -expand 1 } proc LabelTextDemo_2 {} { toplevel .form wm title .form "LabelText Demo" LabelTextDemo_1 .form pack [button .b1 -text "Tony Blair" -command {set ::pm_address "10 Downing St.,\nLONDON"}] -fill x pack [button .b2 -text "Gordon Brown" -command {set ::ce(address) "11 Downing St.,\nLONDON"}] -fill x pack [button .b3 -text "puts pm_address" -command {puts $pm_address } ] -fill x pack [button .b4 -text "puts ce(address)" -command {puts $ce(address) } ] -fill x pack [button .b5 -text "unset pm_address" -command {unset pm_address } ] -fill x pack [button .b6 -text "unset ce(address)" -command {unset ce(address) } ] -fill x set ::ce(address) "11 Downing St.,\nLONDON" set ::pm_address "10 Downing St.,\nLONDON" } LabelTextDemo_2
See also: Multiline expanding entry widget, Multi-Line Text Entry Widget - With Entry Widget Like Field To Field Tabbing and Multi-Line Entry Widget in Snit.
The GRIDPLUS2 text command creates a widget that can be used as a "Multi-Line Text Entry".