Go to the first, previous, next, last section, table of contents.


The Tcl/Tk interface

Author(s): Montse Iglesias Urraca, http://www.clip.dia.fi.upm.es/, The CLIP Group, Facultad de Informática, Universidad Politécnica de Madrid.

Version: 1.10#7 (2006/4/26, 19:22:13 CEST)

Version of last change: 1.9#314 (2004/2/25, 18:27:47 CET)

The tcltk library package is a bidirectional interface to the Tcl language and the Tk toolkit. Tcl is an interpreted scripting language with many extension packages, particularly the graphical interface toolkit, Tk. The interaction between both languages is expressed in terms of an interface between the Tcl/Tk process and the Prolog process. This approach allows the development of mixed applications where both sides, Tcl/Tk and Prolog, can be combined in order to exploit their respective capabilities.

This library uses two sockets to connect both the Tcl and the Prolog processes: event_socket and term_socket. There are also two Tcl global variables: prolog_variables and terms. The value of any of the bound variables in a goal will be stored in the array prolog_variables with the variable name as index. Terms is the string which contains the printed representation of prolog terms.

Prolog to Tcl

The Tcl/Tk side waits for requests from the Prolog side, and executes the Tcl/Tk code received. Also, the Tcl/Tk side handles the events and exceptions which may be raised on its side, passing on control to the Prolog side in case it is necessary.

To use Tcl, you must create a Tcl interpreter object and send commands to it. A Tcl command is specified as follows:

      Command         --> Atom  { other than [] }
                        | Number
                        | chars(PrologString)
                        | write(Term)
                        | format(Fmt,Args)
                        | dq(Command)
                        | br(Command)
                        | sqb(Command)
                        | min(Command)
                        | ListOfCommands
      ListOfCommands  --> []
                        |[Command|ListOfCommands]

where:

Atom
denotes the printed representation of the atom.
Number
denotes their printed representations.
chars(PrologString)
denotes the string represented by PrologString (a list of character codes).
write(Term)
denotes the string that is printed by the corresponding built-in predicate.
format(Term)
denotes the string that is printed by the corresponding built-in predicate.
dq(Command)
denotes the string specified by Command, enclosed in double quotes.
br(Command)
denotes the string specified by Command, enclosed in braces.
sqb(Command)
denotes the string specified by Command, enclosed in square brackets.
min(Command)
denotes the string specified by Command, immediately preceded by a hyphen.
ListOfCommands
denotes the strings denoted by each element, separated by spaces.

The predicates to use Tcl from Prolog are tcl_new/1, tcl_delete/1, tcl_eval/3, and tcl_event/3.

An example of use with Prolog as master and Tcl as slave, consisting of a GUI to a program which calculates the factorial of a number:

:- use_module(library(tcltk)).

go :-
        tcl_new(X),
        tcl_eval(X,[button,'.b',min(text),dq('Compute!')],_),
        tcl_eval(X,[button,'.c','-text',dq('Quit')],_),
        tcl_eval(X,[entry,'.e1',min(textvariable),'inputval'],_),
        tcl_eval(X,[label,'.l1',min(text),dq('The factorial of ')],_),
        tcl_eval(X,[pack, '.l1','.e1'],_),
        tcl_eval(X,[entry,'.e2',min(textvariable),'outputval'],_),
        tcl_eval(X,[label,'.l2',min(text),dq('is  ')],_),
        tcl_eval(X,[pack, '.l2','.e2'],_),
        tcl_eval(X,[pack,'.b','.c',min(side),'left'],_),
        tcl_eval(X,[bind,'.b','<ButtonPress-1>',
                    br([set,'inputval','$inputval','\n',
                    prolog_one_event,dq(write(execute(tk_test_aux:factorial('$inputval','Outputval')))),'\n',
                    set, 'outputval','$prolog_variables(Outputval)'])],_),
        tcl_eval(X,[bind,'.c','<ButtonPress-1>',
                    br([prolog_one_event,dq(write(execute(exit_tk_event_loop)))])],_),
        tk_event_loop(X).

Tcl to Prolog

