jnc Dec 2, 2009 - Tk currently lacks a multiline entry widget. The text widget is a great widget but a bit complex if you just need a multiline plain text widget that acts like entry.
This is one of many solutions on the wiki. This solution includes support for:
snit::widget multiline_entry { delegate option * to text delegate method * to text # On/Off options option -yscroll -default yes option -xscroll -default no option -allowtab -default no option -readonly -default no # Miscellaneous options option -textvariable -default 0 constructor { args } { install text using text $win.txt grid $win.txt -row 0 -column 0 -sticky nswe $self configurelist $args if { [$win cget -yscroll] } { $win.txt configure -yscrollcommand [list $win.vsb set] ttk::scrollbar $win.vsb -command [list $win.txt yview] grid $win.vsb -row 0 -column 1 -sticky nsw } if { [$win cget -xscroll] } { $win.txt configure -xscrollcommand [list $win.hsb set] ttk::scrollbar $win.hsb -orient horizontal -command [list $win.txt xview] grid $win.hsb -row 1 -column 0 -sticky we } grid rowconfigure $win 0 -weight 1 grid columnconfigure $win 0 -weight 1 if {[$win cget -textvariable] != 0} { set varName [$win cget -textvariable] upvar 3 $varName v $win.txt insert 1.0 $v $win.txt mark set insert 1.0 trace add variable v write [list $self setContent] trace add variable v read [list $self getContent] } bind $win <FocusIn> [list focus $win.txt] if { !$options(-allowtab) } { bind $win.txt <Shift-Tab> [list $self focusPrev] bind $win.txt <Tab> [list $self focusNext] } if { $options(-readonly) } { bind $win.txt <KeyPress> break bind $win.txt <ButtonRelease-2> break bind $win.txt <Down> continue bind $win.txt <Up> continue bind $win.txt <Prior> continue bind $win.txt <Next> continue bind $win.txt <Left> continue bind $win.txt <Right> continue } } method getTextWidget {} { return $win.txt } method focusPrev {} { focus [tk_focusPrev $win] return -code break } method focusNext {} { focus [tk_focusNext $win.txt] return -code break } method setContent { name element op} { upvar 1 $name x $win.txt delete 1.0 end if { [array exists x] } { $win.txt insert 1.0 $x($element) } else { $win.txt insert 1.0 $x } } method getContent { name element op } { upvar 1 $name x if { [array exists x] } { set x($element) [$win.txt get 1.0 "end-1 char"] } else { set x [$win.txt get 1.0 "end-1 char"] } } }
jnc Dec 21, 2009 - Added a -readonly option, however, it also prevents keyboard navigation. Any better ideas?
WHD Redefine the "insert" and "delete" subcommands so that they do nothing if -readonly is true. Then, the Text bindings that change the content of the widget will have no effect. To be really fancy, define your own -state option with three values, "normal", "disabled", and "readonly"; pass the first two along to the hull and set your readonly flag for the third.
Bezoar I rewrote the above widget using TclOO Multi-line TclOO Text Entry Widget just to see how hard it would be to convert between the two. Turns out it was very easy. I did add some features that don't exist in this version. First all option not recognized by the Widget get sent to the internal text widget so you get the -state option mentioned above by WHD for free. I also corrected the fact that you could still cut and paste into a readonly widget and finally when -xscroll = 1 I also shut off wrapping in the text widget otherwise it is useless. I have some test code at the afore mentioned page to test the widget.
jnc Sep 15, 2010 - Updated code, includes better readonly support (keyboard navigation) and no mouse paste ability. Handling of getting/setting via array.