Dylan TK library

Previous Page TOC Index Next Page See Page

Mindy Compiler Mindy Debugger Mindy Object Extensions Streams Library Standard IO Print Library Format Library Melange Interface TK Library Collection extensions Table Extensions String extensions Regular Expressions Transcendental Library Time Library Random Library Matrix Library


The TK Library


1. Introduction and Warning

Dylan/TK is an experimental TK binding for the Mindy Dylan interpreter. Although it is definitely usable, it is not intended to be an "industrial strength" product. The implementation strategy virtually guarantees that there will be some rough edges.

This binding operates by starting a wish interpreter as a slave process and passing both Tcl routines and data between the Mindy interpreter and the slave process. However, Dylan/TK provides an abstraction layer that should vastly reduce or even eliminate the need for users to be familiar with the Tcl extension language. For example, the following Dylan code:

    define constant text-frame

= make(<frame>, height: 500, fill: "both", side: "bottom", expand: #t);
define constant text-window
= make(<text>, in: text-frame, relief: "sunken", font: normal-font,
fill: "both", side: "right", expand: #t);
define constant text-scroll
= scroll(text-window, in: text-frame, fill: "y");

could be used to produce the effect as the following Tcl/Tk code:

    frame .text-frame -height 500

pack .text-frame -fill both -side bottom -expand 1
text .text-frame.text -relief sunken -font normal-font
pack .text-frame.text -in .text-frame -fill both -side right -expand 1
scrollbar .text-frame.scroll -command {.text-frame.text yview }
.text-frame.text configure -yscrollcommand {.text-frame.scroll set }
pack .text-frame.scroll -in .text-frame -fill y

while being considerably clearer to the average Dylan programmer.

Note: In order for this implementation to work you must have a copy of wish available on your system. This implementation was developed upon version 4.0 of Tcl/Tk but should work any version Tk implementation after 4.0. Since version 4 introduces incompatible changes, you should not (at present) expect all features to work with earlier versions.

2. General Principles

In order to use Dylan/Tk, you should import module Tk from library Tk. This defines the <window> class, a variety of subclasses representing most of the Tk widgets, and a variety of support routines. All of these will be explained in some detail below. However, the user will sometimes find that he can gain more information by going to the book Tcl and the Tk Toolkit by John Osterhout, which explains the widgets’ behavior in more depth than is practical for this document.

Any Dylan program which uses the Tk library will automatically create a top level window (which is accessible via the *root-window* variable) and a separate thread to process events upon that window. You build an interface by making widgets and "packing" them into windows -- either the root window, newly created top-level windows, or into subwindows of these windows.

An simple application might be the following:

    define method main (program-name :: <string>, #rest args);

make(<message>, text: "Hello, world!", aspect: 500, side: "top");
make(<button>, text: "Okay", relief: "raised",
command: curry(destroy-window, *root-window*), expand: #t);
map-window(*root-window*);
end method main;

This creates a text message and a pushbutton, packs them into the root window, and then exits, and makes the root window visible. It then exits the main thread, leaving just the event processing thread active. When the button is pressed, it will destroy the root window (and all its subwindows). Since there are no windows left, the event thread exits, and the program terminates. We could just as easily specified "command: exit", which would force the Dylan program to exit, killing off all threads, and thus destroying the windows. Go ahead and try it, if you like.

Widgets, like any other Dylan object, are typically created via make. There are three different varieties of keywords which can be specified:

Widget Specific Options:
Standard Options:
Packing Options:

3. Parameter and Return Values

The values which are passed into make or into many other Tcl/Tk functions are passed into to Tcl/Tk as strings, and thus it is sometimes most convenient to write them as strings in Dylan. Most Dylan/Tk functions therefore accept strings as parameter values. However, you will usually find it easier to work with a richer set of types within Dylan’s type system. Parameters values can commonly include instances of the following native Dylan classes:

and will occasionally include others on a case-by-case basis. In addition, the following new classes are also frequently accepted as parameter values:

Those Dylan/Tk functions which return values typically cast the results back into meaningful Dylan types before returning them. However, there are some occasions where this proves impractical, and result values remain as <string>s which must be explicitly cast into appropriate types. For example, the configuration function returns the values of all the configuration options for a widget. Since it can’t guess what the types of these values ought to be, they simply remain as <string>s.

In some cases you must specify callback functions for Dylan/Tk widgets. These are typically specified via the command: keyword to make. On the few occasions where these functions take parameters, they will be passed in as <string>, and may include "\" quotation characters. You may need to call tk-unquote to strip out backslashes or to call tk-as to convert this to another type. For example: tk-as(<boolean>, "1") returns #t.

4. The "Standard" Options

The following options seem to apply universally to all widgets. They are mostly concerned with presentation details of the widget’s window, as opposed to the widget’s function.

background:
borderwidth:
cursor:
foreground:
highlightbackground:
highlightforeground:
highlightthickness:
relief:

Other options are by no means universal, but tend to mean the same thing whenever they occur:

bitmap:
command:
font:
justify:
state:
text:
textvariable:
underline:
variable:

5. Windows

The abstract type <window> represents any one of a wide variety of widgets, although it doesn’t include pseudo-widgets like menu entries, text tags, or canvas items (which will be discussed later). They are almost always created via make, which accepts all of the standard options described above, as well as the packer options name:, in:, after:, before:, side:, expand:, padx:, pady:, and pack:. (Packing will be described briefly in the next section.) All windows except <toplevel>s must specify their parents by some means -- either directly via in: or indirectly via after: or before:.

You also have the right to specify a debug name for the window via the name: option. If you refuse this right, one will be created for you automatically.

One window is automatically created as a result of importing the tk library. This is the top level window *root-window*.

There are a small set of methods which operate upon all windows:

configure (widget :: <window>, #all-keys) [Function]

configuration (widget :: <window>) => (result :: <sequence>) [Function]

map-window (window :: <window>) => () [Function]

unmap-window (window :: <window>) => () [Function]

destroy-window (window :: <window>) => () [Function]

pack (window :: <window>, #all-keys) => (window :: <window>) [Function]

unpack (window :: <window>) => (window :: <window>) [Function]

\= (window :: <window>, window :: <window>) => equal? :: <boolean> [Method]
\= (window :: <window>, path-name :: <string>) => equal? :: <boolean> [Method]
\= (path-name :: <string>, window :: <window>) => equal? :: <boolean> [Method]


6. Packing

Unless they are some sort of top level window (i.e. *root-window* or instances of <toplevel> or <menu>), windows must be "packed" into some containing window before they will appear on the screen. Normally, all Dylan/Tk windows are automatically packed when they are created, using the procedure and options described below. The exception to this is if the pack: option is given a value of #f or is the window was unpacked; in these cases, the pack function will need to be called explicity to display the window. The Dylan/Tk pack function closely follows the Tcl/Tk function described in "Tcl and the Tk Toolkit", and you should look there for more complete information. However, we will provide a brief overview here.

Each "slave" (i.e. non-top-level) window must be packed into some other window. You specify this window either directly, via "in: parent" or indirectly via "before: sibling" or "after: sibling". (The latter options specify that the window should have the same parent as the specified "sibling", and that they should be placed just before or after the sibling in the parent’s "packing order".) If no parent is specified explicitly, Dylan/Tk implicitly assumes "in: *root-window*".

The side: option specifies where the widget should be placed relative to the ones which follow it in the "packing order". If you specify "side: "left"", then all widgets which are packed into the parent after this one (either because they were created later or because of a before: or after: option) will be placed somewhere to the right of this widget. Note that it will not necessarily be placed on the parent’s absolute left side, because all windows which precede this one in the packing order have "first dibs" on prime real estate. Possible values for this option are "left", "right", "top", and "bottom" -- the default is "left".

If you were to execute:

let w1 = make(<listbox>, in: *root-window*, side: "left");

let w2 = make(<text>, before: w1, side: "top");
let w3 = make(<scrollbar>, after: w1);

you would end up with something like:

Window W2 comes first in the packing order (because of the before: option) and preempts the top of the root window. W1 comes second, and grabs the left side of the remaining space, leaving a small chunk on the right for W3 (and any windows which might be packed after W3).

The other options available are anchor:, expand:, fill:, padx:, and pady:, which are explained in the book. Expand: typically takes a boolean value, while fill: takes one of "x", "y", "both", or "none".

The unpack function will remove a window from the control of the "packer" and, as a side effect, remove it from the display. The window will still exist and can be updated or repacked via the pack function. You will, however, get errors if you try to specify a different parent when you repack it.

7. Event bindings

Each Dylan/Tk widget has a default set of "bindings" which determine how they react to X events like button or key presses. These may be changed or extended via the "bind" function. Windows, "tag" strings, and subclasses of <window> can have bindings, and more than one binding may apply to an event. All of the applicable bindings will get called, unless explicitly avoided, and the call order can be changed.

bind (window-tag-or-class, event :: <string>, command) => (window)

   bind(l1, "<Double-Button-1>",  method () 

do(print-config, current-selection(l1))
end method);

There are five other utility functions which allow you to determine and manipulate the bindings for windows:

get-binding (window-tag-or-class, event) => (result :: <string>) [Function]

get-bindings (window-tag-or-class) => (result :: <sequence>) [Function]

binding-call-order (window :: <window>) => (result :: <sequence>) [Function]

binding-call-order-setter (bindings :: <sequence>, window :: <window>) => (bindings :: <sequence>) [Function]

tk-break () [Function]


8. Active Variables

Some widgets have the ability to take an obsessive interest in the value of some "variable". They may update their contents or appearance when the variable’s value changes, or they might update the variable in response to some user action. Because this level of monitoring is not supported by ordinary Dylan variables, Dylan/Tk users must instead use instances of <active-variable>.

Make on <active-variable> requires a value: keyword and accepts an optional class: keyword. If specified, the class defines the logical type of the variable’s value. The value slot will always contain a value of that type, although value-setter will accept arbitrary types (especially <string>) and attempt to convert them to the given type.

You may also specify a Dylan function to be executed when an active variable’s value changes (i.e. becomes \~= to the old value). This method is specified via the command: keyword to make. It will be invoked with both the new and the old value at some point after the value is changed. Note that the value is updated immediately (i.e. asynchronously), while the calls to the given command are executed sequentially along with event callbacks.

Active variables will typically be passed as values of variable: or text-variable: keywords.

9. The widget types

Dylan/Tk provides types corresponding to all of the standard Tcl/Tk widgets:

<button>:

Options:
Functions:

<checkbutton>:

Options:
Functions:

<menubutton>

Options:
Functions:

<radiobutton>:

Options:
Functions:

<canvas>:

Options:
Functions:

<entry>:

Options:
Functions:

<frame>:

Options:
Supports no operations.

<label>:

Options:
Supports no operations.

<listbox>:

Options:
Functions:

<menu>:

Options:
Functions:
Note that if you wish to assocaiate a menu with a menubutton, you must create it in: that button.

<message>:

Options:
Supports no operations.

<scale>:

Options:
Functions:

<scrollbar>:

Options:
Functions:
The scroll function exists to reduce the inefficiency inherent in "standard" method of connecting widgets to scrollbars. This function creates a new scrollbar with the given orientation (i.e. "vertical" or "horizontal") and connects it via lower level mechanisms to the given widget. All of the applicable creation and packing options for scrollbars are accepted.

<text>:

Options:
Functions:

<toplevel>:

Options:
Functions:
Tk-dialog automatically creates a dialog box with the given title, text, bitmap and buttons. The default argument is an integer that corresponds to the button that should be made the default (beginning at zero for the left-most button)

These operations will hopefully be described at greater length in future editions of this document, but for now you are encouraged to check the Tcl/Tk manual for further information.

10. Text indices

The types <text-index>, <text-mark>, and <text-tag> all represent references to the contents of a <text> window. Functions are provided to let you create and manipulate instances of these types.

<Text-index>s represent an "absolute" index within a <text> object. They have two slots -- line and character. Make on <text-index> requires a line: keyword and accepts an optional character: keyword (which defaults to 0). Lines numbers start at 1, while characters start at 0, so you could specify the first character of a <text> by calling make(<text-index>, line: 1, character: 0)

The following functions create and manipulate <text-index>s:

text-at (line, character) => result :: <text-index>
line-end (line) => result :: <string>
as (cls == <text-index>, value :: <string>) => string
as (cls == <string>, value :: <text-index>) => text-index

The text-at function provides a convenient shorthand for making <text-index>s. You might, for example replace the above make call with text-at(1, 0);

Line-end creates a reference to the last character of the named line.

11. Text marks

<Text-mark> objects represent more abstract character positions. It will continue to refer to the same character even if other text is added or deleted. They have two slots -- value and name, and are associated with a particular <text> widget via the required make keyword in:.

If you make a <text-mark> with the name of a "standard" Tcl/Tk mark, such as "end" or "insert", then the new object will pick up the values already associated with the Tcl/Tk mark.

The following functions create or manipulate <text-mark>s:

as (cls == <string>, object :: <text-mark>) => string
as (cls == <text-index>, mark :: <text-mark>) => text-index
marks (text :: <text>) => result :: <sequence>

The marks function returns a sequence containing all of the marks within a given <text>. This will include both the "standard" Tcl/Tk marks and any that you have created. These will not necessarily be == to the original objects.

12. Text tags

<Text-tag>s represent attributes which may be associated with zero or more sequences of characters in a specific <text>. You may specify different display properties or event bindings for the characters that have been associated with a particular <text-tag>.

<Text-tag>s are created within a particular <text> via make, which requires an in: keyword. Optional keywords include name:, bgstipple:, fgstipple:, font:, justify:, lmargin1:, lmargin2:, offset:, overstrike:, relief:, rmargin:, spacing1:, spacing2:, spacing3:, tabs:, wrap:, and underline:. Although tags are not widgets, they support the configure, configuration, and bind functions. You may add ranges of characters to <text-tag>s via add-tag. A complete list of functions upon <text-tag>s follows:

configure (tag, #rest options) => tag
configuration (tag, index) => result :: <sequence>
bind (tag, event :: <string>, command) => tag
as (cls == <string>, object :: <text-tag>) => string
add-tag (tag, #key start, end: last) => tag
remove-tag (tag, #key start, end: last) => tag
tags (text :: <text>) => result :: <sequence>
delete-tag (tag) => ()
raise-tag (tag, #key past :: <text-tag>) => ()
lower-tag (tag, #key past :: <text-tag>) => ()
next-range (tag, #key start, end) => result :: false-or(<pair>)

13. Canvas items and tags

<canvas-item>s represent different graphical entity within a <canvas>. Each create-shape function returns a <canvas-item> corresponding to the newly created shape. These may be used to delete, resize, move, or respecify the shape. Although canvas items are not widgets, they support the configure, configuration and bind functions. The configuration options which are accepted for a given item depend upon its type. You should consult the list of create-... functions for a list of options.

<canvas-tag>s are a convienient way of grouping various canvas items. If more than one item has a given tag, then any operation performed on the tag will be applied to all items with that tag. Tags may be created using the make method with required keywords #"in", the canvas that contains that tag, and #"name", a string identifier. Tags may be assigned to <canvas-item>s when they are created, by giving a single <canvas-tag> or a sequence of <canvas-tag>s in the #"tags" keyword.

The following functions operate upon canvas items and canvas tags:

configure (item, #rest options) => item
configuration (item, index) => result :: <sequence>
bind (item, event :: <string>, command) => item
delete-item (item) => ()
raise-item (item, #key past :: <canvas-item>) => ()
lower-item (item, #key past :: <canvas-item>) => ()
move-item (item, x :: <object>, y :: <object>) => ()
scale-item (item, x-origin, y-origin, x-scale, y-scale) => ()
item-coords (item) => result :: <sequence>
item-coords-setter (value :: <sequence>, item) => ()
item-type (item) => result :: <string>
add-canvas-tag (item, spec, spec-args) => ()
get-canvas-tags (item) => tags :: <sequence>
delete-canvas-tag (item, tag-to-delete) => ()

14. Window Information commands

There are a variety of window information commands that return various data about the state of the widgets, most of these corresponding to Tcl/TK "winfo" commands. There are also two new objects that are returned by some of these functions, <point> and <rgb-color>. <point> has slots x and y, both integers, and <rgb-color> has slots red, green, and blue, all integers. Functions that return these classes come in two forms for flexibility in programming. One form has the class name appended to the function name , which returns the named object (e.g. mouse-point returns a <point>). The second form lists the components as part of the function name, and returns each component individually, as multiple values (e.g. mouse-x-y returns the values x and y). A complete list of the window information functions follows.

colormap-cells (window) => c-m-cells :: <integer>
colormap-full? (window) => c-m-full? :: <boolean>
children (window) => child-seq :: <sequence>
window-containing-x-y (x, y, #key on-display-of = #f) => window
window-containing-point (point :: <point>, #key on-display-of = #f) => window
depth (window)=> colors :: <integer>
exists? (window) => exist? :: <boolean>
distance-to-float-pixels (dist, #rest units) => pixels
geometry (window) => geom-string
height (window) => h
X-id (window) => id :: <integer>
mapped? (window) => map? :: <boolean>
geometry-manager (window) => manager :: <string>
window-with-X-id (id :: <integer>, #key on-display-of = #f) => window
distance-to-pixels (dist, #rest units) => pixels :: <integer>
mouse-x-y (window) => (x, y)
mouse-point (window) => point :: <point>
requested-height (window) => h
requested-width (window) => w
width (window) => w
color-to-r-g-b (window, color :: <string>) => (red, green, blue)
color-to-rgb-color (window, color :: <string>) => rgb-color :: <rgb-color>
abs-position-x-y (window) => (x, y)
abs-position-point (window) => point :: <point>
screen-name (window) => name
screen-colormap-cells (window) => num-cells :: <integer>
screen-depth (window) => bit-depth :: <integer>
screen-height (window) => h
screen-width (window) => w
server (window) => srv :: <integer>
toplevel (window) => top :: <window>
viewable? (window) => view?
visual-class (window) => vis-class :: <string>
available-visuals (window) => avail-vis :: <sequence>
virtual-root-height (window) => h
virtual-root-width (window) => w
virtual-root-position-x-y (window) => (x, y)
virtual-root-position-point (window) => point :: <point>
x-y-in-parent (window) => (x, y)
point-in-parent (window) => point :: <point>

Notes on the functions:

Distance-to-pixels and distance-to-float-pixels take a units paramater that could be one of #"centimeters", #"inches", #"millimeters", or #"points".

X-y-in-parent and point-in-parent return the position of the upper-left corner of the window in it’s parent window.

Abs-position-x-y and abs-position-point return the position of the upper-left corner of the window relative to the root window.

Mouse-x-y and mouse-point return the position of the pointer relative to the argument window.

Anything that returns a <window> or a sequence of <window>s will return a new object which refers to the same Tk widget. A \= method is provided for comparing these to the previously existing ones.

15. Requested Enhancements

Allow event bindings to access the window, mouse coords, character, and other "%" substitutions.

Add better support for scale and scrollbar widgets.

Provide a "focus" command.

Revise the interface to provide a more uniform object-oriented integration of <window>s, <text-tag>s, and <canvas-item>s. (This would probably be an incompatible change.)

16. The Extension Protocol

Because early versions of Dylan/Tk don’t support the entire functionality of Tcl/Tk, users may wish to interface directly with the underlying Tcl/Tk interpreter. This capability is provided by the Tk-extension module. (Note: if any user decides to use these capabilities to provide a firm interface to a Tcl/Tk subsystem (e.g. the "wm" command), we would willingly incorporate such code into future versions of this library.)

The following functions are exported:

tk-as (cls :: <class>, value) => result :: <object> [Generic Function]

put-tk-line (#rest pieces) => () [Function]

call-tk-function (#rest pieces) => result :: <string> [Function]

join-tk-args (#rest object) => result :: <string> [Function]

make-option (option, value) => option :: <string> [Function]

parse-tk-list (string, #key depth, unquote, start, end) => sequence [Function]

tk-quote (object :: <object>) => result :: <string> [Function]

tk-unquote (string :: <string>) => result :: <string> [Function]

anonymous-name (#key prefix = "w") => result :: <string> [Function]

Mindy Compiler Mindy Debugger Mindy Object Extensions Streams Library Standard IO Print Library Format Library Melange Interface TK Library Collection extensions Table Extensions String extensions Regular Expressions Transcendental Library Time Library Random Library Matrix Library

Previous Page TOC Index Next Page See Page

Copyright 1994, 1995, 1996, 1997 Carnegie Mellon University. All rights reserved.

Send comments and bug reports to gwydion-bugs@cs.cmu.edu