Tk est très puissant, malheureusement Tcl l'est moins, ses principaux points faibles sont:
C'est pour cela que lorsque l'on veut écrire une grosse application,
il est indispensable de passer par un langage classique (C, Ada, et pourquoi
pas ML...).
Lier dynamiquement un langage compilé (C en l'occurrence), et
un langage interprété comme TCL/TK paraît étrange,
mais le fait est que cela fonctionne très bien. Tcl/Tk est écrit
en C et les bibliothèques C restent. La fonction permettant d'interpréter
du script Tcl/Tk est elle aussi écrite en C et donc utilisable dans
un programme C.
Le principe de programmation est le suivant:
Associer a chaque événement qui doit être récupéré
par le programme C une variable (globale) TCL. Par exemple si le programme
C doit être averti d'un click sur le bouton OK, le script TCL doit
lier l'événement click souris sur OK avec une écriture
dans une variable TCL.
Un interpréteur logique (type Tcl_interp) est ce qui lie le source C au fichier TCL. La première chose à faire est de créer un interpréteur par la fonction :
Tcl_Intepr * Tcl_CreateInterp().
L'interpréteur créé contient au retour de chaque
fonction TCL appelée des informations sur le statut de la fonction:
quel type d'erreur elle contient , etc... Tout ceci est dans un champs
nommé result du type Tcl_interp.
Ensuite il faut initialiser l'interpréteur TCL par
int Tcl_Init(Tcl_interp * interp)
initialiser l'interpréteur pour qu'il gère TK par
int Tk_Init(Tcl_Interp* interp)
ces deux fonctions étant appelées successivement sur l'interpréteur
renvoyé par Tcl_CreateInterp.
Il ne reste plus qu'à charger le fichier TCL/TK à interpréter à l'aide de la fonction
int Tcl_EvalFile(Tcl_Interp * interp, char * Path) où
path est le chemin d'accès du fichier et interp le même interpréteur
que précédemment.
Ca y est, le fichier est interprété en parallèle avec le programme C. Toutes ces manipulations étant assez ennuyeuses, elles sont regroupées dans une fonction que j'ai écrite.
Cette fonction est donnée en annexe, et pour les paresseux du clavier, elle peut être récupérée sur mon adresse http:
http://www.lisi.ensma.fr/members/grolleau
Elle est définie par Tcl_Interp * InterpreterfichierTCL(char * Path)
Elle renvoie l'interpréteur du fichier TCL donné dans
Path, qui est interprété.
Il y a plusieurs moyens de récupérer les événement
TCL/TK dans le source C. Cependant, il n'y a, à ma connaissance,
qu'une seule méthode pour rendre ces événements récupérables
par C dans le script TCL:
Imaginons que l'on veuille passer l'événement "Click sur OK" à C. Il suffit, dans le "binding" du bouton OK, d'exécuter la ligne:
set OK 1.
Ainsi à chaque fois que l'utilisateur clique sur OK, la variable OK est accédée en écriture.
Maintenant le stratagème utilisé pour récupérer ce click dans le programme C est de tracer la variable OK du script TCL à l'aide de la fonction
Tcl_TraceVar(Tcl_Interp * interp, char * VariableTCL, int flags, Tcl_VarTraceProc * Proc, ClientData data)
Les fonctions appelées lors du traçage d'une variable
sont définies de la façon suivante:
char * ma_fonction_de_traitement (ClientData clientData /* Ca, je
n'en tiens jamais compte*/, Tcl_Interp interp, char * name1, char * name2,
int flags)
C'est TCL qui va se charger d'appeler la fonction de traitement C et d'en remplir les champs dès que la variable TCL tracée est accédée en écriture. Cette fonction peut utiliser des variables internes au programme C à l'intérieur de son corps exactement comme une fonction ordinaire.
Il est indispensable que
les fonctions ainsi définies retournent une valeur. Pour ma part
je termine toutes mes fonctions de traitement par return NULL.
Une fois que le fichier TCL est interprété, que toutes
les variables TCL à tracer ont ainsi été liées
à des fonctions C, il suffit de lancer la fonction Tk_MainLoop()
qui donne la main à l'interface et qui se charge d'appeler les fonctions
C de traitement liées à des variables tracées.
Pour un exemple simple, voir le fichier exemple_C_Tcl.c en annexe.
Puisqu'en ADA, à ma connaissance, il est impossible de passer un pointeur de fonction en paramètre d'une autre, il existe une autre méthode, un peu plus lourde, pour récupérer les événements TCL.
Elle est basée sur la même méthode de programmation du script TCL que précédemment (écriture d'une variable TCL à chaque événement à récupérer), mais là il faut modifier la valeur de cette variable à chaque occurrence d'événement. Le programme ADA se contentera de scruter les valeurs de ces variables dans la boucle principale du programme à l'aide de fonctions comme GetVar ou bien, si c'est possible, LinkVar (mais je ne sais pas si il est possible de lier des variables ADA aux variables TCL comme des variables C au programme TCL). Plus proprement cela peut être fait à l'aide d'une tâche Ada scrutant les événements Tcl/Tk et appelant éventuellement d'autres tâches pour réagir aux événements...
L'interfaçage des fonctions C de Tcl/Tk avec Ada a été faite par Jean-Claude Potier, et ça fonctionne très bien.
A priori, tout langage interfaçable avec C est interfaçable
avec Tcl/Tk. Il suffit d'interfacer chaque fonction des librairies Tcl
et Tk dans le langage, puis de les utiliser comme n'importe quelle autre
fonction.
Pour utiliser toutes les fonctions Tcl/Tk, il faut dans le source:
#include <tcl.h>
#include <tk.h>
Pour compiler, il faut donner l'endroit où le compilateur c peut trouver ces fichiers d'en-tête: cc monfichier.c -Ichemin_de_tk.h_et_tcl.h sur alienor, ils sont dans /home/local/include
Puis pour lier les objets il faut inclure les librairies libtcl.a et libtk.a avec les options -ltk et -ltcl. De plus si ces librairies ne sont pas dans les répertoires par défaut ajouter
-Lchemin_des_librairies_tcl_et_tk, sur alienor
c'est /home/local/lib.
L'ordre -ltk -ltcl, tk avant
tcl, est important lors de l'édition de liens.