Programmation modulaire en Tcl/Tk

 

Introduction

Programmation modulaire, le nom peut paraître compliqué mais vous utilisez tous les jours des logiciels construits selon ce principe de base de la programmation moderne. Il permet entre-autres la création et l'utilisation de "plugins", la programmation par brique ré-utilisables d'un projet à l'autre, la mise à niveau simple et rapide de vos programmes, la gestion de skin pour relooker un logiciel selon vos goûts personnel, etc..

Avec Tcl, non seulement c'est possible, mais en plus c'est simple ! Il suffit d'utiliser des librairies.

Principe d'un librairie

Une librairie (package en anglais) se compose de trois choses : Un nom qui est utilisé pour identifier la librairie. En théorie, vous pouvez choisir le nom que vous voulez, mais on risque d'utiliser le nom d'un librairie déjà existante. Il est donc fortement conseillé de suivre cette règle simple pour nommer vos librairies : nom_prénom_fonction. Un numéro de version Il consiste en un ou plusieurs nombres décimaux séparés par des points. Généralement on utilise trois chiffres : A.B.C : A est le numéro de version majeur, B est le numéro de version mineur et C est le numéro de révision. L'usage veut qu'on augmente le numéro de révision à chaque correction d'erreur, qu'on augmente le numéro de version mineur chaque fois qu'on ajoute des fonctionnalités à la librairie et qu'on augmente le numéro de version majeur chaque fois qu'une modification apportée entraîne une incompatibilité avec les versions antérieures. Il est également d'usage que toute librairie non-stable ait 0 comme numéro de version majeur. Plus le numéro de version est grand, plus la librairie est récente, toute valeur oubliée étant réputé valoir 0. Ainsi, la version 4.1.1 est plus récente que la 3.92 (.0) et plus ancienne que la 6 (.0.0). Un script dont on décrira le contenu plus loin.

Premier exemple : une brique

Nous allons commencer par un exemple extrêmement simple, pour nous concentrer uniquement sur la déclaration, le chargement et le déchargement d'une librairie. Notre script principal sera monprog.tcl et nous allons créer la librairie kroc_basedef qui servira à définir un contexte de base à toutes nos applications en tcl. Dans les scripts qui suivent, les commentaires sont en bleu et le code est indenté comme dans Editt.

Première étape : la librairie kroc_basedef.tcl

    ################################################################################
    #
    # kroc_basedef.tcl
    #
    # Définition d'un contexte uniforme pour les applications en Tcl/Tk
    #
    # Copyright © 2002 - David Zolli http://www.zolli.fr
    #
    # Ce script est sous licence NOL http://wfr.tcl.tk/nol
    #
    # Version 0.0.1 - 02/05/2002 David Zolli
    #
    ################################################################################

    # Avant tout, on a besoin de Tk :
    package require Tk
    # On nomme la librairie :
    package provide kroc_basedef 0.0.1
    # On créé le namespace :
    namespace eval kroc_basedef {
        namespace export *
    }
    # Procédure d'initialisation. Utilisation : Init nom_du_programme os
    proc kroc_basedef::Init { quoi os } {
        set ::kroc_basedef::nom $quoi
        # On donne les couleurs de fond et de premier plan :
        set ::kroc_basedef::bg [[. cget -bg]]
        set ::kroc_basedef::fg #000000
        # On fixe des variables spécifiques à l'OS :
        switch $os {
            "unix" {
                # On indique le chemin correctement :
                set ::kroc_basedef::chemin [[file join /usr/share/ $kroc_basedef::nom]]
                # On donne une police par défaut :
                set ::kroc_basedef::police helvetica
                # On ajuste les couleurs :
                tk_setPalette $kroc_basedef::bg
                option add *background $kroc_basedef::bg
                option add *activeBackground $kroc_basedef::bg
                option add *foreground $kroc_basedef::fg
                option add *activeForeground $kroc_basedef::fg
                option add *selectcolor $kroc_basedef::fg
                option add *disabledforeground $kroc_basedef::fg
                option add *selectBackground $kroc_basedef::fg
                option add *selectForeground $kroc_basedef::bg
                # On maximise la fenêtre principale :
                wm geometry . [[winfo screenwidth .]]x[[expr { [[winfo screenheight .]]-80 } ]]
            }
            "windows" {
                # On indique le chemin correctement :
                set ::kroc_basedef::chemin [[file join c:/progra~1/ $kroc_basedef::nom]]
                # On donne une police par défaut :
                set ::kroc_basedef::police arial
                # On maximise la fenêtre principale :
                wm state . zoomed
                # On fixe l'icone (nécessite winico et un icone) :
                tkwait visibility .
                update idletasks
                set ::kroc_basedef::icone [[winico create [[file join c:/progra~1/ ${kroc_basedef::nom}.ico]]]]
                winico setwindow . $kroc_basedef::icone
            }
        }
        # On va dans le bon répertoire :
        lappend auto_path $kroc_basedef::chemin
        cd $kroc_basedef::chemin
    }

