Tk FAQ for Tcl 7.5+ && Tk 4.1+
This FAQ will address commonly asked questions about usage of the Tk Toolkit (version 4.1+). By providing answers to commonly asked questions in this document, it is hoped that new users of Tk may suffer less frustration getting started with Tk, and that readers of news:comp.lang.tcl may suffer less frustration reading/answering these questions repeatedly.
For Tk 3 related questions, see the Tk 3 Usage FAQ (http://www.cs.uoregon.edu/research/tcl/faqs/tk/tk3.txt).
This FAQ is posted monthly to news:comp.lang.tcl, comp.answers, and news.answers and can also be obtained from the Tcl FTP archive (206.109.1.6) (ftp://ftp.neosoft.com/pub/tcl/) in the /pub/tcl/FAQ directory.
For additional information on Tcl as well as pointers to other documentation and code, see the FAQ maintained by Larry Virden (mailto:lvirden@cas.org):
FAQ: news:comp.lang.tcl Tcl Introductory FAQ (http://www.teraform.com/~lvirden/tcl-faq/part1.html)which resides on the Tcl FTP archive (ftp://ftp.neosoft.com/pub/tcl/) as /pub/tcl/FAQ/tcl-faq.part0*.
For information on usage of the Tcl programming language, see the posting by Joe Moss (mailto:joe@morton.rain.com):
FAQ: news:comp.lang.tcl Tcl Language Usage FAQ (http://route.psg.com/tcl.html)which resides on the Tcl FTP archive (ftp://ftp.neosoft.com/pub/tcl/) as /pub/tcl/FAQ/tcl-faq-usage.
For additional information about using Tk on Windows, see the posting by Eric Johnson (mailto:johnsone@camax.com):
FAQ: news:comp.lang.tcl Tk Windows Usage FAQ (http://ourworld.compuserve.com/homepages/efjohnson/tclwin.htm)which resides on the Tcl FTP archive (ftp://ftp.neosoft.com/pub/tcl/) as /pub/tcl/FAQ/tk-usage-windows.
Comments, suggestions, and contributions to this FAQ are welcomed by Jeffrey Hobbs (mailto:jeff.hobbs@acm.org).
Legend:
Embedded code
(less than one line)
Multi-line code body
Last generated: Tue May 27 09:34:59 PDT 1997 by Jeffrey Hobbs (http://www.cs.uoregon.edu/~jhobbs/)
Click on the question to see its answer.
send
(I get security error
messages)?send
work on Windows/Mac?
canvas
widgets questionscanvas
performance?
canvas
?
canvas
seem to start at 0,0?
canvas
have a see
method?
entry
widgets questionslistbox
widgets questions.listbox curselection
or
selection get
return the proper item when I make a button
binding to my listbox?
menu
widget questionstext
widgets questions-data
option for images?
image
to work with
-stipple
?
cget
to return the correct size of a resized
widget?.widget cget -width|height
returns the wrong size!)
Tcl/Tk binaries are freely available for the Macintosh and Windows platforms at:
Windows: ftp://ftp.sunlabs.com/pub/tcl/win(version).exeand mirrored at:
Macintosh: ftp://ftp.sunlabs.com/pub/tcl/mactk(version).sea.hqx
ftp://ftp.neosoft.com/pub/tcl/mirror/ftp.smli.com/The sources are freely available from the same places. You can pay a nominal fee for precompiled UNIX binaries. See http://sunscript.sun.com/TclTkCore/ for more information. See the Tcl Home Page (http://sunscript.sun.com/) for a listing of the newest available versions.
Look in the Tcl distribution for the file called porting.notes. This will contain a collection of notes that various people have provided about porting Tcl to various machines and operating systems. There is also a file called README which should be read FIRST - before doing anything else with the code (this should always be one's first step with any package). Further, there is a changes file which details what has changed since the last release - be sure to read this to see what might need to change in your programs.
Did you run the configure program first (via sh ./configure or equivalent)? Without doing this, things such as strtoul or strerror are sometimes mentioned as missing.
Tcl includes equivalents for at least the following functions and include files which may not be found on some systems:
dirent.h limits.h stdlib.h string.h opendir.c strerror.c strstr.c strtol.c strtoul.c strtod.c
From ghowlett@fast.net (George A. Howlett) we get the answer:
Instead of adding TclX to blt_wish, try it the other way. Add BLT to wishx. It's pretty simple.
In the file ./<platform>/tkXAppInit.c, add the a call to the BLT initialization routine right after line 116.
if (TkX_Init(interp) == TCL_ERROR) { return TCL_ERROR; } if (Blt_Init(interp) != TCL_OK)) { return TCL_ERROR; }
Link wishx with libBLT.a and that's it.
Note: It is better to use the new dynamic loading capabilities of
Tcl7.5+. BLT2.1+ and TclX7.5.2+ have the ability to be dynamically loaded
modules. See their docs on building them as shared libraries and then see
the Tcl man page load
for loading it into the system at runtime.
The team at Sun have provided examples for building a dynamically loadable library for any supported Tk platform. You can find this at ftp://ftp.sunlabs.com/pub/tcl/example.{zip,tar.gz,tar.Z}.
They are distributed separate from the binaries and sources, but in the same FTP places:
ftp://ftp.sunlabs.com/pub/tcl/vclibs(version).zip
ftp://ftp.neosoft.com/pub/tcl/mirror/ftp.smli.com/vclibs(version).zip
Get the Tk porting notes from http://www.sunlabs.com/research/tcl/tk4.0.ps.
For Unix, most systems require a full pathname to the interpreter. So you cannot start a wish script out as
#!wish -f
Likewise, many Unix systems have a maximum length of characters that you can put on a #! line. If you exceed this, you do not get the behavior you expect. So do not try to put something like:
#!/projects/somethingbig/bin/sun4/wish -f
followed by your wish code. Keep the lines short - under 32 characters is recommended. Another option is the following:
#!/bin/sh # This line makes the next one a comment in Tcl \ exec /path/to/wish "$0" ${1+"$@"}
the /path/to/
is unnecessary if you know that wish is in the
user's path. Be careful to make sure that you are referencing the correct
version of wish. Tk4+ installs its libraries and executable with the
version number attached by default.
Read the documentation for the option
command.
Then you should consider something like the following - assume the program
name is xwf.
The following are two general purpose functions to put into a library:
# envVal envValName # Looks up the envValName environment variable and returns its # value, or {} if it does not exists proc envVal {envValName} { global env if [info exists env($envValName)] {return $env($envValName)} {return {}} } # loadAppDefaults classNameList ?priority? # Searches for the app-default files corresponding to classNames in # the order specified by X Toolkit Intrinsics, and loads them with # the priority specified (default: startupFile). proc loadAppDefaults {classNameList {priority startupFile}} { set filepath "[split [envVal XUSERFILESEARCHPATH] :] [envVal XAPPLRESDIR] [split [envVal XFILESEARCHPATH] :] /usr/lib/X11" foreach i $classNameList { foreach j $filepath { if {[file exists $j/$i]} { option readfile $j/$i $priority; break } } } }
Now, here is what you would put into xwf:
option add Tk.BoldFont "*-lucida sans-Bold-R-Normal-*-100-*" widgetDefault loadAppDefaults {xwf XWF} userDefault
This sets a program default, then load any defaults specified in the user's default resources and finally any site or general app-defaults resource. Of course, you would want to add some xwf command line handling to allow the user to override things at execution time.
Chris Milam contributes the following modification
of loadAppDefaults
which follows the X11R5 method of merging
app-default files from several sources.
# loadAppDefaults classNameList ?priority? # Searches for the app-default files corresponding to classNames in # the order specified by X Toolkit Intrinsics (R5), and loads them with # the priority specified (default: startupFile). proc loadAppDefaults {classNameList {priority startupFile}} { set lang [envVal LANG] if {[string length $lang] > 0} { set lang /$lang } set filepath " /usr/lib/X11${lang}/app-defaults [split [envVal XFILESEARCHPATH] :] [envVal XAPPLRESDIR]${lang} [split [envVal XUSERFILESEARCHPATH] :] " foreach i $classNameList { foreach j $filepath { if {[file exists $j/$i]} { option readfile $j/$i $priority; } } } }
Tk4 has a more Motif compliant look and feel (LAF). If you want a more conformant Motif LAF, put:
set tk_strictMotif 1
as close to the beginning of your program as possible. Tk reads that variable dynamically to determine whether it should maintain a strict Motif LAF.
Tk8 has native LAF for Windows and Mac. Tk8 uses the LAF of the system it is on without exception. You can get the Tk4 LAF only by modifying the core files to use the Unix widget counterpart code.
Tk strives to be Motif compliant and does not currently use either XView or Xt based widgets in its user interface, so an OpenLook compliant (or even similar) interface is probably not easily achievable in the near future.
Editor's note: who wants OpenLook?
You must use Tk8 to get native look and feel on Windows/Mac.
send
(I get security error
messages)?send
work on Windows/Mac?
Alternate forms of this question often mention that Tk send
is broken, or ask how to use xauth.
Since Tk 3.3, the X11 xauth security mechanism is used. While this
provides more security, it does require the user to do a bit more setup to
use the send
command. The man page for send
describes
how to solve this question for the average user. For those interested in
further reading on auth, look at
ftp://ftp.neosoft.com/pub/tcl/alcatel/docs/Xauthority.gz.
You can configure Tk to not depend on xauth by modifying Makefile.in to comment out the following:
# To turn off the security checks that disallow incoming sends when # the X server appears to be insecure, reverse the comments on the # following lines: #SECURITY_FLAGS = SECURITY_FLAGS = -DTK_NO_SECURITY
Note: It's not a good idea to disable security if security is an issue for you. You may want to consult your sysadmin before doing this.
Currently send
is not supported on the Mac or Windows platforms.
A beta DDE-based send
for Windows can be found at
http://www.sunlabs.com/~kcorey/tcldde.html. Hopefully this will be
included in the final Tk8 release.
Several simple examples have been posted to comp.lang.tcl. Eric Bleeker <ericbl@paramount.nikhefk.nikhef.nl> was gracious enough to package his up and place it at ftp://ftp.neosoft.com/pub/tcl/alcatel/code/tkHelloWorld*. This program assumes that you have installed the Tcl and Tk libraries, header files, etc.
Alternatively, you can look into creating a dynamically loadable library of your C code for Tcl/Tk. Sun has created some basic examples for all platforms at ftp://ftp.sunlabs.com/pub/tcl/example.{zip,tar.gz,tar.Z}.
If you start wish interactively and type:
puts [wm geometry .]
you will get something like:
200x200+90+90
The actual numbers may vary depending on X11 defaults, window managers, etc. If you put the same thing in a script, though:
#!/usr/local/bin/wish -f puts [wm geometry .]
You will instead get this:
1x1+0+0
This will happen because you are requesting geometry information before
the window has actually been drawn. In general, before you start asking
about window sizes, use the update
command so that the geometries
of the windows can be resolved. Changing the above script to this will give
the expected results:
#!/usr/local/bin/wish -f update puts [wm geometry .]
All default class bindings for Tk widgets are initialized in $tk_library/tk.tcl. Use this file as a guide to implement new bindings.
Give an empty-string command to the bind
invocation. For
example, to disable the Delete key in all entry fields:
bind Entry <Delete> {}
Also, see the documentation for the bind
and bindtags
commands. There are several ways to disable or modify which types of
bindings (instance, class, etc.) occur and the order in which they are
processed.
In Tk4.2+, there is an event
command which allows for the
specification of virtual event names, like <<Cut>>
. Tk4.2+ uses
these for bindings such as Cut/Copy/Paste. Deleting bindings from a virtual
event works like so:
event delete <<Cut>> <Control-x>
You have to call it <Left> rather than <R10>. Under X11,
keys are referred to by their keysym. One can use either xmodmap -pk
or the xev
program to determine what the keysym a particular key on a
keyboard is currently generating.
If the keysym that is being used is not known by Tk, you may have to edit its ks_names.h file. There is a note in this file that indicates that one should not edit it - but this is where the keysym must be for it to be recognized.
Some window managers, such as mwm, define mouse button bindings which cause Tk some problems. Try renaming your window manager's startup file (something like ~/.twmrc for instance) and copy in a startup file from a login id that works.
The binding model in Tk4 allows you to have bindings trigger for a widget instance without modifying that of the widget's class. The following example sets a global variable to the item which a user selects in a listbox without interfering with Tk's highlighting of that item:
bind .listbox <ButtonRelease-1> { set my_global [%W get [%W nearest %y]] }
If you want your binding on the widget instance to be the only event to
trigger (avoiding any possible class or all binding), then add a break
at the end of the binding, like so:
bind .listbox <Double-Button-1> { destroy %W; break }
If you still want to add to an existing binding, you need to have a
+
on the first line of the bind command, like so:
bind .listbox <Double-Button-1> {+ destroy %W; break }
See the documentation for bind
and bindtags
for more
information.
Tk2.1 and Xt have different X connections, and XtAppNextEvent will block if there is nothing coming from the X connection. One way of fixing this is get the connection number of Tk using
ConnectionNumber(Tk_Display(tk_window));
and using XtAddInput to register this with the Xt event handler. The callback procedure for XtAddInput wrapper procedure that runs Tk_OneEvent(1). There might be problems with Tk file sources which aren't registered with Xt.
Note: This information is out of date for the newest Tk (4.1+)
On Unix, the file /usr/include/X11/cursorfont.h for a list of
available cursors. You can use the names in there by removing the
XC_
. These same cursors are emulated on Windows/Mac.
Here's a little proc to make an entire application go busy while it's doing something. Just call it with the commands you want to execute, and the watch cursor will be displayed for the time it takes the commands to complete. Note that any new windows will have their normal cursor.
proc busy {cmds} { global errorInfo set busy {.app .root} set list [winfo children .] while {$list != ""} { set next {} foreach w $list { set class [winfo class $w] set cursor [lindex [$w config -cursor] 4] if {[winfo toplevel $w] == $w || $cursor != ""} { lappend busy [list $w $cursor] } set next [concat $next [winfo children $w]] } set list $next } foreach w $busy { catch {[lindex $w 0] config -cursor watch} } update idletasks set error [catch {uplevel eval [list $cmds]} result] set ei $errorInfo foreach w $busy { catch {[lindex $w 0] config -cursor [lindex $w 1]} } if $error { error $result $ei } else { return $result } }
The commands raise
and lower
are used to change a
window's position in the stacking order, as well as adjust toplevel windows
to be raised/lowered with respect to other windows.
wm withdraw <toplevel>
will take a window off the screen
without iconifying it.
wm iconify <toplevel>
will iconify a window (how it looks
iconified is up to the window manager).
wm deiconify <toplevel>
will remap or deiconify the window.
From faustus@CS.Berkeley.EDU (Wayne A. Christopher):
Create the Tk toplevel window but don't map it
(wm withdraw .toplevel
). Then re-parent the window to be a
subwindow of your other one and then map it. I have done this when the Tk
application is a separate process, but if it's the same process I think you
will get into trouble with the event loop, since each toolkit wants
control.
Note: Tk8 provides better access to this functionality, a spin-off from making the Tk plugin work.
Tk has a new event loop which provides easier interaction than previous answers dictated. The following answer is provided by Paolo Brutti (gi0570@rh0015.roma.tlsoft.it):
void XtEventSetup(ClientData xtconn, int flags) { static Tcl_Time maxDelay={0, 300000}; /* To process non-X events */ Tcl_WatchFile((Tcl_File)xtconn, TCL_READABLE); Tcl_SetMaxBlockTime(&maxDelay); } int XtDoEvent(Tcl_Event *evPtr, int flags) { while (XtPending()) XtProcessEvent(XtIMAll); return 1; } void XtEventCheck(ClientData xtconn, int flags) { Tcl_Event *event; if(XtPending()) { event = (Tcl_Event *)ckalloc(sizeof(Tcl_Event)); event->proc = XtDoEvent; Tcl_QueueEvent(event, TCL_QUEUE_TAIL); } } void tkGo (void) { extern Widget topLevel; Tcl_File xtconn; int xtfd = ConnectionNumber(XtDisplay(topLevel)); xtconn = Tcl_GetFile((ClientData)xtfd, TCL_UNIX_FD); Tcl_CreateEventSource(XtEventSetup, XtEventCheck, (ClientData)xtconn); while (1) { Tcl_DoOneEvent(TCL_ALL_EVENTS); } }
The ResizeRequest
event is used (typically by window managers) to
interpose on configuration changes before they occur, possibly
preventing them from occurring altogether and support for it was removed in
Tk4. There is almost no imaginable case where Tk scripts should really be
asking for ResizeRequest
events; people tended to use them when what
they really wanted was Configure
events (which trigger after the
resize has occured), and this produced very strange behavior in their
programs.
Try bind .widget <Configure> { puts "%W is now %w x %h" }
instead.
Delete the send
command. This removes the interpreter's name
from the X11 property (won't show up in another wish's winfo interps
)
and disables incoming send
processing. You can delete the send
command with:
rename send {}
Note: Currently send is not available on the Win/Mac ports.
wm
(short for window manager) is used for managing
or finding information about toplevels
, while
winfo
(short for widget info) is for querying info
about all types of widgets.
For example, wm geometry .
will give you the size of the
main toplevel, including window manager decoration, as perceived by the
window manager. However, winfo geometry .
returns only the
size of . as perceived by Tk.
You can capture the window manager delete window action with the following:
wm protocol .toplevel WM_DELETE_WINDOW { puts "Don't delete me" }
This overrides the window manager's default action, so if you wanted to have a clean up procedure execute before closing the window, you have to make sure to close the window yourself.
There are two methods for keeping your toplevel on top. Make your choice depending on your needs:
The first method is for modal dialogs, where you want to ensure that the
dialog does not get obscured by its associated toplevel window. It is
assumed that you already have done a local grab
on the dialog to make
it modal. All you have to do then is call
wm transient .dialog .master
to ensure that the dialog will remain
on top. This is somewhat window manager dependent, but works in general.
The second method is more forceful, for when you want a window to not be obscured at all. To create this effect, do the following:
bind .toplevel <Visibility> { if {[string match %W .toplevel] && [string compare %s VisibilityUnobscured]} { raise %W update } }
In short, no. However, it is possible to make Tk more ICCCM compliant
through the use of a few wm
methods. The following are a
couple examples which effect window manager interaction:
wm command . "$argv0 $argv" wm client . [info hostname]
canvas
widgets questions
The Tk canvas
has a postscript
method which allows one
to create an Encapsulated Postscript file describing the canvas.
Unfortunately this does not currently work for images in the canvas.
To get better postscript support, as well as a generally enhanced canvas, get the Tk dash patch (http://www.cogsci.kun.nl/~nijtmans/tcl/patch.html) by Jan Nijtmans (mailto:nijtmans@nici.kun.nl).
You must use a polygon if you want to fill an area bounded by some lines.
Use raise .widget
and lower .widget
to adjust window
objects relative to each other. However, graphics objects cannot be raised
above window objects on the canvas
. See the canvas
man
page for the full set of options.
You need to bind a command to the Configure event, like this:
bind .canvas <Configure> { puts "%W is now %w %h" }
This is actually a pure Tcl question, but it comes up frequently in this context, so here we go...
All canvas items require two or more coordinates on creation, which define the initial position and/or shape of the item. If you have each coordinate in a separate variable, or you are using a constant value, then creating canvas items is simple. For example:
.myCanvas create rectangle $x1 $y1 $x2 $y2 -fill blue .myCanvas create text 100 250 -text "Hello, world"
Many times, though, the coordinates don't each exist in a separate
variable. They may be a list in a single variable that was read from a
file, or returned from some calculation routine, or extracted from some
other list of coordinates. In this case, you need to break the list of
coordinates up before the canvas command is executed. Use the
eval
commands for this. Here are several examples:
# # Example 1 # Given a list of two coordinates, create a text item # set coords {150 50} eval .myCanvas create text $coords -text hello # # Example 2 # # Here's a routine that returns coordinates for a rectangle centered # around a point, and some example uses. # proc CenteredRectangle {centerX centerY width height} { return [list [expr $centerX - $width / 2.0] [expr $centerY - $height / 2.0] [expr $centerX + $width / 2.0] [expr $centerY + $height / 2.0]] } eval .myCanvas create rectangle [CenteredRectangle 80 5 10 75] eval .myCanvas create rectangle [CenteredRectangle 5 80 75 10] eval .myCanvas create oval [CenteredRectangle 140 110 75 50] # # Example 3 # # Here's a routine which creates a text label surrounded by # a rectangle, with both of them centered around a given point. # proc CenteredBoxLabel {w centerX centerY text} { set id [$w create text $centerX $centerY -text $text -anchor center] eval $w create rectangle [$w bbox $id] } CenteredBoxLabel .myCanvas 33 42 "Hello, world" If you have a list of coordinate pairs, e.g. {{25 10} {30 12} {35 14}}, then an extra step is required to make it a flat list. Try this: # # Example 4 # Starting with a list of pairs... # set coordPairs {{25 10} {30 12} {35 14}} # # ... flatten out the list into just a list of numbers (as in # the above examples). # set flatList [eval concat $coordPairs] # # Now, follow the same strategy as in the examples above. # eval .myCanvas create line $flatList
In summary, carefully read the docs for eval
,
concat
, and list
so that you can combine the
coordinate data with the canvas create
command to form a valid Tcl
command which can be executed.
canvas
performance?
Often times coding style changes can result in increased performance, but
the canvas
has its limits. The Tk dash patch (http://www.cogsci.kun.nl/~nijtmans/tcl/patch.html) by Jan Nijtmans (mailto:nijtmans@nici.kun.nl) has
many canvas improvements, including one or two that can improve performance
in some situations.
canvas
?
To put an image into the canvas
you must first create it
with image create ...
and then embed that image into
the canvas. For example:
image create photo my_image -file [file join $tk_library demos images teapot.ppm] pack [canvas .c] .c create image 0 0 -anchor nw -image my_image
Unfortunately Tk does not yet support the printing of images. You can get this functionality by grabbing the Tk dash patch (http://www.cogsci.kun.nl/~nijtmans/tcl/patch.html) by Jan Nijtmans (mailto:nijtmans@nici.kun.nl).
canvas
seem to start at 0,0?
The canvas coords are skewed by the highlight border and the relief. By default, they overlap onto the canvas coord space. There are two ways to deal with this:
## Method 1, zero out the highlightthickness and borderwidth ## (borderwidth defaults to zero) anyway .canvas config -borderwidth 0 -highlightthickness 0 ## Method 2, adjust the canvas position to expose 0,0 properly .canvas xview moveto 0 .canvas yview moveto 0
Method 2 is better, but you must do it anytime you adjust the canvas borderwidth or highlightthickness.
canvas
have a see
method?
The canvas
lacks a see
method like that available in the
text
or listbox
widgets. The following code provides
the equivalent functionality for a canvas:
## "see" method alternative for canvas ## Aligns the named item as best it can in the middle of the screen ## Behavior depends on whether -scrollregion is set ## ## c - a canvas widget ## item - a canvas tagOrId proc canvas_see {c item} { set box [$c bbox $item] if [string match {} $box] return if [string match {} [$c cget -scrollreg]] { ## People really should set -scrollregion you know... foreach {x y x1 y1} $box { set x [expr round(2.5*($x1+$x)/[winfo width $c])] set y [expr round(2.5*($y1+$y)/[winfo height $c])] } $c xview moveto 0 $c yview moveto 0 $c xview scroll $x units $c yview scroll $y units } else { ## If -scrollregion is set properly, use this foreach {x y x1 y1} $box {top btm} [$c yview] {left right} [$c xview] {p q xmax ymax} [$c cget -scrollreg] { set xpos [expr (($x1+$x)/2.0)/$xmax - ($right-$left)/2.0] set ypos [expr (($y1+$y)/2.0)/$ymax - ($btm-$top)/2.0] } $c xview moveto $xpos $c yview moveto $ypos } }
entry
widgets questions
You can use the -textvariable
option for an entry
widget
as follows:
set default "foobar" entry .foo -width 25 -textvariable default
or you can specifically insert text into the entry:
entry .foo .foo insert 0 "foobar"
You want to make use of combination of the entry
widget's
-textvariable
option and the tcl variable trace
function. Here is a limited example:
proc forceInt {name el op} { global $name ${name}_int if [string comp {} $el] { set old ${name}_int\($el) set name $name\($el) } else { set old ${name}_int } if ![regexp {^[-+]?[0-9]*$} [set $name]] { set $name [set $old] bell; return } set $old [set $name] } pack [label .la -text {Integer 2: {^[-+]?[0-9]*$}}] -anchor w pack [entry .a -textvariable myVar] -fill x -expand 1 trace variable myVar w forceInt set myVar {}
You can see a more complex example as a Tk plugin (http://sunscript.sun.com/products/plugin.html) at http://www.cs.uoregon.edu/research/tcl/code/tclet/entrylimit.html.
listbox
widgets questions
Use the -selectmode
option of the listbox
to specify
what type of selection you desire. The modes multiple
and
extended
will allow you to select multiple non-contiguous entries.
See the listbox
man page for more information.
The default for Tk's listbox
widget is to export its selection
as the X selection. There can only be one of these at a time. To turn off
this behavior in Tk, use -exportselection false
when you create the
listbox
. Alternatively, place the following command at the
beginning of your script:
option add *Listbox.exportselection false
Use -setgrid 1
when you create the listbox
. Note that
only one widget can properly have setgrid set per toplevel. See the
options
man page for more information. It works like so:
listbox .l -setgrid 1 -yscrollcommand ".s set" -relief sunken -bd 2 scrollbar .s -command ".l yview" pack .s -side right -fill y pack .l -side top -fill both -expand 1 .l insert end one two three four five six seven eight nine ten LAST
Note: You may have only one widget per toplevel use -setgrid
.
Scrollbars have a -command
option which is used to tell scrollable
widgets (e.g. listbox
, text
, entry
) how to
position themselves when the scrollbar is moved. This command typically
looks like:
scrollbar .scroll -command {.scrollable_widget yview}
where xview
can substitute for yview
. Before the command
is executed, however, it will have two numbers concatenated to it. The
numbers are fractional positions which indicate how the scrollable widget
should position itself. Thus, to have a single scrollbar control multiple
widgets, simply use a procedure as the scroll command, and have that
procedure scroll as many widgets as you would like. The procedure should
take a two arguments (i.e. the fractional positions). The following
example will connect multiple listboxes to one scrollbar and correctly
handle button bindings in each for single/browse selection:
set BOXES {.lb0 .lb1 .lb2 .lb3} proc LBset args { global BOXES foreach lb $BOXES { eval $lb $args } } proc LBscroll args { eval .sy set $args LBset yview moveto [lindex $args 0] } scrollbar .sy -orient v -command [list LBset yview] pack .sy -fill y -side right foreach lb $BOXES { listbox $lb -exportsel no -selectmode browse -yscrollcommand LBscroll pack $lb -side left -fill both -expand 1 bind $lb <ButtonPress-1> { LBset select clear 0 end LBset select set [%W nearest %y] } bind $lb <B1-Motion> { LBset select clear 0 end LBset select set [%W nearest %y] LBset see [%W nearest %y] } bind $lb <ButtonRelease-1> { LBset select clear 0 end LBset select set [%W nearest %y] } } for {set i 100} {$i} {incr i -1} {LBset insert end $i}
To get proper behavior with the keys as well, you will have to shadow the bindings for key movement found in $tk_library/listbox.tcl.
.listbox curselection
or
selection get
return the proper item when I make a button
binding to my listbox?
The best way to get the selected item during a button click event on
a listbox
is to use the following code:
bind .listbox <Button-1> { set item [%W get [%W nearest %y]] }
This ensures that the item under the pointer is what will be returned as
item
. The reason .listbox curselection
can fail is because
the items in curselection
are not set until the Listbox
class
binding triggers, which is after the instance bindings by defaults. This is
the same reason for which selection get
can fail, but it will also
fail if you set the -exportselection
option to 0.
This is not possible with the standard Tk4 listbox
. Some
attempts have been made to make megawidget listboxes with this
functionality based on the text
or canvas
widget.
The Tix (http://www.xpi.com/tix/) megawidget extension provides an extended listbox.
menu
widget questions
At the moment torn-off menus will not reflect changes made to the
original menu. This functionality is slated for an upcoming revision of the
menu
system in Tk. It's possible to do this now by tracking the
associated tearoff using the -tearoffcommand
option for menus. This
allows you to specify a command that will be executed when the menu is torn
off. The widget names of the menu and tearoff menu (tearoffs are created as
toplevels with the name .toplevel.tearoff<id>
when torn off) are
appended to this command before it is evaluated.
Tearoffs are new to Tk4 and the new default for menu
s. They
now occupy index 0 of the menu when they are present. You can exclude them
by passing -tearoff 0
to each menu or by placing the following line
at the beginning of your code:
option add *Menu.tearoff 0
text
widgets questions
Use -expand 1
, as in the following:
pack [text .text] -fill both -expand 1
For internal reasons, the text
widget maintains a newline at
the end of the text widget. In order to avoid having this added to what was
actually input into the text widget, use .text get 1.0 end-1c
to
get the full text out of a text widget.
The text
widget does not have a -textvariable
option
like the entry
widget, so you must be more devious in determining
when the contents have changed.
If the contents of the text widget are known to be small, then a simple
solution would be to cache the original contents and use
string compare $cache [.text get 1.0 end-1c]
to check for
changes.
A more general solution that some have recommended is to make bindings that set a global flag when the text widget is edited. This is often imperfect because you have to make sure to account for all bindings which might edit the widget. Also, you don't really want these bindings to trigger all the time, but rather just once after any save command. Alternatively, you could place a wrapper proc around the text widget which intercepts any insert/delete calls:
pack [text .text] set .text 1; # Represents whether text is SAVED or not rename .text ..text proc .text args { global .text if [regexp {^(ins|del).*} [lindex $args 0]] { set .text 0 } uplevel ..text $args }
The only thing that misses is direct C calls and embedded window
addition. Don't forget to set .text 1
when you save text.
To create read-only sections in a text widget, you should make use of the
text
widget tag facility. The following is a minimal example of
this:
pack [text .text] .text tag config readonly -background yellow rename .text ..text proc .text args { if {[string match ins* $args] && [lsearch -exact [.text tag names [lindex $args 1]] readonly]>-1} return if [string match del* $args] { if [string comp {} [lindex $args 2]] { if {[string comp {} [eval .text tag nextrange readonly [lrange $args 1 2]]]} return } else { if {[lsearch -exact [.text tag names [lindex $args 1]] readonly]>-1} return } } uplevel ..text $args }
Not by default, but you can change the tkTextInsert and tkEntryInsert library procedures to include this with the following:
proc tkTextInsert {w s} { global tkPriv if {($s == "") || ([$w cget -state] == "disabled")} { return } if {[catch { if {[$w compare sel.first <= insert] && [$w compare sel.last >= insert]} { $w delete sel.first sel.last } }] && [info exists tkPriv(overwrite)] && $tkPriv(overwrite)} { if {[$w compare "insert+[string len $s]c" < "insert lineend"]} { $w delete insert "insert+[string length $s]c" } else { $w delete insert "insert lineend" } } $w insert insert $s $w see insert } proc tkEntryInsert {w s} { global tkPriv if {$s == ""} { return } if {[catch { set insert [$w index insert] if {([$w index sel.first] <= $insert) && ([$w index sel.last] >= $insert)} { $w delete sel.first sel.last } }] && [info exists tkPriv(overwrite)] && $tkPriv(overwrite)} { $w delete insert [expr [$w index insert]+[string length $s]] } $w insert insert $s tkEntrySeeInsert $w }
Thus you just set the tkPriv(overwrite) variable to 0/1 to switch between the overwrite and insert modes.
The problem is you add text to the text widget but you can't see it because it is now off the screen. Instead of requiring any interaction from the user, you can use either of the following lines of code:
.text see end ;# works anytime for text widgets # OR .text yview moveto 1 ;# works for other widgets with scrollbars attached
The easy way to do this is to make the buttons the children of a
canvas
widget, place them in the canvas with canvas create
window ...
and attach a scrollbar
to the canvas. For example:
scrollbar .sy -orient v -command ".c yview" canvas .c -yscrollcommand ".sy set" pack .sy -fill y -side right pack .c -fill both -expand 1 -side left set x 2 set y 2 for {set i 0} {$i<20} {incr i} { button .c.b$i -text "Button $i" -width 10 -command "puts {$i pressed}" .c create window $x $y -window .c.b$i -anchor nw incr y [winfo reqheight .c.b$i] } .c config -scrollregion "0 0 [winfo reqwidth .c.b0] $y" -width [winfo reqwidth .c.b0]
You can't. During a recent revision of Tk, things were changed so that names beginning with a capital letter are reserved for class names. Specific instances of widgets must begin with a lower case letter. This enables X11 resource definitions to distinguish between a class and an instance.
Note the following example:
radiobutton .times -text Times -anchor w -value Times radiobutton .helvetica -text Helvetica -anchor w -value Helvetica radiobutton .courier -text Courier -anchor w -value Courier pack .times .helvetica .courier -side top -fill x
Note that you are using anchor west in the widgets themselves, and not in the packer. This lets the packer produce full width buttons.
To group radiobuttons, simply give all the buttons in a group the same
-variable
name. Since the default variable name is
selectedButton
for all radiobuttons, if no -variable
is
used, then all belong to the same group.
radiobutton .left.b1 -text "Left 1" -variable leftChoice -value left1 radiobutton .left.b2 -text "Left 2" -variable leftChoice -value left2 radiobutton .left.b3 -text "Left 3" -variable leftChoice -value left3 radiobutton .right.b1 -text "Right 1" -variable rightChoice -value right1 radiobutton .right.b2 -text "Right 2" -variable rightChoice -value right2 radiobutton .right.b3 -text "Right 3" -variable rightChoice -value right3
As of Tk4.2, Tk supports XBM (X bitmap) for bitmaps as well as PPM
(portable pixmap, a 24 bit format) and GIF (graphics interchange format) for
photo images
. Currently only PPM and XBM support the
-data
option.
The Tk Image Extension (ftp://ftp.nici.kun.nl/pub/nici/software/tcltk/img/) by Jan Nijtmans (mailto:nijtmans@nici.kun.nl) contains format handlers for XBM,
XPM, JPEG, GIF89, PNG and TIFF and the pixmap
image type
adopted from Tix (http://www.xpi.com/tix/). Further image formats can be added via DLLs
with the Tk C command Tk_CreateImageType
(along with code to read that format, of course).
-data
option for images?
For XBM and PPM formatted images, the image
command in Tk
allows you to pass a -data
option that would contain the image data
in the same format as you'd have in a file.
Note: The Tk plugin (http://sunscript.sun.com/products/plugin.html) and Tk8.0+ can read base64 encoded GIF data
via -data
, but this isn't available in Tk4.2- unless you get the
excellent Tk plus patch (http://www.cogsci.kun.nl/tkpvm/pluspatch.html) by Jan Nijtmans (mailto:nijtmans@nici.kun.nl).
Tk uses a hack for transparency in GIF images. If you have a GIF89
image that has the transparency index set, you need to set the global
Tcl variable TRANSPARENT_GIF_COLOR
to the color which you want
the show through (in general, the background of the widget you are
placing it on). Use the following code as an example:
label .x set TRANSPARENT_GIF_COLOR [.x cget -bg] image create photo x -file image.gif .x config -image x
Donal Fellows has a minimal C extension to support real transparency at http://r8h.cs.man.ac.uk:8000/tcl/transPhoto.c
image
to work with
-stipple
?
At the moment, you can't. Bitmaps created with
do not use
image
create bitmap ...Tk_DefineBitmap
, which is required for
-stipple
to know it's a bitmap. Instead, you'll have to use the
old format for using bitmaps in stipples, like so:
.canvas create rect 10 10 80 80 -fill black -stipple @/path/to/my.bmp
It's not a simple C fix for the above problem, but it's on Sun's ToDo list.
The situation: A window is created, say .w1
, followed by another
window, say .w2
. The command pack .w1 -in .w2
is used to
pack .w1
inside of .w2
. The pack
command completes
successfully, and pack info .w1
indicates that things are as
expected. However, .w1
isn't visible! Where is it?
button .w1 -text Hello; # create .w1 frame .w2; # create .w2 pack .w1 -in .w2; # pack .w1 inside .w2 pack .w2; # pack .w1 in main window # where's the button?
The explanation: (based on a posting by js@aelfric.bu.edu (Jay Sekora))
The short answer is raise .w1
. In the example .w1
is
positioned properly inside .w2
, and all the sizing glue that lets
.w1
and .w2
adjust their sizes based on each other will work,
but .w1
is underneath .w2
, because windows are
stacked in the order they're created in, by default. You can change the
stacking order explicitly with the raise
command, in this case
raise .w1
.
cget
to return the correct size of a resized
widget?.widget cget -width|height
returns the wrong size!)
Don't use a widget's cget
method, use
instead. The winfo
width|height .widgetcget
method will only tell you what the widget wanted to be or what you told it
to be with .widget config -width|height ...
. If the packer resizes
it to fill the slave space, or the user resizes it, then only winfo
will return the actual new size.
There is a simple Tcl solution for this, provided by Stephen Uhler, (with modification by Donal Fellows):
# insert rows or columns into a grid # grid: the geometry master # what: row or column # index: where to insert # count: how many rows/cols to insert proc grid_insert {grid what index {count 1}} { foreach slave [grid slaves $grid] { array set info [grid info $slave] if {$info(-$what) >= $index} { incr info(-$what) $count eval {grid $slave} [array get info] } elseif {$info(-$what)+$info(-${what}span) > $index} { incr info(-${what}span) $count eval {grid $slave} [array get info] } } }
tk appname
or winfo name .
returns the name of your Tk
interpreter as seen by others.
The answer is:
eval destroy [winfo children .]
The eval
is necessary so that the list of children windows
can be separated into individual arguments. Destroy will get individual
window names instead of one big string.
You can change the default colors by modifying your X resource database
for your personal use or use the Tk convenience command
tk_setPalette
. You can do the first using whatever
method you usually use to add/modify X resources (X default file, etc.), or
you can use the Tk option
command to change the option database
from within a Tk application. Tk also has the command tk_bisque which
reverts Tk4 to using the Tk3 default colors. The easiest way to set your
application to one general scheme is via tk_setPalette like so:
tk_setPalette pink
For more information, see your system's documentation for loading X
resources, and/or the Tk man page for the option
and
tk_setPalette
commands.
Currently, fonts are specified in different ways for X11 and Windows/Mac environments. For X11, you want to specify fonts in the X11 font spec format, like so:
.widget config -font "-adobe-courier-bold-r-normal--8-80-75-75-m-50-iso8859-1"
Often you will see *
s replace certain elements of the above font
spec. You can get a full list of fonts on your machine from the command
xlsfonts
. For Windows/Mac environments, the fonts are specified
like so:
## Font spec: {Family Size Style} .widget config -font {Courier 12 {}} .widget config -font {Helvetica 18 {Bold Italic}}
For valid font spec formats on Win/Mac, Tk will find a font, even if it is not the specified one. You should always be careful which fonts you choose because only a core set can be expected to be on any given machine.
Tk8 has a new font
mechanism that allow for the easy
specification of fonts (as above) for all platforms, along with commands to
query and manipulate information about available fonts.
The BLT (http://www.tcltk.com/blt/) extension has this functionality.
You can also try the all-tcl code by Donal Fellows at http://r8h.cs.man.ac.uk:8000/tcl/.
In short, you can't. A single-click will always register at least once -
in the interval between the clicks of a double-click. Tk does not delay
evaluation of a mouse button binding to see if the user will double or
triple click. You can prevent a second single-click binding from triggering
by adding a break
to the end of the double-click binding.
This functionality is not provided by Tk (it's considered improper to warp the user's cursor in general). However, you can make a simple dynamically loadable library to do it. Here is the core code:
int Tk_CursorCmd(clientData, interp, argc, argv) ClientData clientData; Tcl_Interp *interp; /* Current interpreter. */ int argc; /* Number of arguments. */ char **argv; /* Argument strings. */ { int length; char c; Tk_Window tkwin = (Tk_Window) clientData; Tk_Window winPtr; if (argc < 2) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ?options?\"", (char *) NULL); return TCL_ERROR; } length = strlen(argv[1]); c = argv[1][0]; if ( c == 'w' && strncmp(argv[1],"warp",length) == 0 ) { int x,y; Window win; if (argc != 5) { Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " warp <window> <x> <y>\"", (char *) NULL); return TCL_ERROR; } if ( argv[2][0] == '.' ) { winPtr = (Tk_Window ) Tk_NameToWindow(interp, argv[2], tkwin); if (winPtr == NULL) { return TCL_ERROR; } win = Tk_WindowId(winPtr); } else { winPtr = (Tk_Window )clientData; win = None; } if ( Tk_GetPixels(interp,winPtr,argv[3],&x) != TCL_OK )return TCL_ERROR; if ( Tk_GetPixels(interp,winPtr,argv[4],&y) != TCL_OK )return TCL_ERROR; XWarpPointer(Tk_Display(winPtr),None,win,0,0,0,0,x,y); } return TCL_OK; }
You'll of course need an Foo_Init
function with something like:
Tcl_CreateCommand(interp, "cursor", Tk_CursorCmd, (ClientData) Tk_MainWindow(interp), NULL);
That will give you a command that understands
cursor warp <window> <X> <Y>
. The Tk dash patch (http://www.cogsci.kun.nl/~nijtmans/tcl/patch.html) also has added
this functionality to the Tk event
command by adding a
-warp
option, which is more robust than the above.
At the moment this is not possible in Tk without modifying the code. This feature is on Sun's ToDo list.
Yes. While regular Tk and the Tk plugin (http://sunscript.sun.com/products/plugin.html) are based off the same source code, the plugin is subtly different due to its web-based interaction. Primarily, the security policies for the plugin remove certain commands from being evaluated in the interpreter (the plugin code is run in a safe interpreter). Also, there are some enhancements to the plugin (as of version 2 of the plugin) such as the ability to intercommunicate with other applets or other sites when being run. See the Tk Plugin FAQ (http://sunscript.sun.com/techcorner/faq.html) for more information.
The plugin works with Netscape 3.0 on Unix, but 2.0+ on Mac and Windows, as well as Microsoft Explorer 3.0.
Courtesy of Don Libes (mailto:libes@nist.gov):
expect_before
command to match characters
and insert them into the widget. Expect's tkterm example performs smart
terminal emulation. It's capable of handling emacs, vi, or any
termcap/terminfo/curses-based program. And since it's done with a text
widget, you can manipulate the display simply by accessing the text widget.
Exploring Expect http://www.ora.com/www/item/expect.html covers
both dumb and smart terminal emulation in the Tk chapter.
[incr Tcl] (http://www.tcltk.com/itcl/) provides the extra language support needed to build large
Tcl/Tk applications. It introduces the notion of objects, which act as
building blocks for an application. Each object is a bag of data with a set
of procedures or methods
that are used to manipulate it. Objects are
organized into classes
with identical characteristics, and classes
can inherit functionality from one another. This object-oriented paradigm
adds another level of organization on top of the basic variable/procedure
elements, and the resulting code is easier to understand and maintain.
[incr Tk] (http://www.tcltk.com/itk/) is a framework for building megawidgets using the [incr Tcl] (http://www.tcltk.com/itcl/) object system. Megawidgets are high-level widgets like a file browser or a tab notebook that act like ordinary Tk widgets but are constructed using Tk widgets as component parts, without having to write C code. In effect, a megawidget looks and acts exactly like a Tk widget, but is considerably easier to implement.
BLT (http://www.tcltk.com/blt/) is an extension to the Tk toolkit, adding new widgets (like a
2D graph widget), another geometry manager (now subsumed by Tk's
grid
), and others commands. It does not require any patching
of the Tcl or Tk source files.
A patch to get BLT (http://www.tcltk.com/blt/) running on Windows is available at http://www.jessikat.demon.co.uk/.
Tix (http://www.xpi.com/tix/) (Tk Interface Extension) is an extensive set of over 40 megawidgets including ComboBox, Motif style FileSelectBox, MS Windows style FileSelectBox, PanedWindow, NoteBook, Hierarchical List, Directory Tree and File Manager, among others.
There are a few GUI (Graphical User interface) builders available for Tk.
The most recent entrant is SpecTcl (http://sunscript.sun.com/products/spectcl.html), in development by the
guys at Sun (see the Tcl Home Page (http://sunscript.sun.com/)), which can output Perl, Tcl or Java
UI code and is grid
based.
XF is the oldest major GUI builder app for Tcl/Tk and is available at http://www.cimetrix.com/sven/xf.html.
Visual Tcl (not the SCO version of Tcl) is a new GUI builder with some IDE features for Tcl/Tk and is available at http://www.neuron.com/stewart/vtcl/.
Tk, as a user interface toolkit, has been grafted onto many other languages. There is an effort underway to develop a Tcl independent Tk for any language to easily adapt Tk as its UI extension. Among the many languages which currently make use of Tk:
Thanks for looking here first. There are two newsgroups for the Tcl language: news:comp.lang.tcl for basic discussion of bugs, problems and ideas, and news:comp.lang.tcl.announce for announcements of new versions of Tcl/Tk and related applications. Aside from the basic netiquette of posting to newsgroups, the following conventions should be followed:
Pnews
on UNIX is the general tool for posting to newsgroups.
Netscape 3+ also has facilities to post to a newsgroup if you have the
news server preferences set up correctly.
In the unlikely event you encounter a bug in Tk, make sure to go through the following process before posting to news:comp.lang.tcl.
I'm sure that the problem is really the fault of corruption during transmission of the FAQ. However, concerned netizens should report any problems with this FAQ to the maintainer: Jeffrey Hobbs (mailto:jeff.hobbs@acm.org).
There is a lot of raw information available for download about Tk on the net. Here are some references of note:
Last generated: Tue May 27 09:35:01 PDT 1997 by Jeffrey Hobbs (http://www.cs.uoregon.edu/~jhobbs/)