Académique Documents
Professionnel Documents
Culture Documents
Août 2022
2
INTRODUCTION
Ce cours de Projet de programmation 2 est destiné aux étudiants de deuxième graduat en
Informatique de Gestion. Son intérêt réside par le fait qu’il vient ajouter une touche
pratique dans la formation des étudiants futurs informaticiens en vue de leur permettre de
réaliser des applications informatiques qui tiennent compte des réalités professionnelles.
L’informatisation est le phénomène le plus important de notre époque. Elle intervient
maintenant dans tous les secteurs de l’entreprise et est devenue une nécessité.
Actuellement, l’informatique est au cœur de toutes les grandes entreprises. Les besoins
des entreprises étant dictés à la fois par la concurrence, les besoins sans cesse croissants
des utilisateurs et l’environnement en perpétuel évolution, il est tout à fait logique pour
les organisations de se doter des applications informatiques dignes de leur permettre
l’atteinte des objectifs en temps opportun et au moindre coût.
Cependant, une application informatique est un ensemble d’instructions soumises à
l’ordinateur pour résoudre un problème donné ; cette dernière peut être écrite dans un
langage exploitable ou compréhensible par l’ordinateur.
La mise en œuvre d’une application informatique (programme) exige d’une part les
respects de normes informatiques qui ne sont rien d’autres que les méthodes utilisées par
l’informaticien et d’autre part le langage de programmation lié à ces méthodes.
Pour arriver à satisfaire le client (les entreprises, organisations, etc.), il s’avère nécessaire
de faire une bonne planification et respecter les normes informatiques y relatives. Ainsi,
ce cours fait un tour d’horizon de deux langages de programmation à savoir : le langage
python en sa version 3.5 ainsi que le WinDev dans sa version 25.
3
I. OBJECTIFS DU COURS
L’objectif principal de ce cours est de renforcer la pratique des étudiants dans le domaine
de programmation en vue de leur permettre de réaliser des projets informatiques
performants qui tiennent compte des réalités professionnelles.
L’étudiant qui aura suivi ce cours avec une attention particulièrement soutenue sera en
mesure de :
Savoir analyser et traduire les besoins fonctionnels en logiciels fonctionnels
Bien travailler dans une équipe de développement
Développer plus simplement des applications informatiques performantes.
Ce cours prend appui sur l’enseignement des cours ci-après : algorithme, langage python
et WinDev et en constituent une base.
IV. PRE-REQUIS
• Des connaissances minimales en informatique générale ; vous devez savoir ce que
désigne chacune des expressions ci-dessous :
- Windows
- Fenêtre, boite de dialogue
- Logiciel, application
- Menus, Barre d’outils, boutons, cases à cocher, Info-bulle, liste
déroulante (« Combo »), icône
4
• Vous devez savoir utiliser un ordinateur (clavier : Touches Ctrl, Alt, Shift ; souris
: clic, un double clic, un clic Droit), Windows, l’Explorateur.
• Un sens de la logique suffisamment développé car la programmation fait
largement appel à la logique(Algorithme).
• Vous devez savoir programmer dans l’un des langages ci-après : python ou
WinDev
• De la patience, du courage et de la volonté
• Du temps…
Bon courage
5
1.1. Introduction
En informatique, la théorie des langages a pour objectif de décrire les langages formels.
D'un point de vue mathématique, un langage formel est un ensemble de mots, un mot
étant une suite finie de symboles. L'ensemble de ces symboles est appelé alphabet, les
symboles eux- mêmes sont des lettres. Un langage (formel) est décrit et analysé par une
méthode formelle. Plusieurs sortes de mécanismes existent pour arriver à cette fin.
Initialisation
Boucle
Finalisation
Imaginez que le déroulement du programme soit effectué par une araignée qui déroule
son fil derrière elle. Quel que soit la complexité de l’application, si l’on considère
l’exécution du programme depuis son lancement jusqu’au moment où il se termine, un
seul fil est déroulé, et on pourrait théoriquement le démêler pour n’obtenir qu’un fil
rectiligne.
routines (sous-programmes) intégrées. Chaque objet appartient à une classe qui définit
les structures de données et les routines qu’il contient.
Si, par exemple, on crée une classe nommée « Cartable », l’objet « mon cartable »
faisant partie de la classe « cartable » est appelé instance de « cartable ». Toute classe
peut donc être utilisée comme variable dans ce type de programme, dont les objets ainsi
définis interagissent.
a) Objectifs :
Lier les données et les fonctions qui les manipulent afin d’éviter des accès aux
données par des fonctions non autorisées ;
Obtenir une meilleure abstraction en cachant l’implémentation des techniques
utilisées et en ne rendant visible que des points d’entrée. Ainsi, si
l’implémentation change, le code utilisateur n’est pas affecté ;
Réutiliser l’existant dans un souci de productivité ;
Traiter les erreurs localement au niveau des objets sans que cela ne perturbe les
autres parties du programme ;
Faciliter la maintenance.
1.3.8 Programmation de macros
De nombreux programmes comprennent des macro-instructions, séquences
d’instructions prédéfinies auxquelles on accède par une combinaison de touches ou par
une commande très simple. Ces macros offrent l’avantage de supprimer les
manipulations répétitives et d’accéder plus facilement aux opérations courantes.
9
2.1. Introduction
Le langage de programmation Python a été créé en 1989 par Guido van Rossum, aux
Pays-Bas. Le nom Python vient d’un hommage à la série télévisée Monty Python’s
Flying Circus dont G. van Rossum est fan. La première version publique de ce langage a
été publiée en 1991. La dernière version de Python est la version 3. Plus précisément, la
version 3.10 a été publiée l’an dernier. La version 2 de Python est désormais obsolète et
cessera d’être maintenue après le 1er janvier 2020. Dans la mesure du possible évitez de
l’utiliser.
La Python Software Foundation 1 est l’association qui organise le développement de
Python et anime la communauté de développeurs et d’utilisateurs. Ce langage de
programmation présente de nombreuses caractéristiques intéressantes :
Il est multiplateforme. C’est-à-dire qu’il fonctionne sur de nombreux systèmes
d’exploitation : Windows, Mac OS X, Linux, Android, iOS, depuis les mini-
ordinateurs Raspberry Pi jusqu’aux supercalculateurs.
Il est gratuit. Vous pouvez l’installer sur autant d’ordinateurs que vous voulez
(même sur votre téléphone!).
C’est un langage interprété. Un script Python n’a pas besoin d’être compilé pour
être exécuté, contrairement à des langages comme le C ou le C++.
1
. https://www.python.org/psf/
11
Il est orienté objet. C’est-à-dire qu’il est possible de concevoir en Python des
entités qui miment celles du monde réel (une cellule, une protéine, un atome, etc.)
avec un certain nombre de règles de fonctionnement et d’interactions.
Le widget label
Un label est un widget constitué d’un court message textuel (en français, on
devrait dire étiquette). Par exemple :
2
. Nous sommes d’accord, cette notion est très relative.
12
Le label est créé avec le constructeur Label. Le texte est transmis avec l’option text et on
peut aussi changer la police avec l’option font.
Un label est un des widgets les plus simples et est souvent utilisé. Il est soit statique (une
description par exemple) soit dynamique (comme un compteur ou une durée qui
évoluent). Voici un exemple de labels qui indiquent le nombre de carrés générés
aléatoirement sur un canevas
75
HEIGHT
montre un court morceau de texte et qui est placé dans un widget de type
label. Le code correspondant est :
Cette méthode n’est pas toujours bien comprise et peut être source de bugs, en particulier
chez les débutants. Il est donc préférable de l’éviter, surtout que son bénéfice est réduit.
Dès qu’une interface a un peu de complexité, il est rare qu’un widget qui a été crée ne
15
soit pas référencé dans le code et donc l’astuce ci-dessus devient une nuisance. Certains
pensent alors utiliser un code comme celui-ci :
L’intention ici est d’afficher dans la console (cf. ligne 6) le contenu du label ("coucou",
ligne 4). Certes, une variable lbl a été créée sauf qu’elle ne référence pas le label mais le
retour de l’appel Label(...).pack() qui lui vaut None. Donc la ligne 6 va planter le
programme :
print(lbl["text"])
TypeError: ’NoneType’ object is not subscriptable
Pour s’en sortir, il faut découpler la création du widget et son placement avec la méthode
pack.
Le widget bouton
Tkinter dispose d’un widget bouton avec la classe Button. On peut donc
créer un bouton qui réagira de façon appropriée à chaque clic du bouton.
Exemple :
HEIGHT
qui produit :
Lorsque l’utilisateur clique sur le bouton, un carré coloré aléatoire est placé sur le
canevas. Décrivons le code en rapport avec le bouton :
— Ligne 19 : un bouton est créé. Il permet l’affichage du texte avec l’option text.
— Ligne 19 : on peut donner une option command au bouton : cette option doit pointer
vers la fonction qui sera exécutée lorsque l’utilisateur appuie sur le bouton. Cette
17
fonction doit être définie avant la définition du bouton (ici ligne 13, la fonction
dessiner). Ce type de fonction de commande ne doit recevoir aucun argument.
— lignes 13-17 : lorsqu’on clique sur le bouton, la fonction dessiner est appelée. Cette
fonction dessine avec une couleur aléatoire (ligne 14) à une position aléatoire (lignes
15-16) un carré sur le canevas (ligne 17).
La longueur variable de texte dans un bouton peut modifier la taille du bouton et donc de
la fenêtre parente. Pour éviter cela, on peut imposer des dimensions au bouton :
— height = nombre de lignes
— width = nombre de caractères
Si plus de caractères que la capacité permise par la largeur sont donnés dans le texte, des
caractères seront invisibles :
— Ligne 8 : un bouton est construit avec le constructeur Button (c’est une classe).
— Ligne 9 : comme pour tout widget, il faut l’inclure dans son environnement avec une
méthode particulière, ici la méthode pack.
— Ligne 8 : le texte passé dans l’option text est affiché sur le bouton.
— Si on clique sur le bouton, rien ne se passe de visible. Pour lier une action à un bouton,
il faudrait lui passer une option command.
19
Donnons une possibilité d’action au bouton : chaque fois qu’on clique le bouton, un logo
80x80 est dessiné sur le canevas :
Slider basique
— from_ : la valeur (numérique) en début du curseur (par défaut à gauche pour une
orientation horizontale) transmise à la fonction de commande; le blanc souligné qui
termine from_ est utilisé car on ne peut pas utiliser la variable from puisque c’est un
mot-clé du langage Python.
— to : la valeur (numérique) en fin de curseur (par défaut à droite pour une orientation
horizontale) transmise à la fonction de commande;
— Lignes 9-18 : la fonction de commande appelée lorsque le curseur est modifié. Il
semblerait que, par défaut, cette fonction reçoive en argument une chaîne de caractères
représentant un nombre entier et qui correspond à la position du curseur dans sa
graduation.
On peut aussi changer la longueur du curseur avec l’option length. Par exemple,
Le widget entrée
Le widget Entry (entrée en français) est un widget analogue aux champs des formulaires
html : l’utilisateur communique avec le programme en lui transmettant dans une zone de
texte des données écrites au clavier (ou par copier-coller).
Exemple simple
Dans l’exemple ci-dessous, on montre comment une entrée transmet son contenu à une
autre partie du programme. L’utilisateur remplit l’entrée avec du texte et s’il clique sur un
bouton, cela affiche le contenu de l’entrée dans la console :
L’utilisateur entre au clavier un entier dans le champ en bas de la fenêtre et il valide cette
entrée par appui sur la touche ESPACE. Cela provoque immédiatement l’affichage sur le
canvas de carrés aléatoirement placés et en nombre égal à la valeur tapée au clavier.
Le code correspondant est :
23
HEIGHT
25 root.mainloop()
— Ligne 21 : création d’une entrée.
— Ligne 22 : placement de l’entrée dans sa fenêtre.
— Ligne 23 : association de l’entrée my_entry avec une touche du clavier : quand
l’entrée a le focus, si on appuie sur une certaine touche indiquée comme premier
argument de bind (dans notre exemple la touche ENTRÉE référencée par <Return>),
une fonction de commande est exécutée (ici la fonction dessiner)
— Lignes 13-19 : la fonction appelée lorsque l’entrée est validée. Cette fonction reçoit
un événement event. Cet événement correspond à l’appui sur la touche ENTRÉE mais
n’est pas véritablement utilisé par la fonction dessiner. L’objet my_entry dispose
d’une méthode get permettant de capturer le contenu textuel de l’entrée, ici un entier.
Cet entier est lu sous forme de chaîne de caractères, donc il faut le convertir avec la
fonction int (ligne 14). Le reste du code crée un carré aléatoire et le dessine sur le
canevas.
Noter que le widget Entry ne gère pas automatiquement la validation du contenu de
l’entrée par appui sur une touche (cf. ligne 23).
4 my_entry = Entry(root,
5 font=’Arial 60 bold’,
6 width=’5’,
7 bg=’lavender’,
8 insertofftime=500,
9 relief=FLAT)
10 my_entry.pack(padx=20, pady=20) 11 my_entry.focus_set()
12
13
root.mainl
oop() qui
produit :
Par défaut, une entrée n’a pas le focus autrement dit, elle n’est pas en état de lire des
caractères. On l’active :
— soit avec la touche TAB
— soit en cliquant dans la zone de saisie de l’entrée.
Mais on peut forcer l’acquisition du focus par la méthode focus_set (ligne 11). Donc, dès
que l’application s’ouvre, l’entrée est réceptive aux touches de clavier.
La couleur de fond de la zone d’édition est déterminée par l’option bg (ligne 7).
Il est possible de choisir avec l’option font la police et la taille de la police de la zone de
saisie (ligne 5). On peut décider de limiter le nombre de caractères que peut accepter
l’entrée (ligne 5). La taille en pixels de la zone de saisie en sera modifiée mais cette taille
dépendra aussi la taille de la police.
Quand le focus est actif, un curseur guide la saisie. Le clignotement du curseur est
modifiable avec l’option insertofftime (ligne 500) qui désigne la durée en millisecondes
entre deux apparition du curseur (si 0 alors aucun clignotement). La couleur du curseur
est contrôlée par l’option insertbackground.
L’entrée est un entourée d’un bord dont l’épaisseur est contrôlée par l’option border.
Le style de relief de l’entrée est contrôlé par l’option relief, par défaut, on a
relief=SUNKEN (ligne 9).
On peut contrôler le texte entré par l’utilisateur grâce à l’option textvariable qui doit être
initialisée sur une variable de contrôle, par exemple StringVar. Un exemple est fourni au
28
paragraphe Exemple d’utilisation de StringVar. Noter qu’il n’y a pas d’option text valide
pour un widget Entry.
Une Entry ne permet pas d’entrer du texte sur plusieurs lignes. Utiliser plutôt le widget Text
(non décrit sur mon site) ainsi que c’est indiqué par Fredrik Lundh :
The entry widget is used to enter text strings. This widget allows the user to enter one line
of text, in a single font. To enter multiple lines of text, use the Text widget.
Après validation de l’entrée (on appuie sur ENTER), des carrés ont été dessinés sur le
canevas et l’entrée a été effacée si bien que l’utilisateur peut directement réutiliser l’entrée pour
générer des carrés sur le canevas.
Pour effacer la zone d’édition d’une entrée, on utilise la méthode Entry.delete :
29
HEIGHT
Gestion du curseur
Initialiser le placement du curseur
30
Une autre méthode consiste à utiliser les variables dynamiques (ou encore
appelées variables de contrôle) proposées par Tkinter. Ici, on va utiliser IntVar
(le rayon est entier). Voici le code :
— Ligne 20 : La position du curseur est contrôlée par l’objet défini par l’option variable
(ligne
20).
— ligne 16 : Initialement, variable (ligne 20) pointe vers une variable dynamique radius.
— Ligne 18 : radius est initialisée à un rayon r. La conséquence est qu’à l’ouverture, le
curseur pointera vers 42.
— Ligne 19 : L’initialisation de la variable de contrôle radius n’entraîne pas d’exécution
de la fonction de commande rayon. Pour que la dimension du cercle soit en conformité
avec la valeur indiquée par le curseur, le cercle est tracé.
Changer le sens de progression
L’état d’un curseur est déterminé par une variable state que l’on peut
modifier pour le rendre inactif. Par défaut, l’état est normal. L’état déactivé
est disabled. Par exemple, dans le code ci-dessous :
34
Faire un menu
déroulant Voici
un menu
déroulant :
35
8
9 def rose():
10 cnv[’bg’]="pink"
11
12 def rouge():
13 cnv[’bg’]="red"
14
15 def orange():
16 cnv[’bg’]="orange"
17
18 def violet():
19 cnv[’bg’]="purple"
20
21 # Barre de menus
22 mon_menu = Menu(root)
23 root.config(menu=mon_menu)
24
25 # Menu légumes
26 legumes = Menu(mon_menu, tearoff=0)
27 legumes.add_command(label="Radis", command=rose)
28 legumes.add_separator()
29 legumes.add_command(label="Tomate", command=rouge)
30 mon_menu.add_cascade(label="Légumes", menu=legumes)
31
32 # Menu fruits
33 fruits = Menu(mon_menu, tearoff=0)
34 fruits.add_command(label="Raisin", command=violet)
35 fruits.add_command(label="Orange", command=orange) 36
mon_menu.add_cascade(label="Fruits", menu=fruits)
37
38 root.mainloop()
36
Pour modifier (voire faire disparaître) le liséré noir autour du canevas, il faut
modifier une option du canevas nommé highlightthickness. Par défaut, il est
de 1 pixel et de couleur noire.
Le widget qui a le focus est entouré d’une bande rouge; quand il perd le focus, cette
bande devient rose. Si on appuie sur la touche TAB, le focus passe des widgets à l’autre
et les couleurs rose et rouge sont échangées à chaque changement de focus.
Le code de l’interface précédente montre qu’on peut contrôler les couleurs et la
dimension de la bande de témoin de focus :
Clavier et focus
Soit un jeu contenant plusieurs widgets, par exemple un canevas et une entrée (un widget
où on peut entrer du texte au clavier). On veut que le canevas réagisse à certains
événements du clavier, par exemple, si on appuie sur la barre d’espace, le joueur saute.
Comme le jeu contient plusieurs widgets, chaque widget a sa propre façon d’écouter le
clavier, un appui sur ESPACE dans le widget entrée n’aura pas même signification que
pour le canevas. Il faut donc qu’il y ait une manière de choisir l’interlocuteur entre le
clavier et les widgets. C’est ce qu’on appelle le focus.
Le focus est acquis en général par appuis successifs sur la touche TAB ou par clic de
souris (si vous cliquez sur un champ d’entrée, le champ prend le focus, comme dans un
formulaire d’une page web). Pour faire en sorte qu’un widget prenne automatiquement le
focus, on utilise la méthode focus_set du widget.
Voici un exemple avec un canevas :
quand on appuie sur la touche ENTRÉE, un carré aléatoire est dessiné sur le
canevas. Voici le
40
HEIGHT
— Ligne 9 : le texte du label est couplé à une variable de contrôle cpt définie
antérieurement
(ligne 7).
— Lignes 12 et 3-4 : quand le bouton reçoit un clic, la fonction sans
paramètre plus est appelée (ligne 3-4) et son code est exécuté. Ce code
43
récupère la valeur de cpt avec la méthode get; cette valeur est une chaîne
représentant un entier. On convertit cette chaîne en entier, on incrémente
et on met à jour la variable de contrôle cpt. Cela a pour effet de mettre à
jour le label.
On peut aussi se passer de StrVar et modifier directement la valeur du label :
— Ligne 8 : l’option text accepte une entrée numérique (qui n’est pas une
chaîne de caractères).
— Lignes 8 et 3-4 : la fonction de rappel plus met directement à jour le
contenu de l’entrée
(ligne 4).
Le widget Frame
Le widget Frame (cadre en français) est un widget qui sert juste de conteneur,
un peu comme une fenêtre Tk. Ce type de widget est très utile pour
regrouper et organiser des interfaces contenant beaucoup de widgets.
44
— ligne 6 : frame est un widget comme un autre et il doit donc être placé
avec un gestionnaire de géométrie, ici pack.
— ligne 5 : on peut donner une couleur de fond à un frame (on ne peut pas
pour un fenêtre Tk).
— lignes 7 et 10 : un frame est un conteneur et ici, il est le premier
argument des constructeurs Canvas et Button. qui affiche :
On peut donner une largeur et une hauteur à un frame mais la plupart du temps, ces
dimensions sont ignorées (sauf dans certains cas où on inhibe la propagation des
dimensions des widgets).
Boutons radio
Typiquement, on utilise des boutons radio dans des situations de choix conduisant à une
unique réponse comme entre un nombre strictement positif, strictement négatif ou nul :
45
— Lignes 7-9 : un bouton radio est un widget comme un autre; on le crée avec un
constructeur, ici RadioButton et on le place comme n’importe quel widget, ici avec la
méthode pack (et des options d’alignement pour que la sortie ne soit pas trop
disgrâcieuse).
— Lignes 11-13 et 15-16 : on crée et on place de même deux autres boutons radio.
— Pour chaque bouton, on dispose d’une option de texte descriptif (text) et de police
pour le texte (font).
Dans l’exemple ci-dessus, les boutons radio sont purement factices et rien n’est prévu
pour écouter s’ils sont cochés ou pas.
Un exemple avec interaction
Les boutons radio fonctionnent, en principe, par groupes. Par exemple, dans un QCM de
10 questions, il y aura 10 groupes de boutons radio. Toutefois, le programmeur va définir
autant de boutons radio qu’il a besoin (sans tenir compte des groupes) et c’est ensuite lui
qui définera les groupes (expliqué plus loin).
Dans ce qui suit, on va examiner une interface qui montre comment le programme peut
récupérer les informations fournies par un groupe de boutons radio.
L’interface contient cinq widgets :
46
29 text="Orange",
47
30 variable=fruit, 31 value="orange",
32 font="arial 20")
33 orange.pack(anchor="w")
34
35 banane = Radiobutton(
36 root,
37 text="Banane",
38 variable=fruit, 39 value="banane",
40 font="arial 20")
41 banane.pack(anchor="w")
42
43 lbl_fruit = Label(root, bg="white",
width=5) 44 lbl_fruit.pack(padx=50,
pady=50)
45
46 btn = Button(root, text="Couleur",
command=colorer) 47 btn.pack(padx=50,
pady=50)
48
49 root.mainloop()
— ligne 16 : une variable de contrôle (spécificité de Tkinter) initialisée à la
chaîne cerise. Elle initialise les options variable des trois boutons radio.
— Lignes 22 et 23 : les boutons radio sont munis de 2 nouvelles options :
variable et value. Si le bouton radio est activé (donc, on a cliqué dessus),
la valeur de la variable de contrôle sera value.
— Le point qui suit est essentiel : les trois boutons fonctionnent comme un
groupe (un seul des trois doit être coché); pour le faire comprendre à
Tkinter, il faut que leur option variable pointe vers la même variable de
contrôle (lignes 22, 30 et 38), ici appelée fruit (ligne 16).
— Ligne 7 : pour savoir quel bouton est coché, il suffit de regarder le contenu
de la variable de contrôle et de le comparer aux différentes value des
boutons.
Si les boutons radio sont nombreux, on utilisera plutôt une boucle for pour
les créer et les placer. A noter que si votre interface a une certaine
complexité et contient des boutons radio, il peut être approprié d’utiliser le
placement des widgets en grid.
Cas de plusieurs groupes
— Lignes 17 : une première variable de contrôle pour les fruits (cf. lignes 25 et 33).
— Lignes 19 : une seconde variable de contrôle pour les légumes (cf. lignes 44 et 52).
Déclencher une action
Comme pour d’autres widgets (bouton, entrée), un bouton radio dispose d’une option
permettant de générer une action (appel d’une fonction) lorsqu’un bouton est modifié. Par
exemple, on peut modifier le code ci-dessus pour que, lorsque l’utilisateur clique sur un
bouton radio, la couleur du fruit sélectionné apparaise dans le label :
50
51
— chaque boution radio (par exemple ligne 25) contient une option command
pointant vers la fonction colorer (sans argument, comme l’impose Tkinter)
— Lorsqu’un bouton est cliqué, la valeur commune de la variable de contrôle
fruit (ligne 16) est examinée et la coloration du label est déclenchée (lignes
9-13).
Dans l’application ci-dessus, la label affiche dynamiquement la somme des valeurs des
cases cochées.
Les widgets Checkbutton vont souvent par groupes mais il faut créer autant de widgets
Checkbutton que de cases à cocher. A la différence des boutons-radio dont un seul est
activable, on peut cocher plusieurs cases.
Ci-dessous, on crée 3 simples cases à cocher :
root=Tk()
Par ailleurs, on peut définir, pour chaque case à cocher, une fonction
référencée par l’option command et qui sera appelée chaque fois que la case
sera modifiée. Cela fournit une première méthode pour réaliser l’application
présentée tout au début :
1
from tkinter import *
— Lignes 16-21 : on crée les 3 cases à cocher; l’état de la case (cochée ou pas) est
contrôlé par la variable de contrôle v (c’est indispensable ici). Le fonctionnement des
53
cases à cocher défini par Tkinter stipule que le contenu de cette variable est l’entier 1
si la case est cochée, 0 sinon.
— Ligne 19, option text : le texte de la case à l’indice i est i+2.
— Ligne 20 : on utilise la méthode grid pour placer les cases.
— Lignes 14 et 21 : les 3 widgets ainsi que la variable de contrôle correspondante sont
placés en tuple dans une liste.
— Ligne 19, option command : chaque bouton réagit au clic sur la case. Si le bouton est
d’indice i, la fonction qui est appelée est g=f(i) (ligne 11). Noter que f est une fonction
qui renvoie une autre fonction.
— Lorsqu’une case à cocher est modifiée, sa fonction de rappel g (ligne 7), qui dispose
de l’indice i de la case modifiée va exécuter les actions suivantes :
— elle recalcule (ligne 8) la nouvelle somme : en effet, si une case est décochée,
v.get() vaut 0 et donc la valeur du texte n’est pas comptée et sinon, v.get() vaut 1 et
donc la valeur du texte est comptée;
— elle met alors le label à jour (ligne 9).
N’utiliser que des variables de contrôle Tkinter
Une autre façon de mettre à jour le label est d’appeler une fonction chaque fois qu’une
des variables contrôlant chaque case à cocher est modifiée. Cela se fait en utilisant la
méthode trace d’une variable de contrôle. Le code suivant montre le principe de la
méthode trace :
def f(*args):
Chaque fois que la variable de contrôle v est modifiée ailleurs dans le
programme, la fonction f est automatiquement appelée; ici, cette fonction
affiche la valeur contenue dans v. L’argument "w" de trace signifie write
(modification en écriture de v).
Voici le code complet de l’application :
54
Le widget Listbox
Le widget Listbox propose une liste dont les éléments sont sélectionnables à
la souris ou avec les flèches Haut et Bas du clavier :
— placer le focus avec la méthode focus_set (et qui n’est pas propre à ce
widget) : sans toucher à la souris, on peut se déplacer dans la liste avec la
souris;
— sélectionner une cellule par son indice (à partir de 0)
— modifier la couleur de certaines cellules avec la méthode
itemconfigure. Voici un code qui utilise ces méthodes :
1
from tkinter import *
57
Action associée
On peut aussi modifier le contenu du texte d’une ligne d’une listbox. Dans
l’exemple ci-dessous :
— Ligne 1-2 : pour des raisons d’esthétique, j’ai choisi d’utiliser la barre de
Ttk.
— Ligne 4 : la liste contient 30 items.
— Ligne 19 : on place une barre (par défaut verticale); sa commande pointe
vers le déplacement vertical des items de la liste lbox.
— Ligne 20 : on place soigneusement la barre pour qu’elle recouvre tout le
côté de la liste.
— Ligne 21 : on apparie cette fois la listbox à la barre.
Le widget spinbox
Il dispose d’une zone de texte et deux boutons de défilement. A partir d’une succession
d’éléments textuels, dans l’exemple les nombres de 2019 à 2024, ce widget permet de
faire défiler ces élements dans la zone de texte en progressant dans un sens ou dans
l’autre selon les boutons qui vont recevoir un clic. Voici le code d’une version
minimaliste :
spinbox_mini
mal.py from
tkinter import
* root=Tk()
root.mai
nloop()
qui
produit :
qui produit :
63
spinbox_simple_texte.py
La zone de texte est en fait une entrée (widget de la classe Entry) et est donc modifiable.
Toutefois, comme une liste de chaînes à afficher est en général prédéfinie, l’intérêt de
pouvoir modifier directement la zone de texte n’est pas immédiat. Sans compter la
possibilité d’écraser accidentellement une valeur. Et justement, il est possible de faire en
sorte que la zone de texte soit non modifiable. Il suffit pour cela d’utiliser l’option
state="readonly". Toutefois, ce changement d’état modifie la couleur de fond de la zone
de texte pour bien montrer qu’elle est désactivée, ce qui n’est pas forcément souhaité. On
peut y remédier en définissant une option readonlybackground. Voici un exemple :
64
On peut faire en sorte qu’une action soit exécutée chaque fois que la zone de texte est
modifiée par appui sur un des deux boutons. Pour cela, comme pour la plupart des
widgets de Tkinter, on utilise l’option command. Pour faire simple, on va parcourir des
nombres et on va afficher dans la console le nombre placé dans la zone de texte du
spinbox après clic :
65
Le module standard Ttk propose une barre de progression. Voici un exemple minimal :
67
Un appel de start sans paramètre effectue une progression toutes les 50 ms.
Barre de progression qui s’arrête
Ce qui suit est essentiel pour faire fonctionner une interface graphique sous
Tkinter. Il suppose que vous avez un minimum de familiarité avec les
widgets.
Pour illustrer, considérons un jeu du Pendu en version très simplifiée : le
joueur choisit des lettres en cliquant sur des boutons à la recherche de lettres
cachées dans une zone de texte.
On souhaite que :
70
— lorsqu’un clic découvre une lettre présente dans le mot inconnu, la lettre
soit rendue visible et donc que l’astérisque qui couvre la lettre disparaisse;
— tout clic (gagnant ou perdant) sur une lettre jamais encore choisie
provoque la désactivation du bouton sur lequel le joueur a cliqué (c’est
assez naturel puisqu’il n’y a aucune raison que le joueur re-clique sur le
même bouton).
Chaque lettre de la zone de texte est un label. On veut donc qu’à chaque clic :
— le texte du label bascule de * vers la
lettre trouvée; — le bouton soit modifié
(et désactivé).
On doit donc changer l’état des deux widgets. Tous les widgets d’une interface
Tkinter ont des options, souvent très nombreuses. Par exemple, un bouton a
une option state qui peut prendre trois valeurs selon l’état de réceptivité du
widget. De même, un label a une option text qui indique le contenu du texte
qu’on lit sur le label ou encore une option bg pour la couleur de fond du
label. L’état d’un widget est déterminé par l’état de ses options. Ce qui
anime une interface graphique est que ses widgets changent d’état.
Il existe essentiellement deux syntaxes pour changer une option (il existe
une 3e façon moins usuelle qui ne sera que très brièvement évoquée). Ainsi,
dans le jeu du Pendu, pour chager l’astérisque d’un label appelé disons lbl
en, par exemple, la lettre E, on pourra écrire : lbl["text"] = "E"
C’est la syntaxe la plus simple, sous forme de dictionnaire. Bien noter que lbl est
ici une référence vers le widget, le nom de l’option text est placé entre
guillement pour obtenir une chaîne de caractère. Et "E" est la nouvelle
valeur de l’option du widget.
Dans l’exemple du jeu du Pendu, pour désactiver un bouton nommé btn, on
écrira par exemple :
btn["state"]=DISABLED
Il existe une 2e syntaxe qui consiste à utiliser la méthode configure de chaque
widget : lbl.configure(text="E")
que StringVar. Une telle variable est mise à jour automatiquement, sans
qu’on réaffecte comme ci-dessus. Pour voir une situation typique, consulter
Exemple d’utilisation de StringVar. Cette utilisation toutefois peut être
évitée dans de nombreuses situations.
formule = ""
def click(num):
global formule
formule = formule + str(num)
equation.set(formule)
def equalclick():
try:
global formule
result = str(eval(formule))
equation.set(result)
formule = result
except:
equation.set(" error ")
formule = ""
def effacer():
global formule
formule = ""
72
equation.set("")
if __name__ == "__main__":
master = Tk()
master.title("Calculatrice")
master.geometry("375x315")
master.config(background="#000011")
equation = StringVar()
formule_field = Entry(master, textvariable=equation)
formule_field.grid(columnspan=4, pady= 30 , padx = 20 , ipadx = 100 ,
ipady = 10)
btn_1 = Button(master, text=' 1 ', command=lambda: click(1), height=2,
width=10)
btn_1.grid(row=2, column=0)
divide.grid(row=5, column=3)
master.mainloop()
#################################
#### Fonctions de conversion ####
#################################
listehexa=["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"]
listebinaire=["0000","0001","0010","0011","0100","0101","0110","0111","1000",
"1001","1010","1011","1100","1101","1110","1111"]
def binairedecimal(string):
x=len(string)-1
n=0
res=0
while x!=-1:
if string[x]=="1":
res=res+2**n
n=n+1
x=x-1
return res
def decimalbinaire(string):
quotient=int(string)
liste=[]
res=""
while quotient!=1:
liste=liste+[quotient%2]
quotient=quotient/2
liste=liste+[1]
while liste!=[]:
res=res+str(liste[-1])
liste=liste[:-1]
return res
def binairehexa(string):
liste=[]
res=""
while len(string)>4:
liste=liste+[string[-4:]]
string=string[:-4]
liste=liste+[string]
while len(liste[-1])!=4:
liste[-1]="0"+liste[-1]
for x in range(len(liste)):
i=listebinaire.index(liste[x])
liste[x]=listehexa[i]
while liste!=[]:
res=res+liste[-1]
liste=liste[:-1]
return res
def hexabinaire(string):
res=""
for x in range(len(string)):
i=listehexa.index(string[x])
75
res=res+listebinaire[i]
return res
def decimalhexa(string):
return binairehexa(decimalbinaire(string))
def hexadecimal(string):
return binairedecimal(hexabinaire(string))
#############################
#### Interface graphique ####
#############################
def convertir():
saisie=Esaisie.get()
x,y=basedepart.get(),basearrivee.get()
couple=(x,y)
if couple==(1,2):
res=decimalbinaire(saisie)
elif couple==(1,3):
res=decimalhexa(saisie)
elif couple==(2,1):
res=binairedecimal(saisie)
elif couple==(2,3):
res=binairehexa(saisie)
elif couple==(3,1):
res=hexadecimal(saisie)
elif couple==(3,2):
res=hexabinaire(saisie)
else :
res="Euh..... B00lay ??"
fen2=Toplevel()
Label(fen2,text="Resultat").pack()
Label(fen2,text=res).pack()
fen2.mainloop()
fen=Tk()
fen.title("Convertisseur Multi-Bases")
Label(fen,text="Saisissez la valeur\na convertir").pack(side=TOP)
Esaisie=Entry(fen)
Esaisie.pack(side=TOP)
Fgauche=Frame(fen)
Fgauche.pack(side=LEFT)
Label(Fgauche,text="Base de depart").pack()
basedepart=IntVar()
Radiobutton(Fgauche,text="Decimal",variable=basedepart,value=1,indicatoron=0,
width=15).pack()
Radiobutton(Fgauche,text="Binaire",variable=basedepart,value=2,indicatoron=0,
width=15).pack()
Radiobutton(Fgauche,text="Hexadecimal",variable=basedepart,value=3,indicatoro
n=0,width=15).pack()
Fdroite=Frame(fen)
Fdroite.pack(side=RIGHT)
Label(Fdroite,text="Base d'arrivee").pack()
basearrivee=IntVar()
Radiobutton(Fdroite,text="Decimal",variable=basearrivee,value=1,indicatoron=0
,width=15).pack()
Radiobutton(Fdroite,text="Binaire",variable=basearrivee,value=2,indicatoron=0
,width=15).pack()
Radiobutton(Fdroite,text="Hexadecimal",variable=basearrivee,value=3,indicator
on=0,width=15).pack()
76
Bconvertir=Button(fen,text="Convertir",command=convertir)
Bconvertir.pack(side=BOTTOM)
fen.mainloop()
def dessine_horloge() :
can1.create_oval(25, 25, 175, 175, fill='', width=8,outline='gold')
can1.create_oval(20, 20, 180, 180, fill='', width=1)
can1.create_oval(92,92,108,108,
fill='gold',outline='black',width=1,tag="axe")
can1.tag_bind("axe","<ButtonRelease>",affich_digit)
can1.tag_bind("axe","<Enter>",curseur_main)
can1.tag_bind("axe","<Leave>",curseur_fleche)
i = 1
while i < 61 :
j = i*((2*pi)/60)
# diametre horloge = 75 centre canvas =100,100
x=(cos(j)*75)+100
y=(sin(j)*75)+100
can1.create_oval(x-1, y-1, x+1, y+1, fill='blue')
if i in (15,30,45,60):
can1.create_oval(x-4, y-4, x+4, y+4, fill='black')
if i in (5,10,20,25,35,40,50,55):
77
def affich_digit(e) :
global iafd
if iafd == 0 :
iafd=1
else : iafd=0
def aff_heure() :
global hala, mala, heuala, indala, iafd
dateheure=localtime()
heur=dateheure[3]
minu=dateheure[4]
seco=dateheure[5]
heurd=heur
minud=minu
if str(heur) == str(hala) and str(minu) == str(mala) and iala == 1 :
Beep(800,100)
if heur >12 :
heur = heur -12
if ichro == 1 :
t1=(dateheure[3]*3600)+(dateheure[4]*60)+dateheure[5]
tchro = t1 - t0
hchro = int(tchro/3600)
mchro = int((tchro-(hchro*3600))/60)
schro=tchro-(hchro*3600)-(mchro*60)
affchro.configure(text = '%d' %hchro+'.%02d' %mchro+'.%02d'%schro,
bg='white')
# affich heures
heur=heur+(minu/60.00)
j=(heur+9)*((2*pi)/12)
x=(cos(j)*55)+100
y=(sin(j)*55)+100
can1.coords(aigheu, 100, 100, x, y)
# affich minutes
minu=minu+(seco/60.0)
j=(minu+45)*((2*pi)/60)
x=(cos(j)*65)+100
y=(sin(j)*65)+100
can1.coords(aigmin, 100, 100, x, y)
# affich secondes
j=(seco+45)*((2*pi)/60)
x=(cos(j)*70)+100
y=(sin(j)*70)+100
can1.coords(aigsec, 100, 100, x, y)
if ichro == 1 and tchro < 60 :
x=(cos(j)*84)+100
y=(sin(j)*84)+100
can1.create_oval(x-1, y-1, x+1, y+1, fill='green',
outline='darkgreen')
#afficher heure digitale
if iafd == 1 :
afdigi.configure(text = '%d' %heurd +" h " +'%02d' %minud)
else : afdigi.configure(text ='',bg='lightgrey')
can1.after(999,aff_heure)
def dessine_alarme() :
global can2 , choixala, iala, dessala
if dessala == 0 :
can2 = Canvas(fen1, width=200, height=50, bg='lightgrey')
can2.pack()
choixala = Label(can2,font=('Arial', 7),fg='darkgreen')
choixala.pack(side=BOTTOM)
curs= Scale(can2, from_=0.0, to=12.00, length=150, sliderlength=7,
78
def choix_alarme(valcurs) :
global hala, mala, heuala
heuala=float(valcurs)
j=(heuala+9)*((2*pi)/12)
x=(cos(j)*70)+100
y=(sin(j)*70)+100
can1.coords(aigala, 100, 100, x, y)
can1.itemconfigure(aigala,fill="red")
hala=int(heuala)
mala=int((heuala - hala) * 60)
dateheure=localtime()
heur=dateheure[3]
if heur > 11 :
hala = hala + 12
choixala.configure(text = "Déclencher l'alarme à " +'% d' %hala +" h. "
+'%02d' %mala)
def set_alarme() :
global indala, iala, dessala
dessala = 0
if iala ==1 :
can1.delete(indala)
bouala.config(bg='red')
j=(heuala+9)*((2*pi)/12)
x=(cos(j)*75)+100
y=(sin(j)*75)+100
indala=can1.create_oval(x-2, y-2, x+2, y+2, fill='red')
iala =1
affala.configure(text = '%d' %hala +" h." +'%02d' %mala,bg='white')
can2.destroy()
Beep(1000,20)
def setoff_alarme() :
global indala, iala, dessala
if dessala == 1 :
can2.destroy()
dessala = 0
bouala.config(bg='grey')
can1.itemconfigure(aigala,fill="lightgrey")
if iala ==1 :
can1.delete(indala)
iala =0
affala.configure(text = '',bg='lightgrey')
Beep(100,50)
def chrono() :
global ichro, t0
if ichro == 0 :
ichro = 1
dateheure=localtime()
t0=(dateheure[3]*3600)+(dateheure[4]*60)+dateheure[5]
bouchro.config(bg='green')
elif ichro == 1 :
79
ichro = 2
bouchro.config(bg='lightblue')
else :
ichro = 0
bouchro.config(bg='grey')
can1.create_oval(16, 16, 184, 184, fill='', outline='lightgrey',
width=6)
affchro.configure(text='',bg='lightgrey')
def aff_infos(e) :
feninf = Toplevel()
feninf.config(bg='lightblue')
geo1=fen1.winfo_geometry()
geox=fen1.winfo_rootx()
geoy=fen1.winfo_rooty()
feninf.geometry("270x260+"+str(geox-50)+"+"+str(geoy-22))
feninf.title("À propos de Horloge")
labinf=Label(feninf, bg='lightblue',fg='black',width=50,font=('Arial',
9),
text= "\nHorloge v.1.3\n\n"
"Programme écrit en Python / Tkinter\n"
"et distribué sous licence GNU GPL.\n\n"
"© 2007 Yves Le Chevalier\n"
"( yveslechevalier@free.fr )\n\n"
"Ce programme affiche une horloge \n"
"avec une alarme, un chronomètre et \n"
"un affichage digital losque l'on clique \n"
"sur l'axe des aiguilles. ")
labinf.pack(pady=5)
bouf3=Button(feninf, text="Fermer", command=feninf.destroy,bg="orange",
fg='brown')
bouf3.pack(side=BOTTOM,pady=10)
#feninf.transient()
feninf.grab_set()
feninf.wait_window()
def curseur_main(e) :
fen1.config(cursor='hand2')
def curseur_fleche(e) :
fen1.config(cursor='arrow')
# main
fen1 = Tk(className='Horloge')
fen1.geometry("+500+400")
fen1.resizable(width=False, height=False)
can1 = Canvas(fen1, width=200, height=200, bg='lightgrey')
aigala = can1.create_line(100, 100, 100, 35, fill='', width=1,arrow=LAST)
aigheu = can1.create_line(100, 100, 100, 50, fill='blue', width=3)
aigmin = can1.create_line(100, 100, 100, 40, fill='blue', width=2)
aigsec = can1.create_line(100, 100, 100, 27, fill='yellow', width=1)
bouala=Button(can1, text="Alarme", command=dessine_alarme, font=('Arial',
7),bg='grey')
bouala.place(x=2,y=2)
affala = Label(can1, font=('Arial', 7))
affala.place(x=4,y=22)
bouchro=Button(can1, text="Chrono", command=chrono, font=('Arial',
7),bg='grey')
bouchro.place(x=163,y=2)
affchro = Label(can1, font=('Arial', 7))
affchro.place(x=164,y=22)
bquit=Button(can1, text="Quitter", command=fen1.destroy, font=('Arial',
6),bg='pink',fg='black')
bquit.place(x=2,y=183)
afdigi = Label(can1, font=('Arial',9,'bold'),fg="blue")
80
afdigi.place(x=78,y=188)
signature='YLC.gif'
signat=PhotoImage(file=signature)
sign=can1.create_image(192,195, image=signat,tag="ylc")
can1.tag_bind("ylc","<ButtonRelease>",aff_infos)
can1.tag_bind("ylc","<Enter>",curseur_main)
can1.tag_bind("ylc","<Leave>",curseur_fleche)
can1.pack()
dessine_horloge()
aff_heure()
fen1.mainloop()
#Création de la fenètre
fen=Tk()
fen.title("FENETRE DE CONNEXION")
fen.geometry("400x300+450+200")
fen.resizable(False, False)
fen.configure(background="#091821")
call(["python", "menu_principal.py"])
else:
messagebox.showwarning("", "Erreur de connexion")
txtmdp.delete("0", "end")
txtuser.delete("0", "end")
#Ajouter le titre
lbltitre=Label(fen, borderwidth=3, relief=SUNKEN, text="FORMULAIRE DE
CONNEXION", font=("Sans Serif", 15), bg="#091821", fg="white")
lbltitre.place(x=0, y=0, width=400)
#Exécution
fen.mainloop()
#Création de la fentre
fen=Tk()
fen.title("MENU PRINCIPAL")
fen.geometry("1350x700+0+0")
fen.resizable(False, False)
fen.configure(background="#091821")
#lES FONCTIONS
#Ajouter
def Ajouter():
matricule=txtmatricule.get()
nom=txtnom.get()
postnom=txtpostnom.get()
prenom=txtprenom.get()
sexe=valeursexe.get()
grade=combograde.get()
adresse=txtadresse.get()
base=sqlite3.connect("employe.db")
con=base.cursor()
if(matricule=="" and nom=="" and postnom=="" and sexe=="" and grade==""
and adresse==""):
messagebox.showerror("Attention !", "Veuillez remplir les champs
vides")
txtmatricule.delete("0", "end")
txtnom.delete("0", "end")
txtpostnom.delete("0", "end")
txtprenom.delete("0", "end")
valeursexe.delete("0", "end")
combograde.delete("0", "end")
txtadresse.delete("0", "end")
else:
con=sqlite3.connect("BDDEMPLOYE.db")
cur=con.cursor()
req1="CREATE TABLE IF NOT EXISTS T_EMPLOYE(mat TEXT PRIMARY KEY, nom
TEXT NOT NULL, postnom TEXT NOT NULL, prenom TEXT NOT NULL, sexe TEXT NOT
NULL, grade TEXT NOT NULL, adresse TEXT NOT NULL)"
cur.execute(req1)
req2="INSERT INTO T_EMPLOYE(mat, nom, postnom, prenom, sexe, grade,
adresse) VALUES(?, ?, ?, ?, ?, ?, ?)"
con.execute(req2, (matricule, nom, postnom, prenom, sexe, grade,
adresse))
con.commit()
messagebox.showinfo("Information", "Employé ajouté")
fen.destroy()
call(["python", "menu_principal.py"])
#Retour
con.close()
#Modifier
def Modifier():
matricule = txtmatricule.get()
nom = txtnom.get()
postnom = txtpostnom.get()
prenom = txtprenom.get()
sexe = valeursexe.get()
grade = combograde.get()
83
adresse = txtadresse.get()
if(matricule==""):
messagebox.showerror("Attention", "Veuillez saisir le matricule de
l'employé")
txtmatricule.delete("0", "end")
else:
con = sqlite3.connect("employe.db")
cur = con.cursor()
req1 = "CREATE TABLE IF NOT EXISTS T_EMPLOYE(mat TEXT PRIMARY KEY,
nom TEXT NOT NULL, postnom TEXT NOT NULL, prenom TEXT NOT NULL, sexe TEXT NOT
NULL, grade TEXT NOT NULL, adresse TEXT NOT NULL)"
cur.execute(req1)
cur.execute("UPDATE T_EMPLOYE SET nom=?, postnom=?, prenom=?, sexe=?,
grade=?, adresse=? where mat=?", (nom, postnom, prenom, sexe, grade, adresse,
matricule))
con.commit()
messagebox.showinfo("Information", "Information modifié avec succès")
select=cur.execute("select * from T_EMPLOYE")
select=list(select)
table.insert('', END, values=select[0])
con.close()
fen.destroy()
call(["python", "menu_principal.py"])
#Fonction supprimer
def Supprimer():
codeselectionner=table.item(table.selection())["values"][0]
con=sqlite3.connect("employe.db")
cur=con.cursor()
delete_=cur.execute("delete from T_EMPLOYE where
mat={}".format(codeselectionner))
con.commit()
table.delete(table.selection())
#Ajouter le titre
lbltitre=Label(fen, borderwidth=3, relief=SUNKEN, text="MENU PRINCIPAL",
font=("Sans Serif", 25), bg="#2F4F4F", fg="#FFFAFA")
lbltitre.place(x=0, y=0, width=1350, height=100)
#Boutton Enregistrer
btnEnregistrer=Button(fen, text="Enregistrer", font=("Arial", 16),
bg="#D2691E", fg="white", command=Ajouter)
btnEnregistrer.place(x=70, y=550, width=150)
#Boutton Modifier
btnModifier=Button(fen, text="Modifier", font=("Arial", 16), bg="#D2691E",
fg="white", command=Modifier)
btnModifier.place(x=240, y=550, width=150)
#Boutton Supprimer
btnSupprimer=Button(fen, text="Supprimer", font=("Arial", 16), bg="#D2691E",
fg="white", command=Supprimer)
btnSupprimer.place(x=410, y=550, width=150)
#Exécution de la fenetre
fen.mainloop()
86
3.1 Présentation
Nous allons conserver ces paramètres par défaut. Passez à l’écran suivant de
l’assistant
2. Vous pouvez ensuite choisir le ou les types de bases de données manipulées par le
projet.
Sélectionnez HyperFileSQLClassic (la base de données proposée par défaut avec
WinDev).
2. Vous pouvez ensuite choisir le ou les types de bases de données manipulées par le
projet.
2. Le fichier de données que nous allons créer est le fichier "Etudiant". Son nom est
donc
" Etudiant ". Ce nom sera utilisé :
- pour manipuler le fichier de données en programmation. La variable associée au
fichier sera
Compte.
- pour construire le nom du fichier de données physique associé (fichier Etudiant.fic).
3. Nous allons modifier la taille de la rubrique. Cliquez sur la case "50" et remplacez
"50" par "10". Cliquez sur la ligne suivante. Les valeurs sont automatiquement mises
à jour.
"Matricule" pour activer les champs de description présents sur la droite de l’écran. Il
suffit alors de préciser le type de clé utilisé. Dans notre cas, le numéro de compte est
une clé uni-que.
7. L’état va contenir une rupture (cochez ‘’Oui’’). Les ruptures servent à regrouper
les données ;
8. L’assistant propose automatiquement la rubrique la rubrique de rupture. Ce sont les
rubriques pour lesquelles nous avons défini un tri dans la requête ;
9. Cet écran est très important. En effet, il permet d’associer les différentes rubriques
associées à l’état aux différentes zones de l’état. ;
10. L’écran suivant nous propose de faire un total sur une rubrique calculée à chaque
fin de rupture. Acceptez et passer à l’écran suivant ;
11. Pour les dimensions du papier, choisissez l’affichage en mode paysage. Passez à
l’écran suivant ;
12. Choisissez un gabarit pour votre état (ActivVista par exemple) ;
13. Donnez un nom et un titre à l’état ;
14. Validez ;
15. L’état est automatiquement créé ;
16. Enregistrez l’état dans le dossier par défaut.
Nous allons maintenant apporter une petite amélioration à l’état que nous venons de
réaliser chaque nouvel organisme bancaire va s’afficher une nouvelle page.
L’organisme bancaire est la rubrique qui sert de tri et de rupture. Nous allons donc
ajouter un saut de page après chaque rupture.
Dans WinDev, lors de la création d’un projet manipulant des données, vous devez tout
d’abord créer une "analyse". Une "analyse" contient la description des fichiers (ou
tables) contenant les données de l’application.
C’est seulement lors de l’exécution de l’application, que ces descriptions sont utilisées
pour créer la base de données et/ou les fichiers de données. C’est dans cette base ou
dans ces fichiers que seront stockées les données.
WinDev sait gérer différents formats de base de données (pour ne pas dire tous). Les
plus courantes sont :
Pour accéder aux données, il existe différentes techniques (appelées "modes d’accès")
:
• Accès Natif
• Accès OLE DB
• Accès ODBC direct
• Accès ODBC via OLE DB
Hyper File :
Le format Hyper File est le format de base de données fourni avec WinDev. Ce format
de base de données est commun à WinDev et WebDev.
3.8.1 Présentation
WinDev propose plusieurs solutions pour réaliser cette migration sur le poste de
développement :
Pour mieux se rendre compte des différentes étapes, nous allons migrer l’application
de gestion de comptes que nous avons réalisé dans la partie 2 de ce livre, en utilisant la
première méthode.
Migration de l’exemple
Une version corrigée du projet étudié dans la partie 2 est disponible avec ce cours
d’auto-formation. Nous allons migrer ce projet pour tester en mode Client-Serveur.
1. Ouvrez le projet;
2. Affichez l’analyse du projet (option ‘’Projet.. Charger l’analyse’’). L’éditeur
d’analyse s’affiche ;
3. Dans l’éditeur d’analyse, sélectionnez l’option
‘’Analyse..HyperFileSQLClient/Serveur.. Passage en
HyprFileSQLClient/Serveur’’. Un assistant s’ouvre, permettant de créer une
connexion au serveur HyperFileSQL installé sur le poste.
4. Indiquez dans les plans suivants :
11. Vous avez migré le projet de développement. Il peut être également nécessaire de
migrer l’application déployée (par exemple si l’application déployée utilise des
fichiers HyperFileSQLClassic). Cette opération se paramètre lors de la création du
programme d’installation de l’application.
Transactions ;
Journal ;
Procédures stockées
Triggers.
3.8.3 Administrer
Par exemple, il est possible d’installer sur le même poste un serveur HyperFileSQL de
tests, avec une base de données de tests, et un serveur HyperFileSQL de production,
utilisant un port différent.
2. Cliquer sur ‘’ HyperfileSQL C/S’’. La zone qui apparait peut être vide si le centre
de contrôle HyperFlieSQL n’a jamais été utilisé depuis ce poste ;
3. Cliquer sur l’icône dans l’écran qui apparait par exemple ‘’Serveur
HyperFileSQL’’ et indiquez le nom de votre poste.
A-Nom poste
B-Nom du serveur HyperFileSQL
C-Nom de la base
D-Fichier de données de la base.
3.8.7 Conclusion
Le centre de contrôle HyperFileSQL est un outil redistribuable qui doit être installé
chez les clients possédant des bases de données HyperFileSQL Client/serveur. Le
centre de contrôle HyperFileSQL doit être utilisé par l’administrateur des bases
données.
Procédure :
Une fois l’analyse créée, il faut maintenant créer les fichiers de données (tables) : clic
droit dans l’espace de l’analyse – Nouveau fichier de données et cette fenêtre apparait :
Prendre Créer une nouvelle description d’un fichier de données, puis suivant.
Indiquer le nom du fichier puis suivant ; choisir une fois de plus le type de base de
données (dans notre cas, HyperFileSQLClassic) puis suivant – suivant – suivantpour
terminer ; une fenêtre apparait, faire la description des rubriques du fichier puis OK
pour terminer.
Code source :
Btn_Valider
SINON
Info("Les données entrées sont incorrectes !")
RAZ()
FIN
Btn_Quitter
Ferme(login)
Btn_Joueur
Ouvre(FEN_joueur)
Btn_Quitter
SELON Dialogue("Voulez-vous quitter cette application s.v.p ?")
CAS 1
Ferme()
FIN
Btn_Valider
EcranVersFichier()
// S'il s'agit d'un nouvel enregistrement
SI Nom<>"" ET Postnom<>"" ALORS// Lecture des informations saisies
// On l'ajoute
HLitRecherche(jouer,code,Code)
EcranVersFichier()
SI HTrouve(jouer)
// On le modifie
Info("Cet enregistrement existe déjà !")
RAZ()
SINON
HAjoute(jouer,hVérifieIntégrité)
TableAffiche(JOUER,taRéExecuteRequete)
TableSelectMoins(JOUER)
Modifier..Grisé=Vrai
Supprimer..Grisé=Vrai
MoiMême..Grisé=Faux
RAZ()
FIN
SINON
Info("Veillez remplir le champs vides")
FIN
Btn_Modifier
SI TableSelect(JOUER)=-1 ALORS RETOUR
//1 : &Modifier
//2 : &Ne pas modifier
//1 : &Modifier
//2 : &Ne pas modifier
//1 : &Modifier
//2 : &Ne pas modifier
SELON Dialogue("Voulez-vous modifier cet enregistrement ?")
// &Supprimer
CAS 1
EcranVersFichier()
HModifie(club)
TableAffiche(JOUER,taRéExecuteRequete)
RAZ()
Valider..Grisé=Faux
MoiMême..Grisé=Vrai
Supprimer..Grisé=Vrai
TableSelectMoins(JOUER)
Info("Operationréissie !")
CAS 2
FIN
Btn_Supprimer
SI TableSelect(JOUER)>0 ALORS
//1 : &Supprimer
//2 : &Ne pas supprimer
//1 : &Supprimer
//2 : &Ne pas supprimer
//1 : &Supprimer
//2 : &Ne pas supprimer
SELON Dialogue("Voulez-vous supprimer cet enregistrement ?")
// &Supprimer
CAS 1
HSupprime(jouer)
TableAffiche(JOUER)
Valider..Grisé=Faux
Modifier..Grisé=Vrai
Supprimer..Grisé=Vrai
RAZ()
TableSelectMoins(JOUER)
Info("Operation réussie !")
// &Ne pas supprimer
CAS 2
FIN
SINON
Info("Operationréissie !")
FIN
iImprimeEtat(ETAT_Joeur)
Ferme(FEN_Etat1)
Btn_Imprimer
HAnnuleDéclaration(REQ_etat1)
HExécuteRequête(REQ_etat1,hRequêteDéfaut,test)
iAperçu(i100)
iImprimeEtat(ETAT1)
Btn_annuler
Ferme()
2) Type d’état : Prendre Etat vierge (pour créer vous-même un état du début à la
fin), puis suivant ;
3) Indiquer la source des données à imprimer : Prendre D’un fichier de données
ou d’une requête existante, puis suivant ;
4) Sélectionner le fichier ou la requête à partir duquel ou de laquelle on veut créer
l’état, puis suivant ;
5) Indiquer si l’état a une rupture de séquence. Dans ce cas :
1) Prendre oui, puis suivant ;
2) Indiquer la rubrique de rupture de séquence. (Il est à noter que la rupture
de séquence ne peut être faite que sur une rubrique triée), puis suivant.
6) Sélectionner par la coche les rubriques à afficher dans l’état, puis suivant ;
7) Choisir le format du papier (par défaut le A4), puis suivant ;
8) Choisir un gabarit (par défaut Aucun : à garder de préférence), puis suivant ;
9) Donner le nom de l’état, puis OK pour terminer.
Haut de page : Intitulé de l’état et aussi des champs des fichiers (tables) ;
Bas de page : Donnée à afficher au bas de la page quel que soit son contenu
(Page remplie ou pas. Par exemple : Note de bas de page, Numéro de page) ;