Deuxième étape : pkgIndex.tcl

Maintenant que notre librairie est écrite, nous devons dire à Tcl comment la charger avec la commande /tcltk/manuel/143. Pour ce faire, on utilise la commande package ifneeded. Cette commande peut être indiquée directement dans le script principal ou dans un fichier prévu à cet effet : pkgIndex.tcl dont voici le contenu :

    ################################################################################
    # Fichier d'index des librairies Tcl de Kroc
    ################################################################################

    # Définition d'un contexte uniforme pour les applications en Tcl/Tk :
    package ifneeded kroc_basedef 0.0.1 [[list source [[file join $dir kroc_basedef.tcl]]]]

La seule chose à laquelle il faut prendre garde, c'est de bien indiquer le même nom et numéro de version que ceux utilisés dans la librairie.

Troisième étape : monprog.tcl

Lorsque la commande package est utilisée, tous les fichiers pkgIndex.tcl que Tcl rencontre dans auto_path sont analysés. Sans rentrer dans le détail, la variable auto_path contient au moins le répertoire lib de votre installation de Tcl ( file dirname [info library] ) plus le sous-répertoire tclx.x si vous avez lancé tclsh et le sous-répertoire tkx.x si vous avez lancé wish (x.x étant la version de Tcl installée). Pour que notre pkgIndex.tcl soit traité, il devrait être enregistré dans l'un de ces répertoires, ce qui n'est pas du tout conseillé si on veut conserver un système propre. Il faudra donc ajouter le chemin du répertoire où il est enregistré à l'auto-path pour s'assurer que Tcl trouve notre bibliothèque. Enfin, on va supposer que kroc_basedef.tcl et le pkgIndex.tcl sont enregistrés dans le répertoire kroclib qui est un sous répertoire du répertoire lib de votre installation de Tcl ( /usr/lib/kroclib chez moi) et que monprog.tcl est enregistré dans le répertoire monprog qui est un sous répertoire de /usr/share ou c:\program files\ selon que vous soyez un utilisateur d'unix ou de windows. Voici la portion de script à placer juste après l'en-tête dans monprog.tcl :

    ...
    # Définition du "dir" utilisé dans le "pkgIndex.tcl" de nos librairies :
    set dir [[file join [[file dirname [[info library]]]] kroclib]]
    # Ajout du répertoire de nos librairies à l'auto-path :
    lappend auto_path $dir
    # On charge kroc_basedef :
    package require kroc_basedef
    ...
    # On initialise notre contexte dès que c'est nécessaire :
    kroc_basedef::Init monprog $tcl_platform(platform)
    ...

Avec ces quatres lignes au début de chacun de vos scripts, vous aurez des applications uniformes sans vous fatiguer. Bien entendu, cette "brique" d'exemple fait peu de chose. Mais tout ce que vous ajouterez dedans sera automatiquement ajouté à toutes vos applications qui l'utiliseront. Vous pourrez ensuite créer d'autres librairies : pour ouvrir et enregistrer des fichiers, pour gèrer l'impression, etc..