This is the usual way to build a GUI application. The slave, Prolog, behaves as a server that fulfills eventual requests from the master side, Tcl. At some point, during the user interaction with the GUI, an action may take place that triggers the execution of some procedure on the slave side (a form submit, for example). Thus, the slave is invoked, performs a service, and returns the result to the GUI through the socket connection.

This library includes two main specific Tcl commands:

prolog Goal
Goal is a string containing the printed representation of a Prolog goal. The goal will be called in the user module unless it is prefixed with another module name. The call is always deterministic and its can be either of the following:
1, in case of success
The value of any of the variables in the goal that is bound to a term will be returned to Tcl in the array prolog_variables with the variable name as index.
0, if the execution fails
The Prolog exception Tcl exception is raised. The error message will be "Prolog Exception: " appended with a string representation of such exception.
prolog_event Term
Adds the new term to the terms queue. These can be later retrieved through predicates tcl_event/3 and tk_next_event/2.

Additionally, seven extra Tcl commands are defined.

prolog_delete_event
Deletes the first term of the terms queue.
prolog_list_events
Sends all the terms of the terms queue through the event_socket. The last element is end_of_event_list.
prolog_cmd Command
Receives as an argument the Tcl/Tk code, evaluates it and returns through the term_socket the term tcl_error in case of error or the term tcl_result with the result of the command executed. If the command is prolog, upon return, the goal run on the prolog side is received. In order to get the value of the variables, predicates are compared using the unify_term command. Returns 0 when the sript runs without errors, and 1 if there is an error.
prolog_one_event Term
Receives as an argument the term associated to one of the Tk events. Sends the term through the event_socket and waits for its unification. Then unify_term command is called to update the prolog_variables array.
prolog_thread_event Term
Receives as an argument the term associated to one of the Tk events. Sends the term through the event_socket and waits for its unification. Then unify_term command is called to update the prolog_variables array. In this case the term_socket is non blocking.
convert_variables String
Its argument is a string containing symbols that can not be sent through the sockets. This procedure deletes them from the input string and returns the new string.
unify_term Term1 Term2
Unifies Term1 and Term2 and updates the the prolog_variables array.

The predicates to use Prolog from Tcl are tk_event_loop/1, tk_main_loop/1, tk_new/2, and tk_next_event/2.

An example of use with Tcl as master and Prolog as slave, implementing the well known "Hello, world!" dummy program (more can be seen in directory examples):

Prolog side:

:- use_module(library(tcltk)).
:- use_package(classic).
     
hello('Hello, world!').
     
go :-
        tk_new([name('Simple')], Tcl),
        tcl_eval(Tcl, 'source simple.tcl', _),
        tk_main_loop(Tcl),
        tcl_delete(Tcl).

Tcl side (simple.tcl):

label .l -textvariable tvar
button .b -text "Go!" -command {run}
pack .l .b -side top

proc run {} {

    global prolog_variables
    global tvar 

    prolog hello(X)
    set tvar $prolog_variables(X)
}

Usage and interface (tcltk)

Documentation on exports (tcltk)

PREDICATE: tcl_new/1:

Usage: tcl_new(-TclInterpreter)

PREDICATE: tcl_eval/3:

Meta-predicate with arguments: tcl_eval(?,?,addmodule).

Usage: tcl_eval(+TclInterpreter, +Command, -Result)

PREDICATE: tcl_delete/1:

Usage: tcl_delete(+TclInterpreter)

PREDICATE: tcl_event/3:

Usage: tcl_event(+TclInterpreter, +Command, -Events)

REGTYPE: tclInterpreter/1:

Usage: tclInterpreter(I)

REGTYPE: tclCommand/1:

Usage: tclCommand(C)

PREDICATE: tk_event_loop/1:

Usage: tk_event_loop(+TclInterpreter)

PREDICATE: tk_main_loop/1:

Usage: tk_main_loop(+TclInterpreter)

PREDICATE: tk_new/2:

Usage: tk_new(+Options, -TclInterpreter)

PREDICATE: tk_next_event/2:

Usage: tk_next_event(+TclInterpreter, -Event)


Go to the first, previous, next, last section, table of contents.