frame .toolbar
pack .toolbar -side top -fill x -expand no
button .toolbar.save -text "save" -command doSave -bd 1
pack .toolbar.save -side left
text .text
pack .text -side top -fill both -expand yes
rename .text .text_
proc .text {command args} {
global textModified
# let the real text widget do all the real work
set result [uplevel .text_ $command $args]
if {[string equal $command "insert"] \
|| [string equal $command "delete"]} {
set textModified 1
}
return $result
}
proc doSave {} {
global textModified
# pretend we've saved the text...
# reset the state
set textModified 0
}
proc updateUI {args} {
global textModified
if {$textModified} {
.toolbar.save configure -state normal
} else {
.toolbar.save configure -state disabled
}
}
trace variable textModified w updateUI
set textModified 0Man, I love writing tcl, but sure do miss writing Tk. Tk is just sooooo nice! I literally haven't written this much tk code in a year :-(See also ANSI color control for a value-added text widget - Arts and crafts of Tcl-Tk programming
D. McC: Now, about that "modified" flag (which came in with Tk 8.4) in the text widget--here's an example of usage. I bind the <Key> and <Button-2> events to execute this "saveup" procedure:
proc saveup {} {
if { [.textinhere edit modified] } {
bind .textinhere <Key> {}
bind .textinhere <Button-2> {}
wmtitulo save
}
}All this does is to (1) stop the bindings from firing needlessly and (2) invoke a procedure ("wmtitulo save") to display a "Save Changes?" indicator on the titlebar. Then, when the contents of the text widget (.textinhere) are saved and the "Save Changes?" indicator vanishes, the "modified" flag is set to zero:.textinhere edit reset .textinhere edit modified 0
MDD: A much simpler approach: (i.e., simpler than my old approach, which I've now deleted in favor of what's above) -- D. McC)
set changed 0
bind .your.text.widget <Any-KeyRelease> {set changed 1}
...
if {$changed == 1}{Save_File_Proc; set changed 0}Of course, this will give a false positive if you use non-editing keys in the text widget, such as moving the cursor with the arrow keys, but it's not a bad quick-and-dirty solution.It also doesn't catch instances where your code adds text to the widget via some other means, such as selecting "paste" from a pulldown menu.MDD: Right. That's the "dirty" part. ;-)Would you get around that with: bind .your.text.widget $event {set changed 1}That would propably mean even more false positives, though.
Ctext provides an edit modified command; which can be used to tell if data has been inserted/deleted. It also works with the 8.3 and possibly 8.1 Tcl/Tk releases.
ABU 19-oct-2005Other than the "modified" flag, the text widget also generates a virtual event <<Modified>>. Here an excerpt from the command reference manual:
- THE MODIFIED FLAG
- The text widget can keep track of changes to the content of the widget by means of the modified flag. Inserting or deleting text will set this flag. The flag can be queried, set and cleared programatically as well. Whenever the flag changes state a <<Modified>> virtual event is generated. See the edit modified widget command for more details.
# DEMO
pack [text .txt]
set feedbackMsg "No Changes"
proc resetModifiedFlag {w} {
global feedbackMsg
$w edit modified false
set feedbackMsg "No Change"
}
button .b1 -text reset -command "resetModifiedFlag .txt"
label .l1 -textvariable feedbackMsg -bg red
pack .b1 .l1 -side left -expand 1
# load some data ...
.txt insert end "aaa\nbbb\nccc"
# reset modified-flag
resetModifiedFlag .txt
bind .txt <<Modified>> { bell ; set feedbackMsg "Changed !" }
# start playing ...Blendernut Just what i needed. Thank you ABU.
WJG (17/03/06) I tried using the above binding in an app which has been starpacked. The <<Modify>> event didn't work. Anyone any ideas why not? The starpack is for Tk8.5a.MG The binding is <<Modified>>, not <<Modify>> like you said there. Check and make sure you're using the right one in your code?
