V Interfaçage avec d'autres langages

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...).

    A Interfacer C et Tcl/Tk

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:

      1 Les différentes étapes

        a) Script Tcl/Tk

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.

        b) Source C

      2 Créer un interpréteur logique 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é.

      3 Définir des fonctions de traitements des événements TCL/TK

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:

        a) Rendre les événements TCL récupérables par C:

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.

    B Note à l'attention des programmeurs ADA:

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.

    C Note à l'attention des programmeurs autres que C et Ada

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.

    D Compilation et édition des liens

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.