Introduction à Tcl / Tk
Tcl = Tool Command Language / Tk = graphical ToolKit
| Arnaud LAPREVOTE Free&ALter Soft 77, rue de Pont-à-Mousson 57950 MONTIGNY FRANCE 32, bd Paul Vaillant-Couturier 93100 MONTREUIL FRANCE arnaud.laprevote@freealter.com |
Table des matières
1. Introduction
1.1. Pourquoi un cours sur le tcl/tk ?
1.2. Et la concurrence ?
1.3. Autres avantages
1.4. Inconvénients
1.5. Success stories
1.5.1. Free&ALter Soft
1.5.2. Thomcast
1.5.3. TCL vs C++
1.6. Historique
2. Tcl
2.1. Vos premiers pas en Tcl
2.1.1. Le premier pas
2.1.2. Le deuxième pas
2.2. La syntaxe du tcl
2.2.1. La clé du tcl : la substitution
2.3. Types de données
2.3.1. Les chaînes de caractères et les scalaires
2.3.2. Les listes
2.3.3. Chaînes et expressions régulières
2.3.4. Les tableaux associatifs
2.4. Commandes de contrôle
2.4.1. Conditions, boucles, contrôle de l'exécution
2.4.2. Fonctions et procédures
2.5. Entrées/sorties
2.6. Gestion des erreurs
2.7. Récapitulatif des commandes du Tcl
2.8. Pas toujours les mêmes
2.8.1. Lecture de fichiers
2.8.2. Lecture des arguments d'un programme
3. Tk
3.1. Premier pas en Tk
3.2. Création d'un widget
3.3. Modification des paramêtres d'un widget existant
3.4. Mort d'un widget
3.5. Les options standard
3.6. A vous Cognaq-Jay
3.7. Placement des widgets
3.8. Le packer dans le détail - les options de pack
3.9. Exercice
3.10. Les frames
3.11. Le gridder
3.12. Evénements disponibles
3.13. Liste des widgets disponibles
3.14. Les boutons
3.15. Les labels
3.16. Les entrées de texte
3.17. Les cases à cocher
3.18. Les boutons radio
3.19. Les menus
3.20. Les images
3.21. Interface graphique contre grosse fatigue
3.22. Vous n'allez pas rigoler
3.23. La prochaine fois
4. Le widget text
4.1. Création du widget
4.2. Insertion, récupération et recherche de texte
4.3. Mais quels sont donc ces tags, qui tapent sur vos têtes ?
4.4. Et avec des images en plus
4.5. Et même d'autres widgets
4.6. Les Marques jaunes ?
4.7. Couper, copier, coller, dodo
5. Le widget canvas
5.1. Quelques élucubrations générales
5.2. Tirons une ligne, un point c'est tout
5.3. Si c'est rond, ...
5.4. Aux arcs citoyens
5.5. Tu polygones ?
5.6. Jouons aux 4 coins
5.7. Le poids des mots
5.8. Le choc des photos
5.9. Le noir et blanc c'est dépassé
5.10. Des fenêtres dans les canevas
6. Ce qu'il reste à dire
6.1. Reste des commandes tcl
6.2. Rest des commandes tk
6.3. Les packs pour tk intéressants
6.4. La programmation des bases de données avec tcl/tk
6.5. La programmation cgi en tcl
6.6. Programmation professionnelle de scripts cgi en tcl
6.7. Scilab et tcl
6.8. Ptolemy et tcl
6.9. Comment ajouter des commandes natives tcl en C
6.10. Comment intégrer des fenêtres X dans une application tk
6.11. Readconf
6.12. Tcl et windows grâce à optcl
6.13. La librairie std tcl
6.14. Plus de détails sur les builders pour tcl et les ide
6.15. Comment débogguer le tcl ?
6.16. Les ressources sur internet intéressantes concernant tcl/tk
1. Introduction
1.1. Pourquoi un cours sur le tcl/tk ?
Je me présente, je m'appelle Henri. Euh non, Arnaud LAPREVOTE (arnaud.laprevote@freealter.com tel. : 03 87 50 83 01). Je suis le gérant d'une société s'appelant Free&ALter Soft.
Il était une fois un programmeur qui avait passé des milliers d'heures à programmer en C, particulièrement des applications de calculs scientifiques (traitement vidéo). Avec les années, il avait acquis une grande facilité dans l'écriture des programmes C, et en même temps une certaine impatience.
Autant le C le satisfaisait pour le calcul scientifique, autant dès qu'il fallait traîter des fichiers ou des chaînes de caractères, il trouvait que c'était fastidieux et surtout générateur d'erreurs de manière inacceptable.
Comme tout le monde, il avait entendu parler des langages de scripts genre perl, tcl/tk, et autres (python). A l'occasion de l'installation de son PC sous linux, il prit le temps de commencer à programmer en tcl.
Et ce fut un choc. Plus de pointeurs, plus de gestion mémoire, de l'idée au programme en un minimum de lignes. Tout cela trivial à apprendre et gratuit et redistribuable, fonctionnant sous unix (tous les unix) et sous windows. Capable de faire des interfaces graphiques de manière très facile, de la programmation cgi en plaisantant. Facile à expliquer. Génial.
Ce programmeur, c'est moi. Et j'ai très envie de vous faire partager cette passion pour mon langage préféré.
1.2. Et la concurrence ?
Il y a de très nombreux concurrents au Tcl/Tk :
- Perl,
- Python,
- Scheme (lisp),
- dans une certaine mesure PHP,
- Visual Basic,
- Java.
Tous ces langages ont des avantages et des inconvénients. Mes critères de choix principaux sont :
- open source (source disponible, gratuit, redistribuable),
- lisibilité (facilité à maintenir et débogguer),
- multi-plateforme (unix, linux, windows),
- grand nombre d'extension.
Un dernier avantage est que le Tcl n'a pas une ambition infinie. Le Tcl ne veut pas TOUT faire. C'est juste un langage de "colle" pour faire tenir un ensemble d'application ensemble. Si vous voulez faire des choses très grosses ou très complexes ou très rapides, vous êtes priés de vous tourner vers le C, le C++ ou le java.
A cette lumière, il ne reste que le python et le tcl, à la limite le perl. La syntaxe du perl me rend fou, donc je l'exclus. Je m'intéresse au Python.
1.3. Autres avantages
Les points suivants méritent d'être soulignés :
- fonctions réseaux (socket) intégrées très élégamment au langage. Un serveur web se fait en claquant des doigts,
- faciliter d'intégration du tcl dans une application existante,
- très grande robustesse du langage,
- faciliter d'intégration de fonctions C dans le Tcl,
- la compatibilité ascendante n'est pas une théorie mais une réalité,
- très forte cohérence due à une origine universitaire.
1.4. Inconvénients
Tout n'est pas parfait en tcl.
- le langage n'est pas en GPL => moins grande dynamique du langage que le python ou le perl,
- il n'est pas possible de définir de vrais structures en tcl (au sens C du terme). Cela peut nuire à la lisibilité des programmes et limite la taille de ce que l'on peut programmer. On peut se tourner vers les extensions objets du tcl pour avoir ces fonctions,
- il manque une IDE libre avec un déboggueur intégré pour faciliter la prise en main par les débutants.
1.5. Success stories
1.5.1. Free&ALter Soft
Free&ALter Soft, c'est :
| 1997 | 1998 | 1999 | 2000 | |
| CA (kF) | 330 | 440 | 885 | 1970 |
| Effectif | 2 | 2 | 2.5 | fin 2000 - 6 |
Une grande partie du chiffre d'affaire repose sur la capacité à montrer très vite des programmes prototypes fonctionnant. Et cela est du à 2 paramètres :
- une grande maîtrise des logiciels libres : nous prenons tout ce que nous pouvons ailleurs et nous l'adaptons,
- l'utilisation du tcl pour faire tenir tous les bouts ensembles.
1.5.2. Thomcast
Au tout début de FAS, un copain à moi bossez chez Thomcast. Il avait besoin d'un développement intranet. Je ne connaissais vraiment pas grand chose au web. Il m'a dit, vient, tu apprendras. 10 jours plus tard, il avait une application cgi permettant de commander toutes les pièces de rechange existantes chez Thomcast.
Au passage, j'avais formé un programmeur Cobol en 3 jours au tcl. Et au bout de 3 jours, je lui posais des questions.
1.5.3. TCL vs C++
Nous avons utilisé un sous-traitant pour nous aider pour la qualité sur un projet de développement ISO. Un jour nous avions une idée, il fallait via un cgi afficher toutes les images d'un répertoire. Lors du clique sur l'image, un autre script cgi était appelé avec comme paramêtre le nom de la vignette sans son extension.
Mon collègue et ami est un programmeur expérimenté (DESS informatique, 10 ans d'expérience embarqué, bases de données, ASP, VB applications, ...). Je lui ai dit dans 10 minutes cela marche. 23 minutes après, l'interface était opérationnelle. Il m'a avoué ensuite avoir passé avec un autre programmeur plus d'une demi-journée pour faire quelque chose d'avoisinant en Visual C++ avec la génération de l'interface et le reste.
La productivité du tcl, c'est cela. Certes, cela n'est utile que quand il n'y a pas de contraintes de performances. Cela ne représente guère plus de 90% des programmes.
1.6. Historique
Tcl fut créé en 1990 par John OUSTERHOUT à l'Université de Berkeley. C'est un language de "collage" pour attacher ensemble plusieurs applications. C'est un langage interprété mais compilé à la volée depuis la version 8.0. La version actuelle est Tcl 8.3.
Après Berkeley, John Ousterhout est passé chez Sun, puis il a créé sa propre société Scriptix qui est devenue ensuite Ajuba Solutions et a été rachetée récemment. Des centaines de programmes et de société utilise le tcl, mais souvent de manière souteraine. Tcl est donc un langage discret.
2. Tcl
2.1. Vos premiers pas en Tcl
2.1.1. Le premier pas
Pour démarrer un interpréteur tcl, tapez :
tclsh |
Ou sous windows, allez dans le menu démarrer, déroulez le sous-menu tcl puis cliquez sur tclsh ou wish(plutôt wish).
Vous obtenez alors un prompt en %. Taper ce qui suit % dans les lignes suivantes :
% set myname "Arnaud LAPREVOTE" Arnaud LAPREVOTE % puts $myname Arnaud LAPREVOTE % set i 0 0 % puts $i 0 % incr i 1 % format "%s : %d" $myname $i Arnaud LAPREVOTE : 1 |
Les points clés de cet exemple sont :
| COMMANDES | set nom_de_variable "valeur" puts "chaine de caractères" incr nom_de_variable_numérique [incrément] format # printf format "format string %s %d ...." $chaine $valeur |
2.1.2. Le deuxième pas
% for { set i 0 } { $i < 3 } { incr i } {
puts $i
puts "$i"
puts [ format " Free&ALter Soft : %d" $i]
}
0
0
Free&ALter Soft : 0
1
1
Free&ALter Soft : 1
2
2
Free&ALter Soft : 2
% #this is a remarque
% set i 0; set j 1; #that also
1
|
| COMMANDES | for { initialisation } { end condition } { incrementation } { code running at each loop } |
| SYNTAXE | [argument1] [argunment2] first_command; second_command "$substitution" "$caracter printed as is" [immediate execution] {execute as late as possible} #remarque |
2.2. La syntaxe du tcl
Un des problèmes du tcl est sa simplicité. Concernant sa syntaxe, il n'y a guère que 2 choses à savoir.
Le premier mot de la commande est TOUJOURS la commande.
commande argument1 argument2 argument3 ... |
Donc en tcl, pour initialiser une variable on écrit :
set toto "xxxx" |
ET PAS
toto = "xxxx" |
Les arguments de la commande sont séparés les uns des autres par des espaces.
D'où obligatoirement :
for {set i 0} {$i < 4} {incr i} {
}
|
Et non pas
for{set i 0}{$i < 4}{incr i}{
}
|
2.2.1. La clé du tcl : la substitution
Il y a une finesse en tcl. Les substitutions. L'interprétation d'une ligne se fait en 2 temps :
- substitution de tout ce qui est substituable (variable, code entre crochets []),
- exécution de la commande.
Donc :
% set toto "TOTO" TOTO % set tata "$toto" TOTO % set titi "[expr 1 + 2]" 3 % set tutu [string trim [string tolower "Ceci Est Une Phrase avec des espaces au bout : $toto va "]] ceci est une phrase avec des espaces au bout : toto va % set tutu "[string trim [string tolower "Ceci Est Une Phrase avec des espaces au bout : $toto va "]]" ceci est une phrase avec des espaces au bout : toto va % puts "--$tutu--" --ceci est une phrase avec des espaces au bout : toto va-- |
L'exécution d'un code entre [] et la substitution dans l'expression appelante du contenu de [] par son résultat. C'est ce que l'on appel de la programmation fonctionnelle. Le lisp est l'archétype de ces langages. Le tcl permet de mélanger élégamment programmation fonctionnelle et procédurale. Dans certains cas (les traitements sur des chaînes de caractères) la programmation fonctionnelle est TRES (très, vraiment très, j'insiste encore ? non) pratique.
Pour empécher la substitution, on utilise les accolades { } :
% set toto {TOTO}
TOTO
% set tata {$toto}
$toto
% set titi {[expr 1 + 2]}
set titi {[expr 1 + 2]}
% set tutu [string trim [string tolower "Ceci Est Une Phrase avec des espaces au bout : $toto va "]]
ceci est une phrase avec des espaces au bout : toto va
% set tutu {[string trim [string tolower "Ceci Est Une Phrase avec des espaces au bout : $toto va "]]}
[string trim [string tolower "Ceci Est Une Phrase avec des espaces au bout : $toto va "]]
% puts {--$tutu--}
--$tutu--
|
Pour affiner ces notions, on peut ajouter que le caratère (antislash), force l'interprétation du caractère le suivant comme étant un simple caractère et rien d'autre :
set toto {TOTO}
TOTO
% set tata "\$toto"
$toto
% set tata Ce\ qui\ suit\ est\ une\ seule\ chaîne
Ce qui suit est une seule chaîne
% puts "\[ pas d'interprétation hative ]"
[ pas d'interprétation hative ]
|
Et que l'on peut utiliser les accolades autour d'un nom de variable pour lever l'ambiguité :
% set var1 "CONTENU ORIGINE"
CONTENU 1
% set var12 "AUTRE CONTENU"
AUTRE CONTENU
% puts "${var1}2"
CONTENU ORIGINE2
% puts "${var12} == $var12"
AUTRE CONTENU == AUTRE CONTENU
|
Si vous avez complètement compris ce qui précédait, alors une friandise (sinon c'est le moment de piquer un roupillon, de papoter avec les voisins, de se taper un carton, de relever ses SMS, et de noter qu'il faut relire le paragraphe qui suit dans 15 jours).
L'instruction eval permet de forcer une évaluation supplémentaire, et de temps en temps c'est fantastique (le préprocesseur de tcl est tcl contrairement au C):
#!/usr/bin/tclsh
set var1 "Un"
set var2 "Deux"
set var3 "Trois"
set var4 "Quatre"
set var5 "Cinq"
set var6 "Six"
for { set i 1 } { $i < 7 } { incr i } {
set command "puts \$var$i"
eval $command
}
Un
Deux
Trois
Quatre
Cinq
Six
|
2.3. Types de données
2.3.1. Les chaînes de caractères et les scalaires
- scalaire : tcl 7.6 - chaînes seulement => tcl 8.0 - chaînes et valeurs.
Tout est chaîne en tcl : c'est la clé de la facilité d'interaction : toute fonction peut envoyer des résultats à n'importe quelle autre.
%set str1 "0123456789"
%string length $str1
10
%string index $str1 5
5
%string range $str1 0 4
01234
% string compare $str1 "101112131415"
-1
%proc frame_string { str } {
format "###->%s<-###" $str
}
%frame_string "Arnaud LAPREVOTE"
###->Arnaud LAPREVOTE<-###
%frame_string "Arnaud LAPREVOTE "
###->Arnaud LAPREVOTE <-###
%frame_string [string trimright "Arnaud LAPREVOTE "]
###->Arnaud LAPREVOTE<-###
|
| COMMANDES | string length $a_string string index $a_string index ; #(0 is first) string range $a_string first_index last_index |
| SYNTAXE | proc function_name { list of args } { instructions return 5 } |
2.3.2. Les listes
On utilise beaucoup les listes en tcl.
set mylist [list "toto et tata" 1 [list 1 2 3] stop]
{toto et tata} 1 {1 2 3} stop
% puts [llength $mylist]
4
% lindex $mylist 0
toto et tata
% lrange $mylist 0 1
{toto et tata} 1
% lsort $mylist
1 {1 2 3} stop {toto et tata}
% set mylist [linsert $mylist 1 coucou]
{toto et tata} coucou 1 {1 2 3} stop
% lappend mylist "why not"
{toto et tata} coucou 1 {1 2 3} stop {why not}
% puts $mylist
{toto et tata} coucou 1 {1 2 3} stop {why not}
% split "1,2,3,4,5,6" ,
1 2 3 4 5 6
|
| COMMANDES | Description |
| list first_elt second_elt ... | Création d'une liste. Renvoi une liste. |
| llength $a_list | Renvoi le nombre d'élément de la liste |
| lindex $a_list elt_nber | Renvoi l'élement n° elt_nber de la liste. elt_nber peut être end (dernier élément). |
| lrange $a_list start_nber end_nber | Renvoi une liste composée des éléments commençant ) start_nber et finissant à end_nber |
| lsort $a_liste | Ordonnancement de la liste. De nombreuses options permettent de classer en ordre croissant / décroissant, en utilisant un élément d'une sous-liste comme clé, en ordre numérique, ... Renvoi une liste |
| linsert $a_list nber elt_to_insert | Insère un élement dans une liste à l'endroit indiqué. Renvoi une liste. |
| lappend a_list elt_to_append_at_the_end | Ajoute les éléments suivant à la fin de la liste. ATTENTION LAPPEND NE RENVOI PAS DE LISTE. IL MET AU BOUT DE LA LISTE NOMMEE a_list LES ELEMENTS. |
| split "chaine de caractère" [caractère] | Transforme une chaîne de caractères en une liste. Le séparateur est le caractère fourni en second paramètre. |
2.3.3. Chaînes et expressions régulières
Les expressions régulières sont une fonction clé des langages de scripts (ksh, perl, awk, tcl, python, ...). Elles ne sont pas du tout naturelles, mais une fois comprise, elles sont un outil très puissant. Vous devez les essayer !
Une seule méthode pour survivre en United States of Regular Expressions : essayez d'abord, puis programmez. Même une ceinture noire 4ème dan de tcl fait comme cela.
| COMMANDES | regexp {sf(first expr)(second expr)} $string matching_string first_matching_str second_matching_string
|
%set reg "This is a string = 12"
string = 12
% regexp {([a-zA-Z]*) *= *([0-9]*)} $reg string var val
1
% puts $string
string = 12
% puts $var
string
% puts $val
12
% set reg "string = 12; # forget the rest"
string = 12; # forget the rest
% regsub {([a-zA-Z]*) *= *([0-9]*)} $reg \
{and \2 = \1} string
1
%puts $string
and 12 = string; # forget the rest
|
2.3.4. Les tableaux associatifs
%set good(name) "Free&ALter Soft"
%set good(first_name) "Laprevote"
%set good(sur_name) "Arnaud"
%proc puts_array { current_array } {
upvar $current_array good
foreach name [array names good] {
puts "$name = $good($name)"
}
}
%puts_array good
first_name = Laprevote
name = Free&ALter Soft
sur_name = Arnaud
|
| COMMANDES | ||
| set toto(tata) "string" | Initialisation à string de l'entrée tata dans le tableau toto | |
| array exists name | Renvoi 1 si le tableau name existe | |
| array names name | Renvoi la liste des entrées du tableau | |
| array get name | Liste de paiares clé valeur du tableau name | |
| array set name list | Initialise le tableau name en utilisant une liste à la syntaxe identique au résultat de array get name | |
| parray name | Affichage du tableau name | |
| Passage d'un tableau par pointeur à une fonction |
2.4. Commandes de contrôle
2.4.1. Conditions, boucles, contrôle de l'exécution
if { condition } {
#code à exécuter si la condition est vraie
} elseif { condition2 } {
# code à exécuter si la condition2 est vraie
} else {
# code à exécuter si aucune condition n'est vraie
}
|
while { condition } {
# code à exécuter tant que la condition est vraie
}
|
switch valeur {
value1 {
#code à exécuter si valeur remplie la condition value1
}
value2 {
#code à exécuter si valeur remplie la condition value2
}
default {
#code à exécuter si aucune des conditions précédentes n'est vraie
}
}
|
Les options -exact -glob et -regexp permettent de choisir le type de règle de comparaison utilisé. Pour distinguer les options de switch de l'argument final de switch on utilise -- :
switch -exact -- $toto {
1 {
puts 1
}
}
|
Si l'on est en mode -exact de switch, on cherche la section de switch dont la valeur est strictement identique à l'argument de switch.
Si l'on est en mode -glob, alors * remplace n'importe quel caractère zéro ou plusieurs fois. Donc :
set toto test
switch -glob -- $toto {
t* {
puts "Mode test"
}
default {
puts "Autre chose"
}
}
|
Enfin en mode regexp, on utilise un mode de comparaison de type expression régulière.
set toto test
switch -regexp -- $toto {
[tT].* {
puts "Mode test"
}
default {
puts "Autre chose"
}
}
|
Un exemple plus complet :
set i 0
while { $i < 200 } {
switch -exact -- $i {
0 {
puts "Je ne vois pas de mouton"
}
1 {
puts "Whoua un mouton là"
}
100 {
puts "T'en a pas marre des moutons ?"
puts "Tape Ctrl-c pour arréter du plouc !"
}
default {
puts "$i moutons"
}
}
incr i
}
puts "J'ai une indigestion de mouton,"
puts "plus le mal de mer et la tête lourde"
puts "avec une grosse envie de dormir. J'arrête."
|
for { # code d'initialisation } { condition } { # passage à l'état suivant (typ. incrémentation } {
# code à exécuter
}
|
Exemple
for { set i 1 } { $i < 100 } { incr i } {
if { $i == 1 } {
set pluriel ""
} elseif { $i == 57 } {
puts "Un mosellan"
set pluriel "s"
}else {
set pluriel "s"
}
puts "$i mouton${pluriel}"
}
|
Enfin, il ne faut pas oublier l'instruction foreach. Cette instruction permet de boucler sur les éléments d'une liste.
set l [list lundi mardi mercredi jeudi vendredi samedi dimanche]
foreach jour $l {
switch -regexp -- $jour {
^[lmmjvs].* {
puts "Le $jour on bosse"
}
default {
puts "Le $jour on bulle"
}
}
}
|
2.4.2. Fonctions et procédures
La commande permettant de définir une procédure est proc. C'est une commande comme une autre qui prend 3 arguments :
proc nom_de_la_procedure { liste des arguments } {
# code a exécuter quand la procédure est appelée.
# Les valeurs des variables $liste $des et $arguments sont disponibles
# On peut avoir accès aux variables défini au niveau 0 de l'exécution
# avec l'instruction global
# upvar permet de passer des variables par pointeur
# on retourne une valeur avec :
return 1
}
|
Exemple :
#!/usr/bin/tclsh
set DEBUG 1
proc debug { message } {
global DEBUG
if $DEBUG {
puts $message
}
}
proc read_file { filename } {
if { [catch { open $filename } fileid] } {
puts "Impossible d'ouvrir $filename"
return ""
}
debug "Le fichier $filename est ouvert"
set full_text [read $fileid]
# Je vais renvoyer la liste des lignes du fichiers
return [split $full_text "\n"]
}
set cour1_list [read_file "cour1.txt"]
puts "$cour1_list"
|
2.5. Entrées/sorties
Les commandes sont les suivantes :
| gets seek flush close read tell puts file |
La commande open retourne un identifiant qui sera utilisé lors des appels aux autres commandes.
Ex:
set f [open "toto.txt" "r"] => file4 set toto [read $f] => xxxxxx close $f |
Ou encore :
set f [open "titi.txt" w] => file4 puts $f "Ecrit ce texte dans le fichier" # puts permet d'écrire dans un canal déterminé (défaut sortie standard) close $f |
Les autres commandes utiles sont :
# lecture d'une ligne set x [gets $f] # read permet de lire un certain nombre d'octets read $f 100 # seek pour se positionner set f [open "database" "r"] seek $f 1024 read $f 100 Ici on lit les octets 1024 a 1123 |
2.6. Gestion des erreurs
La commande catch permet d'attraper les erreurs :
if [catch { n'importe quoi }] {
puts "Vous avez du taper une bétise dans la commande appelée par catch"
exit
}
|
Tout cela est bien sûr très utilisé lors de l'ouverture d'un fichier en lecture ou en écriture et plus généralement dès que l'on communique avec l'extérieur.
catch { exec cp toto tutu }
|
La commande error permet elle de générer une erreur dans un code et d'y associer un message d'erreur.
2.7. Récapitulatif des commandes du Tcl
| COMMANDES TRES UTILISEES |
|
| MOINS USITEES |
|
Comme vous pouvez le remarquer, cela représente vraiment peu de commandes, ce qui explique la facilité d'apprentissage du tcl.
2.8. Pas toujours les mêmes
2.8.1. Lecture de fichiers
L'objectif est d'écrire un programme tcl qui parcourrera un fichier html et donnera la liste des noms entre les tags html
et
et toute les variantes de ces tags. La liste sera imprimée sur la sortie standard.2.8.2. Lecture des arguments d'un programme
Vous souhaitez écrire un programme qui a des options d'appel en ligne de commande. En particulier :
-h[elp] : affichage d'une aide
-f[ile] nom_de_fichier : fichier d'entrée,
-l[evel] [0-9]+ : niveau de recherche de 1 à ce que vous voulez.
Les arguments peuvent être passés sur la ligne de commande dans n'importe quel ordre. A la fin de l'initialisation de la fonction vous avez 3 drapeaux à 1 ou 0 indiquant si les options -help, -file ou -level ont été appelées. Le nom du fichier d'entrée et le niveau sont stockés dans les variables filename et level.
Lors de l'appel d'un programme, les variables suivantes sont disponibles :
- argc : nombre d'argument sur la ligne de commande (stockée dans argv),
- argv : liste des arguments sur la ligne de commande, sans la commande,
- argv0 : nom de la commande,
- env : tableau contenant les variables d'environnement.
#!/usr/bin/tclsh
puts "argc : $argc"
puts "argv : $argv"
set i 0
foreach arg $argv {
puts "argument $i : $arg"
incr i
}
puts "argv0 : $argv0"
|
Nous appelons cette commande args.tcl et la rendons exécutable puis testons :
args.tcl -f test.html -l 2 $ ./args.tcl argc : 0 argv : argv0 : ./args.tcl $ ./args.tcl -f test -level 3 argc : 4 argv : -f test -level 3 argument 0 : -f argument 1 : test argument 2 : -level argument 3 : 3 argv0 : ./args.tcl |
Il ne vous reste plus qu'à créer une variable menu_state, initialisée à get_args. Pendant que vous parcourez les paramètres un à un, vous testez (avec un switch) l'argument, si c'est -l*, vous changez menu_state en level, et à l'argument d'après comme vous êtes en level, vous savez que arg est le niveau. Vous réinitialisez ensuite menu_state à get_args. Faite la même chose avec -f en passant menu_state à file.
Bon courage. Merci de ne pas oublier le guide à la fin de la visite. A votre bon coeur M'sieur dame.
3. Tk
Tk est le companion graphique de tcl. Il contient en particulier les widgets suivants :
- bouton
- label
- entrée de texte
- menu
- photo
- fenêtre de sélection de fichiers, de couleurs, ...
- ...
Ce qui n'est pas directement dans Tk peut être trouvé directement dans des extensions supplémentaires, telles que Blt (widget de tracé de courbes), les Bwidgets, html. On commence aussi à trouver des méga-widgets directement écrits en tk (combobox, notepad, arbre).
3.1. Premier pas en Tk
Pour créer une interface, on :
- défini chaque widget et ses attributs,
- dispose les widgets dans la fenêtre ( pack ou grid ),
- défini les commandes associées aux actions.
Tk gère intégralement la boucle de suivi des événements. On ne s'en préoccupe pas.
#!/usr/bin/wish
label .nouveau_label -text "Je dis juste bonjour !"
button .say_ok -text "OK ?"
pack .nouveau_label .say_ok -side top
bind .say_ok <Button-1> { exit }
bind .say_ok <Button-2> { .nouveau_label configure -text "Vous avez appuyez sur le bouton 2" }
|
Ou encore plus simplement :
#!/usr/bin/wish
label .nouveau_label -text "Je dis juste bonjour !"
button .say_ok -text "OK ?" -command { exit }
pack .nouveau_label .say_ok -side top
|
3.2. Création d'un widget
Le nom d'un widget est toujours :
.xxxx.yyyy.zzzz
Dans ce cas on crée le widget zzzz qui se trouve dans le widget yyyy qui se trouve dans le widget xxxx. xxxx pourrait parfaitement être une nouvelle fenêtre ou un widget.
#!/usr/bin/wish
toplevel .nouvelle_fenetre
label .nouvelle_fenetre.label -text "Je dis juste bonjour !"
button .nouvelle_fenetre.say_ok -text "OK ?" -command { destroy .nouvelle_fenetre }
pack .nouvelle_fenetre.label .nouvelle_fenetre.say_ok -side top
|
Lors de la création d'un widget, des paramètres sont initialisés. Par exemple, dans :
label .exemple_label -text "Je dis juste bonjour !" |
Lors de la création du label .exemple_label, on vient initialiser son paramètre -text à la valeur "Je dis juste bonjour !".
Il est constamment possible de changer un paramètre d'un widget avec la commande configure.
Les valeurs initialisables pour un widget varie d'un widget à l'autre. Cependant il y a un certain nom de paramètre qui sont systèmatiquement initialisables pour les widgets. La liste de ces options par défaut est disponible :
man options
options(n) Tk Built-In Commands options(n)
_________________________________________________________________
NAME
options - Standard options supported by widgets
_________________________________________________________________
DESCRIPTION
This manual entry describes the common configuration
options supported by widgets in the Tk toolkit. Every
widget does not necessarily support every option (see the
manual entries for individual widgets for a list of the
standard options supported by that widget), but if a wid-
get does support an option with one of the names listed
below, then the option has exactly the effect described
below.
In the descriptions below, ``Command-Line Name'' refers to
.........
|
3.3. Modification des paramêtres d'un widget existant
Reprenons notre petit exemple :
label .exemple_label -text "Je dis juste bonjour !" pack .exemple_label after 1000 .exemple_label configure -text "puis au revoir" after 1000 |
Comme vous pouvez le constater configure a permis de changer la valeur d'un paramêtre d'un widget. Si vous souhaitez connaître la liste de tous les paramêtres d'un widget, il vous suffit de taper :
.nom_du_widget configure
Si vous souhaitez connaître a valeur d'un paramètre donné, vous pouvez utiliser la commande cget :
% label .exemple_label -text "Je dis juste bonjour !" % pack .exemple_label % .exemple_label cget -text Je dis juste bonjour ! |
Remarque
Dis tonton Arnaud, tu nous as bassiné avec le fait qu'une ligne tcl consistait toujours en :
commande argument1 argument2 ... |
Or je constate ici que l'on a :
nom_du_widget commande argument1 ... |
Il y a tromperie sur la marchandise, remboursez !!!!!
Réponse de tonton Arnaud
Que nennie !!! Lorsque l'on crée un widget, une commande portant le nom du widget est créé et configure est un argument de cette commande comme un autre.
3.4. Mort d'un widget
Tout à une fin. On peut détruire un widget avec la commande :
destroy .nom_du_widget
3.5. Les options standard
| Option | Signification |
| -background | couleur de fond du widget. Ou un mot (red, ...) ou une chaine définissant rgb avec des valeurs hexa (noir : "#00000", blanc : "#ffffff", rouge : "#ff0000") |
| -activebackground | couleur de fond lorsque le curseur est sur le widget |
| -foreground | la couleur du texte quand le curseur n'est pas sur le widget |
| -activeforeground | la couleur du texte quand le curseur est sur le widget |
| -text | le texte du boutton |
| -textvariable | une variable dont le contenu s'affichera dans le widget |
| -image | une image précédemment chargée |
| -bitmap | un bitmap qui s'affichera dans le widget |
| -padx | espace de garde à droite et à gauche du widget |
| -pady | espace de garde au-dessus et en dessous du widget |
| -anchor | l'élément interne au widget (texte ou graphique) sera collé à la partie haute (nord => n) basse (sud => s) droite (est => e) ou gauche (ouest => w) ou au centre (center). |
| -width | largeur en caractères du widget |
| -height | hauteur en caractères du widget |
| -justify | right, left, center. Si le widget contient un texte sur plusieurs lignes, la justification choisie sera appliquée. |
3.6. A vous Cognaq-Jay
Créez une application contenant un label, un bouton "Quitter", un bouton "Changer". Au départ, sur le label on lit :
Je dis juste bonjour |
Quand on clique sur le bouton "Changer", le label devient "Vous venez de cliquer sur le bouton Changer", si on reclique, on revient à "Je dis juste bonjour" et ainsi de suite. Si on clique sur le bouton "Quitter", l'application se termine.
Le bouton "Quitter" a un fond rouge, quand le curseur passe dessus se fond devient rose (#ff8080).
Dans une seconde version, vous garderez cette même application, ajouterez les boutons flat, groove, sunken, ridge. Lors de l'appui sur ces boutons, la propriété -relief du label changera et prendra la valeur flat, groove, sunken, ridge.
Je paye personnellement un coca-cola à celui qui réussira à faire ce dernier exercice avec une boucle sur la liste [list flat groove sunken ridge].
3.7. Placement des widgets
3 modes de placement existent :
- pack
- grid
- place
Le packer :
frame .top label .top.label -text "Name" entry .top.name -textvariable name image create photo test -file !/usr/src/linux/Documentation/logo.gif label .bottom -image test pack .top.label .top.name -side left pack .top .bottom -side top |

Les widgets sont placés en colonnes ou lignes. Les colonnes ou les lignes sont créées les unes après les autres. Pour obtenir des placements par groupe de widget on utilise des frames qui vont contenir des widgets en horizontal ou en vertical.
Le grider :
label .one -text "One" entry .one_entry -textvariable one_entry label .two -text "BIIIIIG TWO" entry .two_entry -textvariable two_entry label .three -text "Un très grand commentaire" grid .one -column 1 -row 1 grid .one_entry -column 2 -row 1 grid .two -column 1 -row 2 grid .two_entry -column 2 -row 2 grid .three -column 1 -row 3 -columnspan 2 -stick e |
Les widgets sont placés sur une grille (comme dans un tableau html pour ceux qui connaissent). La taille des colonnes est calculée automatiquement.
Le placer permet de placer les widgets en donnant directement leurs coordonnées. Je ne l'ai jamais utilisé.
3.8. Le packer dans le détail - les options de pack
On peut utiliser la commande pack avec les options :
-side [left|right|top|bottom] |
On choisit l'orientation (horizontal ou vertical) ainsi que l'endroit (de gauche à droite, de droite à gauche, de haut en bas, de bas en haut) dans lequel les widget sont placés.
-fill [x|y|both|none] |
Défini si les widgets packés doivent remplir complètement l'espace disponible ou non en horizontal (x) ou en vertical (y). Par défaut l'option est none.
-expand [true|false] |
Lors du redimmensionnement de la fenêtre, les widgets packés avec cette commande suivront l'expansion de la taille de la fenêtre.
-padx [0-9]+ -pady [0-9]+ |
Le nombre de pixels à droite et à gauche du widget courant sera ajouté en horizontal (padx) ou en vertical (pady) autour du widget.
-ipadx [0-9]+ -ipady [0-9]+ |
Le nombre de pixels nécessaire est ajouté à l'intérieur du widget à droite et à gauche (-ipady) ou au dessus et en dessous (-ipadx).
On peut faire "oublier" un widget au packer en utilisant l'option forget.
Enfin, pour pouvoir bouger un widget dans tous les sens, il faut qu'il soit défini avant un autre.
3.9. Exercice
Votre mission si vous l'acceptez consiste à obtenir successivement les looks suivant avec le packer et 2 labels :






Pour ce faire, vous allez lancer wish et vous allez créer les 2 widgets suivants en ligne de commande :
label .lab1 -text "------------------------------lab1---------" label .lab2 -text "lab2" -relief ridge pack .lab1 |
Afin que votre cerveau ne s'auto-détruise pas au bout de 15 minutes, voici quelques conseils :
- les 5 premiers écrans s'obtiennent uniquement en faisant bouger l'un ou l'autre des widgets avec la commande pack,
- le dernier écran s'obtient en configurant l'option -anchor du label 2.
Bien sûr, si votre mission échoue, nous nierons tout lien avec vous et peut-être même vous livrerons au côté obscure de la force dans la salle d'à côté (un cliquodrome où l'on asticote des papillons et où certains s'évertuent à ouvrir des fenêtres sans les casser).
3.10. Les frames
Les frames sont comme le sel en cuisine, il en faut des pincées, cela reste invible, mais sans cela le plat est infecte.
Imaginons que nous souhaîtions avoir l'interface suivante :

Le code correspondant est le suivant :
frame .frame1 -background "#808080" -relief groove
frame .frame1.frame2 -background "#000000" -relief groove
label .frame1.frame2.lab1 -text "Ici :"
set ent1 "Entrée de texte numéro 1"
entry .frame1.frame2.ent1 -textvariable ent1 -width 20
set ent2 "Entrée de texte numéro 2"
entry .frame1.ent2 -textvariable ent2 -width 30
button .butt1 -background red -text "OK" -command {exit}
pack .frame1.frame2.lab1 -side left
pack .frame1.frame2.ent1 -fill x -expand true -side left
pack .frame1.frame2 -side top -ipadx 5 -ipadx 5
pack .frame1.ent2 -side top -fill x -expand true
pack .butt1 -fill both -expand true -side left
pack .frame1 -fill x -expand true -ipadx 5 -ipady 5 -side left
|
Comme vous le voyez, les frames permettent de regrouper des ensembles de widget par ligne horizontale et verticale. Grâce à .frame1.frame2 on a groupé les widgets .frame1.frame2.lab1 et .frame1.frame2.ent1 horizontalement, puis dans .frame1 on a ajouté .ent2 et on les a empilés verticalement. Enfin on a placé .but1 et .frame2 cote à cote.
En jouant judicieusement sur les options -expand et -fill, on arrive à obtenir un comportement sophistiqué de l'application lors des redimmensionnements.
3.11. Le gridder
Dans certains cas, le packer est vraiment assez inadapté et oblige à utiliser un nombre incroyable de frame. Des extensions à tcl sont alors apparus qui intégraient des algorithmes de placement basés sur une grille de cases.
Une grille est définie et l'on choisi le ou les cases sur lesquels un widget (ou un ensemble de widget dans une frame) vont être placés. Le gridder est plus verbeux que le packer à l'écriture parce qu'il faut une ligne pour chaque widget. Par contre, il est trivial de générer le code automatiquement.
Les options de grid (au placement ou lors d'un configure) sont les suivantes :
-column [0-9]+ -row [0-9]+ |
Identification de la case où le widget sera placé
-columnspan [0-9]+ -rowspan [0-9]+ |
Le widget est placé sur une ou plusieurs colonnes, sur une ou plusieurs lignes.
-padx -pady -ipadx -ipady |
Strictement identique à ces valeurs dans le packer.
-sticky [ewns]+ |
La manière dont le widget est "collé" aux bords. Si l'on souhaite qu'en cas de redimensionnement le widget voit sa taille augmenté, on utilise -sticky ew ou ns ou ewns.
Il est possible de fixer les attributs d'une colonne ou d'une ligne grâce à
grid columnconfigure columnindex [-minsize [0-9]+] [-weight [0-9]+] [-pad [0-9]+] grid rowconfigure rowindex [-minsize [0-9]+] [-weight [0-9]+] [-pad [0-9]+] |
Assez étrangement, les numéros de lignes et de colonnes commencent à 1 et non pas à 0.
3.12. Evénements disponibles
On peut associer à chaque événement d'un widget des actions. Cela se fait avec la commande bind.
label .lab1 -textvariable var
bind .lab1 <Enter> { incr var }
bind .lab1 <1> { incr var 10 }
bind .lab1 <Button-2> { incr var 20 }
bind all <Key> { set var2 "%K" }
label .lab2 -textvariable var2
pack .lab2
|
La syntaxe de bind est :
bind [.nom_d_un_widget|all] <événement> { script à exécuter }
|
La syntaxe des événements est un peu particulière. En première approximation, c'est :
type_d_evenement peut être :
| ButtonPress <=> Button | Expose | Map |
| ButtonRelease | FocusIn | Motion |
| Circulate | FocusOut | Property |
| Colormap | Gravity | Reparent |
| Configure | KeyPress <=> Key | Unmap |
| Destroy | KeyRelease | Visibility |
| Enter | Leave | Activate |
| Deactivate |
Button et Key sont d'utilisation très courantes. Il m'est arrivé d'utiliser aussi Enter et Leave.
evenement peut être :
- 1 : le bouton 1 de la souris,
- 2 : le bouton 2 de la souris,
- 3 : le bouton 3 de la souris,
- le nom d'une touche : abcdefghij...left, right, up, down, Control_L, Control_R, Insert, Delete, ....
En ce qui concerne les touches, attention, il peut y avoir des différences de dénomination entre OS. Utilisez l'exemple plus haut pour connaître le code.
Enfin devant tout cela ( type_d_evenement-evenement ), il peut y avoir un modificateur. Par exemple, on peut demander à ce que la touche Ctrl soit appuyé, Alt ou Shift, ou vouloir un double clique, ou que le bouton 1 de la souris soit activé. Les autres événements me paraissent moins utiles.
La liste est la suivante :
| Control | Mod2 <=> M2 |
| Shift | Mod3 <=> M3 |
| Lock | Mod4 <=> M4 |
| Button1 <=> B1 | Mod5 <=> M5 |
| Button2 <=> B2 | Meta <=> M |
| Button3 <=> B3 | Alt |
| Button4 <=> B4 | Double |
| Button5 <=> B5 | Triple |
| Mod1 <=> M1 |
Enfin, dans le script associé au binding, on peut récupérer diverses informations sur l'événement grâce à des chaines du type %x :
- %b : numéro du bouton pour les événements ButtonPress et ButtonRelease,
- %k : le code de touche pour l'événement KeyPress ou KeyRelease,
- %K : le code de touche sous forme de chaîne pour les 2 événements décrits plus haut,
- %X : coordonnée horizontal de l'événement dans le widget courant (pour ButtonPress, ButtonRelease, KeyPress, KeyRelease ),
- %Y : coordonnée vertical de l'événement dans le widget courant (pour ButtonPress, ButtonRelease, KeyPress, KeyRelease ).
La page de man de bind donne toutes les indications.
3.13. Liste des widgets disponibles
|
|
3.14. Les boutons
Pour avoir toutes les options, n'hésitez pas à vous reporter à la page de man. Les options me semblant crucialement utiles sont :
| Option | Signification |
| -background | couleur de fond du bouton |
| -activebackground | couleur de fond lorsque le curseur est sur le bouton |
| -text | le texte du bouton |
| -image | une image précédemment chargée s'affiche dans le bouton |
| -command | commande(s) exécutées lors de l'appui sur le bouton |
3.15. Les labels
Les labels sont les widgets contenant un texte non modifiable interactivement. Evidemment le texte est modifiable via programmation.
| Option | Signification |
| -text | le texte du bouton |
| -textvariable | une variable dont le contenu s'affichera dans le widget |
Le widget "message" est un label multiligne.
3.16. Les entrées de texte
| Option | Signification |
| -textvariable | une variable dont le contenu s'affichera dans le widget |
| -width | le nombre de caractères par défaut du widget en largeur |
3.17. Les cases à cocher
Une case à cocher permet de savoir si une option est ou non sélectionnée. Cela s'utilise de la manière suivante :
checkbutton .c1 -text "Essai" -variable check1 \
-command { puts "c1 contient $check1" }
|
Les options -onvalue -offvalue permettent de forcer une valeur pour la variable selon que la case est ou non cochée.
3.18. Les boutons radio
Les boutons radio sont des cases à cocher dont une seule peut-être active à la fois.
radiobutton .r1 -text "Tout" \ -variable test -value "tout" -anchor w radiobutton .r2 -text "Rien" \ -variable test -value "rien" -anchor w .r1 select .r2 invoke .r2 deselect .r1 toggle |
3.19. Les menus
Pour créer un menu avec des listes déroulantes, on utilise simplement une frame (-relief raised), avec à l'intérieur des widget "menubutton". A chaque menubutton on associe un widget fils menu. Ce menu est composé d'entrée de type command (avec option -label, -command), de type radiobutton (option -label, -command, -variable et -value) de type checkbutton (-label -command -variable -onvalue -offvalue) ou de type cascade (option -label -cascade) enchaînant vers un autre menu.
L'option -accelerator permet d'associer une touche d'accélération pour activer l'entrée de menu correspondante.
Il existe aussi des menus d'options : tk_optionMenu
tk_optionMenu .nom_du_widget variable_global \ elt1_du_menu elt2 elt3 ... |
Ainsi que des menus pop-up.
set filetype text
menubutton .file \
-text "File" -menu .file.menu
pack .file -side left
menu .file.menu
.file.menu add command \
-label "Nouveau" \
-command { puts "New" }
.file.menu add command \
-label "Ouvrir..." \
-command { puts "Open..." }
.file.menu add separator
.file.menu add radiobutton \
-label "Graphique" -variable filetype \
-value "graphic" -command { puts $filetype }
.file.menu add radiobutton \
-label "Texte" -variable filetype \
-value "text" -command { puts $filetype }
.file.menu add separator
.file.menu add checkbutton \
-label "Fichier rw seulement" \
-variable rwfile -onvalue on \
-offvalue off -command { puts $rwfile }
.file.menu add separator
.file.menu add cascade \
-label "Autre menu" -menu .file.menu.sousmenu
.file.menu add command \
-label "Exit" \
-command { exit }
menu .file.menu.sousmenu
.file.menu.sousmenu add command \
-label "Action 1" \
-command { puts "Sous-menu action 1" }
.file.menu.sousmenu add command \
-label "Action 2" \
-command { puts "Sous-menu action 2" }
|

3.20. Les images
Comme nous l'avons vu précédemment, il est possible d'associer un bitmap (noir et blanc) ou une photo à un widget (bouton, label).
La procédure est simple :
- on crée l'image de type photo (couleur) ou bitmap (pixel noir ou blanc),
- on associe la photo créée au widget.
Prenons le cas de la photo :
image create photo toto_photo -file nom_d_un_fichiergifoujpeg |
Il ne reste plus qu'à associer la photo à un label
label .lab1 -image toto_photo |
Il est évidemment possible de changer de photo par exemple :
toto_photo configure -file nom_dunautrefichier.jpg |
Vous pouvez vous reporter au man de la commande image pour voir les commandes disponibles.
3.21. Interface graphique contre grosse fatigue
Nous allons refaire un joyeux exercice, mais cette fois-ci vous allez pouvoir utiliser un builder graphique d'application. Il en existe 3 pour tk.
Le plus ancien est SpecTcl (http://wuarchive.wustl.edu/languages/tcl/SpecTcl/). A sa création par les laboratoires de Sun, s'était un produit commercial. Ils l'ont rapidement mis dans le domaine public et abandonné le développement. Le résultat est un excellent produit stable et facile à utiliser mais qui n'évolue plus (et s'est bien dommage). C'est ce que j'ai utilisé au départ.
L'inconvénient de specTcl est qu'il faut très régulièrement retouché le code généré. A partir du moment où on touche le code généré par un builder, on ne peut plus du tout continuer à utiliser l'interface graphique et cela perd de son intérêt.
tkBuilder que l'on peut trouver sur http://scp.on.ca/sawpit, est un outil moins graphique que specTcl, mais très pratique pour le programmeur. C'est un excellent support graphique à la programmation. Grâce à la possibilité de rajouter du code manuel un peu partout, il est très facile de ne pas avoir à modifier le code.
Enfin, Visual Tcl est un logiciel constamment prometteur, certainement le plus ambitieux des 3 (le plus proche de VB ?). On le trouve sur :
Malheureusement, à chaque fois que je l'utilise, il me claque entre les mains. Je vous propose malgrè tout de voir si la dernière version (1.5.1) tient ou non la route.
Je vous propose de charger l'un des 3 et de faire les exercices suivants avec une interface de construction. A charge pour vous de lire le manuel.
3.22. Vous n'allez pas rigoler
Votre but est de créer l'application suivante :

On donne en haut le nom d'un fichier gif ou jpeg et quand on appuie sur le bouton Ouvrir cette image est affichée dans le label central. Bien sûr, on peut répéter l'opération d'ouverture à chaque fois.
On peut choisir le nom de fichier ou en le tapant dans l'entrée de texte du haut ou en cliquant sur le bouton à coté de l'entrée de texte qui permet d'appeler le widget tk_getOpenFile. On utilise cette fonction de la manière suivante :
set filename [tk_getOpenFile -filetypes [list [list "Fichiers graphique" {.gif .jpg .jpeg}] [list "Tous fichiers" {*}]]]
|
tk_getOpenFile est un widget standard de tcl ayant un manuel.
J'ai utilisé tkBuilder pour créer cette application :

mais n'hésitez pas à utiliser un autre builder.
3.23. La prochaine fois
Nous parlerons des widget text et canvas, ainsi que de "megawidgets" tels que les combobox, les notebooks, le tree widget, les widget d'affichage de l'html. Puis nous attaquerons la programmation de scripts cgi en tcl/tk.
Bibliographie
"Graphical Applications with Tcl&Tk" de Eric F. Johnson, M&T Books, ISBN 1-55851-471-6 : le livre avec lequel j'ai appris le tcl/tk. Pas complet, mais très pédagogique et agréable à lire.
4. Le widget text
Les widgets que nous avons vu jusqu'ici sont simples (bouton, label, entrée de texte, frame, ...). Nous allons examiner maintenant des widgets complexes, des supports quasi idéals pour des applications complexes.
Le widget texte est un widget d'entrée et d'affichage de texte avec de nombreuses possibilités d'enluminure. Vous pourrez choisir la fonte de chaque portion de texte, la couleur, la taille, la justification, créer des hyperliens, ajouter des images, ou n'importe quel autre widget à l'intérieur. Bref, vous avez un nombre de possibilités énorme. Ce n'est malheureusement pas aussi complet qu'un widget d'affichage html, mais cela n'est vraiment pas loin.
En raison de la richesse du widget, il est difficile de faire un traitement exhaustif. Nous nous contenterons donc dans la suite de présenter les possibilités essentielles. Si vous souhaitez tout savoir dans le détail, merci de vous reporter à l'aide sur le widget texte (taper la commande "man text" sous unix).
En route, tout d'abord un exemple de résultat :

Et le code associé (fichier test/wid_text.tcl) :
#!/home/arnaud/source/tcltk83/bin/wish8.3
text .text -height 30 -width 80 -yscrollcommand ".scroll set"
scrollbar .scroll -command ".text yview"
pack .scroll -side right -fill y
pack .text -expand yes -fill both
set text .text
set title_font [font create title_font -family times -size 20 \
-weight bold]
set title {Le widget text}
$text tag configure BODY -foreground black -background white
$text tag configure TITLE -foreground "#808000" \
-font title_font -justify center
$text tag configure H1 -foreground blue -font helvetica
$text tag configure H2 -foreground green -font courrier
$text tag configure LISTE0 -foreground black -lmargin1 20
$text tag configure P -foreground black
$text tag configure PRE -foreground black -background grey
$text insert end {Le widget text
} TITLE
$text mark set "1." insert
$text insert end {1. Changement de fontes et ancre pour les déplacements
} H1
$text mark set "1.1." insert
$text insert end {1.1. Encore d'autres fontes
} H2
$text insert end {Evidemment, on peut faire du texte tout simple,
} TEXT
$text insert end {ou alors le décalé (ici à gauche mais aussi à droite)
} LISTE0
$text insert end { Ou des choses plus sophistiquées :
} TEXT
$text insert end {#!/usr/bin/tclsh
puts "Hello world"
} PRE
# open_IMG
image create photo im0 -file img/exemple.gif
$text image create end -image im0 -align center -pady 10 -padx 100
$text insert end "\n"
button $text.button0 -text button -command exit
$text window create end -window $text.button0 -align center -padx 100
$text insert end {
That's all folks !
} TEXT
|
4.1. Création du widget
Le code suivant permet la création du widget et d'une barre de déroulement verticale associée :
text .text -height 30 -width 80 -yscrollcommand ".scroll set" scrollbar .scroll -command ".text yview" pack .scroll -side right -fill y pack .text -expand yes -fill both |
Ici on crée le widget texte avec une hauteur de 30 lignes et une largeur de 80 caractères et l'on indique que le déroulement de la fenêtre dépend de la valeur du widget .scroll.
On crée ensuite ce widget .scroll et l'on indique que lors des mouvements de la barre, il faut réafficher le widget text.
Enfin, on place le widget text et la barre défilement verticale l'un à côté de l'autre et l'on demande que lors des chagement de dimension le widget text voit sa taille augmentée.
Les raccourcis claviers classiques d'emacs sont disponibles dans un widget text pour aller en début (Ctrl-a) ou en fin de ligne (Ctrl-e).
Les commandes génériques disponibles sont maintenant :
| .widget_text insert | insertion de texte dans le widget, |
| widget_text tag | manipulation de tags permettant de changer les formats de portions de texte, |
| .widget_text mark | marquage d'une position dans le texte, |
| .widget_text image | manipulation d'images dans le widget texte, |
| .widget_text window | manipulation de fenêtres pouvant contenir des widgets dans le widget text, |
| .widget_text search | recherche dans le widget d'une chaine de caractères, |
| .widget_text cget | permet de consulter la valeur d'une option du widget, |
| .widget_text configure | permet de configurer les options du widget, |
| .widget_text delete | permet de supprimer des portions du contenu du widget, |
| .widget_text dump | récupération d'une portion ou de la totalité du contenu du widget sous forme de liste, |
| .widget_text get | récupération d'une portion ou de la totalité du texte du widget, |
| .widget_text see | ajuste l'affichage pour montrer un endroit précis du texte, |
| .widget_text xview | ajustement de l'affichage à l'horizontal, |
| .widget_text yview | ajustement de l'affichage en vertical |
La plupart des commandes utilise des indices pour spécifier des portions du widgt. Un indice peut avoir la forme suivante :
| line.char | Le caractère n° char (commençant à 0) de la ligne n° line (commençant à 1) |
| 1.10 | le 11ème caractère de la 1ère ligne |
| @x,y | Le caractère sous le pixel de la ligne x colonne y |
| @0,0 | Le caractère en haut à gauche de l'écran |
| end | Le caractère juste après le dernier saut de ligne |
| marque | Le caractère juste après la marque marque |
| nomdetag.first | Le premier caractère de la zone nomdetag |
| nomdetag.last | Le caractère juste après le dernier caractère de la zone nomdetag |
| nomdefenetre | La position de la fenêtre ayant ce nom |
Il est possible de rafiner encore ces positions en y associant des modificateurs tels que
| + valeur chars | valeur caractères après la position précédemment définie |
| - valeur chars | valeur caractères avant la position précédemment définie |
| + valeur lines | valeur lignes après la position précédemment définie |
| - valeur lines | valeur lignes avant la position précédemment définie |
| linestart | Début de la ligne |
| lineend | Fin de la ligne |
| wordstart | Début du mot |
| wordend | Fin du mot |
On pourra donc lire :
set 4linetext [.text get {end - 4 lines } end]
|
4.2. Insertion, récupération et recherche de texte
Pour insérer un texte, rien de plus simple :
.text insert 1.0 "Insertion de texte" |
On peut aussi associer le texte insérer à un tag (en fait un style):
.text insert end "Un titre" titre1 |
Ou même à plusieurs :
.text insert 1.0 "Un titre en gras" [list titre1 gras] |
Pour récupérer un texte on utilise get :
set titre [.text get 1.0 {1.0 lineend}]
|
Il est aussi possible d'avoir le contenu complet du widget (texte, tag, mark, image, fenêtre embarquée) grâce au dump.
set full_content [.text dump 1.0 end] |
Il est simple à partir de ce résultat de faire une moulinettre qui recrée le widget texte à partir de ce contenu. Le résultat est une liste dont les éléments sont :
type_d_entree valeur index |
D'où par exemple :
tagon TITLE 1.0 \
tagon gras 1.0 \
tagon titre1 1.0 \
text {Un titre en gras} 1.0 \
tagoff gras 1.16 \
text {Un titre} 1.16 \
tagoff titre1 1.24 \
text {Insertion de texte} 1.24 \
tagoff TITLE 1.42 \
window .text.b1 1.42 \
mark current 1.43 \
mark insert 1.43 \
text {
} 1.43
|
Une commande search permet de faire toutes les recherches que l'on veut dans le texte.
.text search -regexp {[Tt]it} 1.0 end
|
Les options de la recherche sont :
| Option | Signification |
| -forward | Recherche à partir du début |
| -backward | Recherche à partir de la fin |
| -exact | Recherche exacte |
| -regexp | Recherche sur expression régulière |
| -nocase | Sans tenir compte des majuscules/minuscules |
| -count nom_de_variable | Si l'on trouve, stocke le nombre de caractères de correspondance dans la variable nom_de_variable |
| -- | Arrêt des options |
4.3. Mais quels sont donc ces tags, qui tapent sur vos têtes ?
Les tags permettent de choisir les caractéristiques visuelles de la ou des portions de texte marquées. L'utilisation des tags se fait en 2 temps. Il faut d'abord créer le tag et les caractéristiques associées, puis l'utiliser sur le texte.
La syntaxe de la création est la suivante :
.text tag configure TITLE -font nom_d_une_fonte -justify center |
On peut préciser un tag à l'insertion :
.text insert end "Le titre du document" TITLE |
Ou bien demander à appliquer un tag à une portion de texte :
.text tag add TITLE 1.0 {1.0 lineend}
|
Les caractéristiques modifiables sont :
| Option | Effet |
| -background couleur | Couleur de fond pour le tag |
| -bgstipple bitmap | Un bitmap utilisé en motif de fond |
| -borderwidth nombre_de_pixels | Largeur du bord en pixels |
| -elide booléen | Affiché ou non |
| -fgstipple bitmap | Un bitmap utilisé en motif pour l'avant plan (le texte) |
| -font nom_d_une_fonte | Fonte utilisée |
| -foreground couleur | Couleur du texte |
| -justify left/right/center | Justification (gauche, droite ou centrée) du texte |
| -lmargin1 nombre_de_pixels | Marge à droite pour la première ligne |
| -lmargin2 nombre_de_pixels | Marge à gauche pour les lignes autres que la première |
| -offset nombre_de_pixels | Décalage vers le haut par rapport à la ligne de base du texte |
| -overstrike booléen | Texte barré |
| -relief raised/sunken/flat/ridge/solid/groove | Aspect "3d"des bords du texte |
| -rmargin nombre_de_pixels | Marge à droite |
| -spacing1 nombre_de_pixels | Espace additionnel laissé au-dessus des lignes de texte. Si le texte se replie, ne s'applique qu'à la première ligne |
| -spacing2 nombre_de_pixels | Pour les lignes se repliant, spécifie l'espace à laisser au-dessus des lignes replièes |
| -spacing3 nombre_de_pixels | Espace laissé sous les lignes. Si les lignes se replient, ne s'applique qu'à la dernière ligne |
| -tabs liste_de_tabulation | Liste de tabulation pour la portion de texte (détails dans le manuel) |
| -underline booléen | Texte souligné |
| -wrap none/char/word | Type de repliement appliqué au texte |
Il est possible d'associer des actions à des tags. Cela se fait avec la syntaxe :
nom_du_widget tag bind evénement script |
Par exemple :
.text tag bind TITLE |
On peut supprimer un tag avec la commande :
.text tag delete TITLE |
Ou empécher son application sur une portion de texte par :
.text tag remove TITLE 1.0 |
Et connaître la liste des tags disponibles par :
.text tag names |
Ou pour une section par
.text tag names 1.0 |
4.4. Et avec des images en plus
Si vous avez une image vous pouvez l'afficher dans le texte.
image photo create im1 -file img/exemple.gif .text image create end -image im1 |
Et voila. Vous trouverez le détail des options associées à la commande image du widget texte dans le manuel de texte.
4.5. Et même d'autres widgets
John ne s'est pas arrêté sur sa lancée et il est donc possible d'inclure n'importe quel tag dans un widget text. On utilise pour cela des "fenêtres embarquées" (embedded windows).
Donc il vous suffit d'avoir un widget quelconque et hop là !
button .text.b1 -text "Bye Bye" -command exit .text window create end -window .b1 |
Là encore de nombreuses options sont possibles.
4.6. Les Marques jaunes ?
Il est possible de placer des balises dans le texte qui sont appelées des marques (comme des marque-pages).
.text mark set "title0" 1.0 |
Les autres commandes associées aux marques sont :
| Commande | Action |
| widget mark gravity | Montre ou initialise l'attachement d'une marque vers les caractères de gauche ou de droite |
| widget mark names | Liste des marques disponibles |
| widget mark next indice | Prochaine marque disponible à la positionindice |
| widget mark previous indice | Précédente marque disponible à la positionindice |
| widget mark set nom_de_marque indice | Insertion de la marque nom_de_marque à la position indice |
| widget mark unset nom_de_marque | Suppression de la marque nom_de_marque |
Les marques suivantes sont constamment et automatiquement créées et indestructibles :
- insert : marque du curseur courant d'insertion,
- current : est associé au caractère le plus proche de la souris.
4.7. Couper, copier, coller, dodo
Les commandes selection et clipboard permettent de faire l'essentiel du boulot.
set sel [ selection get ] |
selection get renvoie le contenu de la sélection courrante.
clipboard clear clipboard append [selection get] |
Insertion dans le presse-papier de la zone sélectionnée après nettoyage du clipboard.
Le tag sel contient la zone de texte sélectionnée. Donc on peut aussi supprimer le contenu de cette zone :
.text delete sel.first sel.last |
Enfin, pour récupérer le contenu du presse-papier on utilise la commande.
set clip [selection get -selection CLIPBOARD] |
5. Le widget canvas
Une note d'avertissement pour le lecteur. Je viens de finir à l'instant "Métaphysique des tubes" d'Amélie Nothomb. J'en sors enthousiaste et réjouis. Malheureusement pour le lecteur de cette prose, j'ai une tendance naturelle à être un caméléon. Résultat, mon style va se ressentir de cette lecture. Malheureusement, je n'ai ni le talent ni le style de cet auteur. Le pire est donc à craindre.
Généralement, l'on apprend à dessiner avant d'apprendre à écrire. Dans le cas d'espèce, nous allons faire l'inverse et dessiner après avoir écrit. Tant pis, ou tant mieux.
Le widget canvas est une surface sur laquelle vous pouvez disposer et manipuler toute sorte d'objets graphiques :
- des lignes,
- des suites de lignes,
- des ellipses,
- des courbes,
- des rectangles,
- des zones de texte,
- des images ou des bitmaps,
- des fenêtres embarquées contenant tout autre widget.
On retrouve le mécanisme des tags, qui permettait de manipuler un objet ou des ensembles d'objet dans le widget texte. Tout comme avec le widget text, je ne prétends pas à l'exhaustivité dans le traitement du widget canvas. Si vous pensez qu'une fonction ou une option doit ou devrait exister, reportez-vous à la description du canvas pour en être sûr.
Le canvas est une liste dans l'ordre d'apparition des objets graphiques que l'on y dessine. L'on peut changer les caractéristiques d'un élément, ou changer l'ordre d'apparition des objets dans la liste. Un élément est dessiné au-dessus des éléments déssinés antérieurement.
5.1. Quelques élucubrations générales
Les différents objets ont des caractéristiques communes. Quelques unes sont données ci-dessous.
| Option | Signification |
| -dash forme de pointillé | Lorsque des traits sont utilisés, ils peuvent représenter des pointillés. L'option permet de choisir le type de pointillé. Par exemple {2 4} ou .- |
| -activedash forme de pointillé | Le pointillé pour un trait actif |
| -disableddash forme de pointillé | Le pointillé pour un trait non actif |
| -dashoffset nombre | L'offset au démarrage du pointillé |
| -fill couleur | Couleur de remplissage |
| -activefill couleur | Couleur de remplissage si actif |
| -disabledfill couleur | Couleur de remplissage si inactif |
| -stipple bitmap | Un motif bitmap utilisé pour le remplissage |
| -activestipple bitmap | Un motif bitmap utilisé pour le remplissage d'un objet actif |
| -disabledstipple bitmap | Un motif bitmap utilisé pour le remplissage d'un objet inactif |
| -state normal/hidden/disabled | L'état normal, caché ou non activé d'un objet |
| -tag tag/liste de tags | Tag permettant de regrouper ou de nommer un ou plusieurs objets |
| -width largeur | Largeur en pixels |
| -activewidth largeur | Largeur si actif |
| -disabledwidth largeur | Largeur si inactif |
Nous avons évoqué dans ce qui précède une mystérieuse forme de pointillé, elle dispose de 2 syntaxes. L'une est à base d'un des 5 signes [.,-_ ]. L'autre utilise une liste de nombres. Un nombre sur 2 représente le nombre de pixels d'une ligne, l'autre le nombre de pixels transparents suivant. La liste est donc un nombre pair de nombres permettant de créer des motifs d'une grande complexité.
Chaque objet graphique est identifiable de 2 manières. A la création d'un objet un numéro d'identification est créé :
canvas .can -width 300 -height 200 pack .can .can create line 100 50 200 50 |
A l'exécution de cet exemple, la valeur
1 |
est retournée. C'est le numéro de carte d'itentité (nouveau type infalsifiable merci Charles) de la ligne (blanche à ne pas franchir, merci Charles). On peut systématiquement utiliser l'identité ou le tag d'un élément graphique. Le tag doit obligatoirement commencer par une lettre pour ne pas être confondu avec un numéro d'identité.
Non seulement il est possible de définir des tags à la création des objets graphiques, mais en plus 2 sont définis par défaut. Le tag all contient tous les objets graphiques de la page. Le tag current indique l'élément graphique le plus haut et le plus proche de la souris.
Grâce au tag d'un élément graphique, il est possible de connaître et de configurer chacune de ses caractéristiques. On connait une caractéristique d'un élément grâce à :
.can itemcget tag option |
Par exemple :
canvas .can -width 300 -height 200 pack .can .can create line 100 50 200 50 200 150 100 \ 150 100 50 -arrow both -tag this_line .can itemcget this_line -arrow |
La dernière instruction renvoie
both |
Il est possible de changer une caractéristique d'un élément grâce à la commande itemconfigure. d'où par exemple :
.can itemconfigure this_line |
qui renvoie :
{-arrow {} {} none both} {-arrowshape {} {} {8 10 3} {8 10 3}} {-capstyle {} {} butt butt} {-fill {} {} black black} {-joinstyle {} {} round round} {-smooth {} {} 0 0} {-splinesteps {} {} 12 12} {-stipple {} {} {} {}} {-tags {} {} {} this_line} {-width {} {} 1 1}
|
On peut modifier la largeur du trait de la manière suivante :
.can itemconfigure this_line -width 5 |
On peut obtenir les coordonnées d'un élément avec la commande coords, et l'on peut bouger un élément avec la commande move.
canvas .can -width 300 -height 200 pack .can .can create line 100 50 200 50 200 150 100 \ 150 100 50 -arrow both -tag this_line .can coords this_line |
On obtient alors :
100.0 50.0 200.0 50.0 200.0 150.0 100.0 150.0 100.0 50.0 |
On peut obtenir un déplacement de l'élément grâce à :
.can move this_line 10 20 |
Ob obtient alors un déplacement de 10 pixels vers la droite et de 20 pixels vers le bas.
5.2. Tirons une ligne, un point c'est tout
Une ligne est créée par la commande :
.canvas create line x0 y0 x1 y1 x2 y2 ... xn yn ?option valeur ?option valeur ... |
D'où par exemple :
canvas .can -width 300 -height 200 pack .can .can create line 100 50 200 50 200 150 100 \ 150 100 50 .can create line 110 60 190 60 190 140 110 \ 140 110 60 -smooth 1 -fill "#0000FF" .can itemconfigure 2 -arrow both |

Comme vous pouvez le constater, cette commande permet de créer aussi bien une ligne, qu'une suite de ligne, que des courbes (options -smooth 1).
5.3. Si c'est rond, ...
Les ellipses sont créées par la commande :
.canvas create oval x1 y1 x2 y2 ?option valeur ?option valeur ... |
x1 y1 x2 y2 donne les 2 coins opposés d'un rectangle dans lequel l'oval s'inscrit.
canvas .can -width 300 -height 200 -background "#E0FFE0" pack .can .can create oval 50 50 150 150 -width 10 .can create oval 80 80 120 120 -fill "#ff0000" .can create oval 160 50 300 80 -outline "#00ff00" \ -width 5 -fill "#ffffff" |

5.4. Aux arcs citoyens
Un arc est une portion d'ellipse. Cette portion d'ellipse part d'un angle donné, et s'étend sur une portion de l'ellipse. 3 styles d'arcs existent :
- -style pieslice : portion de camembert,
- -style chord : une portion d'arc dont les extrémités sont reliées par une ligne,
- -style arc : simplement la ligne d'arc.
La création de l'arc utilise la commande :
.can create arc x0 y0 x1 y1 ?-option1 valeur1 -option2 valeur2 ...? |
D'où l'exemple suivant :
canvas .can -width 300 -height 200 -background "#E0FFE0"
pack .can
.can create arc 50 50 100 100 -style pieslice \
-start 0 -extent 90
.can create arc 110 50 160 100 -style chord \
-start 90 -extent 90 -fill "#ffff00" -width 5 \
-outline "#00ffff"
.can create arc 50 110 100 160 -style arc \
-start 180 -extent 90 -outline "#808080"
.can create arc 110 110 160 160 -style pieslice \
-start 270 -extent 90
.can create line 0 50 300 50
.can create line 0 100 300 100
.can create line 0 110 300 110
.can create line 0 160 300 160
.can create line 50 0 50 200
.can create line 100 0 100 200
.can create line 110 0 110 200
.can create line 160 0 160 200
|

5.5. Tu polygones ?
Un polygone est une figure fermée. Les côtés du polygone peuvent être droits ou courbes (splines). Le polygone peut être plein ou vide. A partir du moment où l'on utilise un polygone, le premier et le dernier point sont reliés entre eux.
La syntaxe est la suivante :
.can create polygon x1 y1 ... xn yn ?option valeur option valeur? |
Les options des polygones sont les suivantes :
- -smooth [0|1] : transformation en spline des lignes droites,
- -splinesteps [entier] : nombre de segments utilisés pour approximer les splines.
D'où l'exemple suivant :
# Creating a new canvas
canvas .can -width 300 -height 200 -background "#E0FFE0"
# Putting some frames for buttons below
frame .button_frame
# This button will allow to switch between smooth 1 and smooth 0
button .button_frame.smooth_button -text "Smooth" -command {
set smooth [.can itemcget poly1 -smooth]
.can itemconfigure poly1 -smooth [expr 1 - $smooth]
}
pack .button_frame.smooth_button
pack .can .button_frame -side top
.can create polygon 100 10 150 20 160 50 150 100 \
130 120 90 130 40 100 70 70 80 60 70 50 -tag poly1
# Inside of polygon will be white
.can itemconfigure poly1 -fill "#ffffff"
# Color of the line delimiting the polygon
.can itemconfigure poly1 -outline "#000000"
|
Qui permet d'obtenir les figures suivantes :
![]() |
![]() |
5.6. Jouons aux 4 coins
Zou un trivial rectangle :
.can create rectangle x0 y0 x1 y1 ?option valeur option valeur? |
Donc :
# Creating a new canvas canvas .can -width 300 -height 200 -background "#E0FFE0" pack .can .can create rectangle 10 10 100 100 -outline "#000000" -fill "#ffffff" -width 4 -tags rect1 |
Donnant :

N'oubliez pas que vous pouvez obtenir toutes les options en regardant la documentation du canvas ou en demandant le man canvas.
5.7. Le poids des mots
Détendez-vous, ils ont fait simple.
.can create text x0 y0 ?option valeur option valeur ...? |
Les options les plus courantes sont :
- -anchor [left|center|right] : permet de donner la position du texte par rapport au point de positionnement,
- -font nomdelafonte : la fonte,
- -justify [left|center|right] : justification du texte à l'intérieur des limites de la boite d'affichage. N'est utile que si le texte est sur plusieurs lignes,
- -text chaine_a_afficher : la chaîne à afficher,
- -width largeur_de_la_fenetre : largeur de la fenêtre d'affichage.
# Creating a new canvas canvas .can -width 300 -height 200 -background "#E0FFE0" pack .can # Creating a font font create font0 -family Helvetica -size 20 -weight bold # And now a text .can create text 150 150 -anchor center -font font0 -justify center -text "Ceci est un texte" -width 200 |

5.8. Le choc des photos
Il est trivial d'ajouter des photos dans un canvas. Tout d'abord on crée un bitmap ou une photo, puis on la place sur le canvas.
.can create image x0 y0 -image une_image |
Les options disponibles sont :
- -anchor [n|e|w|s|ne|...|center] : position de l'image par rapport au point d'ancrage,
- -image nom_de_l_image : nom de l'image précédemment créée avec la commande image create.
Une exemple possible est :
# Creating a new canvas canvas .can -width 300 -height 200 -background "#E0FFE0" pack .can # Chargement d'une image image create photo exemple1 -file img/exemple.gif # Affichage de l'image .can create image 160 110 -image exemple1 |
Donnant pour résultat :

5.9. Le noir et blanc c'est dépassé
Les bitmaps sont une catégorie d'images noire et blanc utilisées pour le curseur par exemple. Cela date un peu mais un type particulier existe en tcl/tk.
.can create bitmap x0 y0 ?option valeur option valeur? |
Les options courantes sont :
- -bitmap nom_d_un_bitmap : le nom d'un bitmap à charger,
- -anchor [n|e|w|s|ne|nw|...|center] : la position du bitmap par rapport au point d'ancrage,
- -background couleur : la couleur des pixels de fond,
- -foreground couleur : la couleur des pixels d'avant plan,
- -tags list_de_tag : liste de tags associée au bitmap.
Un exemple possible est en utilisant les bitmaps standards de tcl le suivant :
# Creation d'un nouveau canvas
canvas .can -width 300 -height 200 -background "#E0FFE0"
pack .can
# Affichage des bitmaps
set xori 80
set yori 40
set incx 40
set incy 80
set width 240
set x $xori
set y $yori
# Creating a serie of bitmap in the canvas.
# Foreach one a different anchor is used
# (respectively n e w s ne nw se center),
# different foreground and background are also used.
foreach bitmap [list error gray25 gray50 hourglass \
info questhead question warning] \
anchor [list n e w s ne nw se center] \
background [list "#000000" "#ff0000" "#00ff00" \
"#0000ff" "#ffff00" "#00ffff" "#ff00ff" "#ffffff"] \
foreground [list "#ffffff" "#ff00ff" "#00ffff" \
"#ffff00" "#0000ff" "#00ff00" "#ff0000" "#000000"] {
.can create bitmap $x $y -bitmap $bitmap -anchor $anchor \
-background $background -foreground $foreground
.can create text $x [expr $y - 30] -text "$anchor" \
-anchor center
incr x $incx
if { $x > $width } {
set x $xori
incr y $incy
}
}
|

5.10. Des fenêtres dans les canevas
Finalement, il est possible d'insérer des fenêtres dans les canevas pour insérer d'autres widgets. Cette possibilité rend assez simple en tcl la création de nouveaux widgets comme le notebook, ou des trames nommés (named frame), ou des frame à tailles variables, ... L'imagination est maître dans ce cas.
On utilise pour cela l'objet window. Et cela se fait de la manière suivante :
.can create window x0 y0 -widget .can.widget |
Les options standards sont :
- -window .nom.du.widget : le widget que l'on veut inclure,
- -anchor [n|e|w|s|ne|nw|...|center] : position de la fenêtre par rapport au point d'ancrage,
- -width largeur : largeur de la fenêtre,
- -height hauteur : hauteur de la fenêtre,
- -tags liste_de_tags : liste de tags associés à la fenêtre.
Nous allons reprendre l'exemple concernant les polygones mais en insérant 2 boutons directement dans le canvas.
# Creation du nouveau canvas
canvas .can -width 300 -height 200 -background "#E0FFE0"
# Creation d'une frame pour les boutons
frame .can.button_frame
# Ce bouton permet de basculer de smooth 0 a 1
button .can.button_frame.smooth_button -text "Smooth" -command {
set smooth [.can itemcget poly1 -smooth]
.can itemconfigure poly1 -smooth [expr 1 - $smooth]
}
pack .can.button_frame.smooth_button
pack .can
.can create polygon 100 10 150 20 160 50 150 100 \
130 120 90 130 40 100 70 70 80 60 70 50 -tag poly1
# L'intérieur du polygone sera blanc
.can itemconfigure poly1 -fill "#ffffff"
# Couleur de la ligne autour du polygone
.can itemconfigure poly1 -outline "#000000"
# Insertion de la frame
.can create window 200 150 -window .can.button_frame \
-width 90 -anchor w
|

6. Ce qu'il reste à dire
6.1. Reste des commandes tcl
info socket
6.2. Rest des commandes tk
tkdialog tkSaveDialog tkLoadDialog
6.3. Les packs pour tk intéressants
Pour être précis que j'ai utilisé à un moment ou à un autre.
Img, combobox, notebook
6.4. La programmation des bases de données avec tcl/tk
pgaccess, postgresql, mysql, db.tcl
6.5. La programmation cgi en tcl
Merci cgi.tcl
6.6. Programmation professionnelle de scripts cgi en tcl
mod_tcl
Les contraintes ergonomiques de base :
- cohérence et rappel d'état de l'interface,
- utilisation de template,
- mécanisme d'importation des variables cohérent,
- interface de gestion de fichiers par web,
- interface de gestion de formulaires grâce à txt2ml.
6.7. Scilab et tcl
Les interfaces graphiques de scilab grâce à tcl
6.8. Ptolemy et tcl
6.9. Comment ajouter des commandes natives tcl en C
6.10. Comment intégrer des fenêtres X dans une application tk
6.11. Readconf
6.12. Tcl et windows grâce à optcl
De quoi être dégoutté. Par exemple, créons un navigateur à nous.
6.13. La librairie std tcl
- ftp,
- ...


