Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

save the contents of a text widget to a file?

15 views
Skip to first unread message

Operator

unread,
Apr 5, 1996, 3:00:00 AM4/5/96
to
I am trying to create a text widget for editing and save the contents on to a file. Haven't been able to. Below is the program that I have written to accomplish the same. Please let mw know where i am going wrong.


#!/usr/local/bin/wish4.1 -f
text .text -relief raised -bd 2 -yscrollcommand ".scroll set"
scrollbar .scroll -command ".text yview"
pack .scroll -side right -fill y
pack .text -side left

set f [open "text.output" "w"]
puts $f [.text get 1.0 end] ;
close $f


thanks
uday

Wayne Throop

unread,
Apr 13, 1996, 3:00:00 AM4/13/96
to
: ro...@ss10.retix.com (Operator)
: Message-ID: <4k46t6$7...@ss10.retix.com>
: I am trying to create a text widget for editing and save the contents

The main problem here is a misunderstanding about the flow of control
between X events and the tcl script itself. Tcl scripts are read through
to the end, and then the X event loop processes mouse clicks and keystrokes
and suchlike. This means that the file "text.output" gets written after
the text widget is created, but before any text is typed/moused into it.

A simple solution is to put the action that saves the text into
a binding, so that the text window is saved iff it is deleted:

# you'd think this'd work, but it doesn't
bind .text <Destroy> {


set f [open "text.output" "w"]

puts $f [.text get 1.0 end] nonewline
close $f
destroy .
}

Unfortunately, the ".text" command has already been deleted during the
destroy event processing, so you can't retrieve the text with [.text get ],
so the above doesn't actually work. You have to do something like

# this is horrible, but it works
frame .text.kludge
bind .text.kludge <Destroy> {


set f [open "text.output" "w"]

puts $f [.text get 1.0 end] nonewline
close $f
destroy .
}

This works, because asking the window manager to quit the window
causes "destroy" processing to occur children-first. Ugh, but it works.
( Hmmmm. There's presumably a better way, but I don't happen to know it.
Anybody else? Has this been addressed in recent releases (I've avoided
exploiting recent features for various reasons.) )

Note the "nonewline" so that the file will have exactly what the
widget contained, no more, no less. Well, actually, the phantom newline
in newer tk text widget semantics means that should be

puts $f [.text get 1.0 end-1char] nonewline

IFF $tk_version>=4.0. Sigh.

Of course, something like

pack [button .save -text save -command {


set f [open "text.output" "w"]

puts $f [.text get 1.0 end-1char] nonewline
close $f
}] -before .text -side top

(or, more likely eventually, a simple menubar), would perhaps be
better than unconditionally writing upon exit, though you might want
to put a dialogue into the <Destroy> to see if the file has been saved....

Combining all this and a few frills, here's a little proc that can be
used to pop up a simple edit box on a file. (excuse the brace-matching style}

proc endindex {} {
global tk_version
if $tk_version>=4.0 {return end-1char} {return end}
}
proc editfile {w f} {
# create the window if it doesn't exist,
catch {toplevel $w
pack [text $w.text -yscrollcommand "$w.scroll set"] -side left
pack [scrollbar $w.scroll -command "$w.text yview"
] -side right -fill y
pack [button $w.save -text save -command [
format {exec cat << [%s.text get 1.0 [endindex]] > %s} \
$w [list $f]]
] -before $w.text -side top
$w.text insert 1.0 [exec -keepnewline cat $f]}
# and bring it up from background or iconic state if it does
catch {wm iconify $w
wm deiconify $w}
}

The above is a rather cryptic, compressed style, since I'm cramming
things in to avoid having to write procs as much as possible. For example,
read-file and write-file routines would perhaps make the text handling
between widget and file a bit less peculiar, and the "format" trick to
get proper behavior for the two levels of substitution required is
a bit obscure, but saves writing a proc for the button command.

In other words, this is illustrating the principles in working code, but
restricting myself to vanilla tcl primitives, for exposition sake. I
did, however, finesse the what-is-the-last-char problem by coining a new
proc, so I can't be accused of consistency, either.

It can, of course, be improved, by allowing optional settings of style
and size and font-choice and so on to be passed through to the widgets,
or by allowing more operations besides "save" (eg, a menubar), or by
allowing a file-select dialogue upon save (a save-as menu item), or
specification of extra keybindings for editing convenience, and
so on and on and on. But it's small, and it works, and it
illustrates several important principles.

On the other hand, so does

exec $env(EDITOR) $f &

(or if it's a non-X-aware editor, say vi, then maybe

exec xterm -e $env(EDITOR) $f &
--
Wayne Throop throopw%sheol...@dg-rtp.dg.com
thr...@aur.alcatel.com

0 new messages