GPS May 27, 2002: I wanted an extended entry box that provides by default copy, paste, cut, and append options via a popup menu. I also wanted the ability to restrict the data entered to a RE pattern. The solution below provides a modified entry widget that does all of the above. It is standalone, but does use one of the binding procs from the Inheriting Widget Binding Classes page.
#Updated Aug 7, 2002 to fix minor bugs and introduce paste primary proc bind:copyClass {class newClass} { set bindingList [bind $class] foreach binding $bindingList { bind $newClass $binding [bind $class $binding] } } proc widget:entry:copy {win type} { if {[$win index end] == 0 || [catch {$win index sel.first}]} { return } if {[catch {selection get -displayof $win -selection $type -type STRING} data]} { return } clipboard clear -displayof $win clipboard append -displayof $win $data } proc widget:entry:paste {win type} { if {[catch {selection get -displayof $win -selection $type -type STRING} data]} { return } $win insert insert $data } proc widget:entry:cut {win type} { if {[catch {$win index sel.first}]} { return } if {[catch {selection get -displayof $win -selection $type -type STRING} data]} { return } $win delete sel.first sel.last clipboard clear -displayof $win clipboard append -displayof $win $data } proc widget:entry:append {win type} { if {[$win index end] == 0 || [catch {$win index sel.first}]} { return } if {[catch {selection get -displayof $win -selection $type -type STRING} data]} { return } clipboard append -displayof $win $data } proc widget:entry:clear {win} { $win delete 0 end } proc widget:entry:event:ButtonPress-3 {win X Y} { destroy $win._popup set m [menu $win._popup -tearoff 0] #valid types are PRIMARY and CLIPBOARD $m add command -label Copy -command "widget:entry:copy $win PRIMARY" $m add command -label "Paste Primary" -command "widget:entry:paste $win PRIMARY" $m add command -label "Paste Clipboard" -command "widget:entry:paste $win CLIPBOARD" $m add command -label Cut -command "widget:entry:cut $win PRIMARY" $m add command -label Append -command "widget:entry:append $win PRIMARY" $m add command -label Clear -command "widget:entry:clear $win" tk_popup $m $X $Y } proc widget:entry:instanceCmd {win args} { upvar #0 widget:entry$win inputRegexp set cmd [lindex $args 0] set useInputRegexp 0 set isInsert 0 if {[string length $inputRegexp] > 0} { set useInputRegexp 1 } if {[string equal $cmd "insert"]} { set isInsert 1 } if {$isInsert && $useInputRegexp} { set data [lrange $args 2 end] set valid 1 foreach char [split $data ""] { if {[regexp $inputRegexp $char] <= 0} { set valid 0 break } } if {$valid} { return [uplevel 2 widget:entry:origCmd$win $args] } } else { return [uplevel 2 widget:entry:origCmd$win $args] } } proc widget:entry {win args} { upvar #0 widget:entry$win inputRegexp set inputRegexp "" if {[set pos [lsearch $args "-inputregexp"]] > -1} { set posRe [expr {$pos + 1}] set inputRegexp [lindex $args $posRe] set args [lreplace $args $pos $posRe] } eval entry [concat $win $args] bind:copyClass Entry Widget:Entry bind Widget:Entry <ButtonPress-3> {widget:entry:event:ButtonPress-3 %W %X %Y} #use our new binding class bindtags $win "$win Widget:Entry all" rename $win widget:entry:origCmd$win proc $win {args} "eval widget:entry:instanceCmd $win \$args" return $win }
#BEGIN test code proc checkIP {win clientData} { set RE {[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}} set data [$win get] set result 1 if {[regexp $RE $data] > 0} { foreach num [split $data .] { if {$num < 0 || $num > 255} { set result 0 break } } } else { set result 0 } eval [concat $clientData $result] } proc main {} { pack [widget:entry .e -inputregexp {[0-9\.]} -width 20] .e insert end abc ;#should fail pack [frame .info] -side left -fill x pack [label .info.valid -text "Valid: "] -side left pack [label .info.bool -text 0] -side left #I could use a textvariable but this works pack [button .checkIP -text "Check IP" -command "checkIP .e {.info.bool config -text}"] pack [button .exit -text Exit -command exit] } main