LANGAGE PYTHON



Fenêtre et boutons:


Le package Tkinter  comprend un ensemble de modules qui permettent de créer des fenêtres, des boutons, etc..


Vous pouvez ainsi créer des applications fenêtrées.


  • Création d'une fenêtre



- tester le code ci-dessous:



#importation de tous les modules de Tkinter

from tkinter import *

#création de la fenêtre associée à la variable (objet) fen1

fen1 = Tk()

#titre de la fenêtre

fen1.title("ma super fenêtre")

#taille de la fenêtre en pixels

fen1.geometry("400x200")

#écriture dans le label lbl1 placé dans la fenêtre

lbl1 = Label(fen1, text="Bonjour tout le monde", fg='red')

lbl1.pack()

#ajout d'un bouton quitter appelé btn1

btn1 = Button(fen1, text="Quitter", command=fen1.destroy)

btn1.pack()

#abonnement de la fenêtre aux messages de Windows

fen1.mainloop()



Explications:


fen1= Tk()  :  la fonction constructeur "Tk()" créée un objet fenêtre appelé ici fen1 

lbl1= Label(fen1, text='Bonjour tout le monde !', fg='red') : crée un objet zone de texte lbl1, avec la fonction constructeur  Label (....), dans le constructeur Label (....) le premier argument est le nom de la fenêtre qui doit afficher la zone de texte  (ici fen1  ). L'argument text détient le texte à afficher dans la zone, l'argument  fg  est la couleur de texte (fg: foreground en Anglais).

lbl1.pack() : applique la méthode "pack()" à l'objet  lbl1, cette méthode place l'objet  lbl1 sur la fenêtre et agit sur sa position, La méthode "geometry()" fixe une taille de 400 x 200 pixels à la fenêtre.

fen1.mainloop(): cette instruction est nécessaire pour que la fenêtre soit « à l'affût » des clics de souris, des pressions exercées sur les touches du clavier, etc. Elle initialise l'application.


Créer une méthode associée à un objet bouton


Dans l’exemple précédent, le bouton « Quitter » déclenche la commande " fen1.destroy", c'est-à-dire l’appel de la méthode "destroy()" de l’objet fen1.  Vous n’avez pas écrit la méthode "destroy()", elle a été écrite par les concepteurs de Tkinter.


On peut écrire sa propre fonction et l’associer comme action à exécuter si on clique sur un bouton, voici la démarche:


  • Création du code d'un bouton :


# ajout de l’objet bouton btn2 à la fenêtre fen1, le bouton appellera la fonction popup() quand on cliquera dessus


btn2 = Button(fen1, text="Clique", command=popup)

btn2.pack()


  • Définition de la fonction (méthode) popup ():


La méthode (fonction) "popup() " demandera la création de la boite de message ci-dessous :



Les boites de message Windows sont des fenêtres particulières prêtes à l'emploi. Elle se trouve dans  Tkinter, ici la boite de message voulue est générée par la fonction « showinfo()» du module messagebox du package tkinter. Voici la définition de notre méthode "popup()"  qui demande la création d'une boite de message de type "showinfo()" configurée pour afficher le message montré ci-dessus:


def  popup():

   messagebox.showinfo("Information", "tu as cliqué !")




  • Le code complet avec le nouveau bouton:

    - tester le code ci-dessous:

#Importations des modules et fonctions de l'interface Tkinter


from tkinter import  Tk, messagebox, Label, Button



# Définition de la fonction popup()

def  popup():

   messagebox.showinfo("Information", "tu as cliqué !")




#création de la fenêtre associée à la variable fen1

fen1 = Tk()

#titre de la fenêtre

fen1.title("ma super fenêtre")

#taille de la fenêtre en pixels

fen1.geometry("400x200")

#écriture dans le label lbl1 placé dans la fenêtre

lbl1 = Label(fen1, text="Bonjour tout le monde", fg='red')

lbl1.pack()

#ajout d'un bouton quitter appelé btn1

btn1 = Button(fen1, text="Quitter", command=fen1.destroy)

btn1.pack()

#ajout du bouton btn2 qui appelera la fonction popup() définie plus haut

btn2 = Button(fen1, text="Clique", command=popup)

btn2.pack()

#abonnement de la fenêtre aux messages de Windows

fen1.mainloop()


Le résultat:



Remarque: 


En tant qu'argument de command  dans "Button(....)" la méthode "popup() est écrite sans ses parenthèses, on écrit command=popup et non command = popup():


btn2 = Button(fen1, text="Clique", command=popup)


Vous retrouver cette écriture pour toutes les fonctions placées comme argument de command , par exemple la méthode "destroy()" d'une fenêtre:


btn1 = Button(fen1, text="Quitter", command=fen1.destroy)



Positionnement des éléments sur une fenêtre


Tous les éléments d’une fenêtre (boutons, zone de texte, etc..) sont appelés des widgets en python. Les widgets peuvent  être positionnés dans les fenêtres à l'aide de trois méthodes différentes : la méthode grid(), la méthode pack() et la méthode place().


La méthode pack() que vous avez déjà utilisée ne permet pas un positionnement  très précis.


La méthode grid() permet d’associer une grille à la fenêtre dans laquelle sont positionnés les widgets. La grille est composée de lignes et de colonnes. Une ligne est appelée row et une colonne column 


Voyons comment positionner les widgets pour obtenir le rendu suivant :



La fenêtre comprend :

- 3 champs de type Label qui affichent Nom, Prénom et âge,

- 3 zones de saisie de texte (Entry en python),

- un Canvas dans lequel on positionne  l’image d’un blaireau.


Ci-dessous, vous voyez la grille avec ses colonnes ( Col ) et ses lignes ( Row ), un élément placé dans une cellule peut être positionné avec une marge, c'est le cas de l'image du blaireau. Les textes dans les labels peuvent être alignés à droite, à gauche, en haut ou en bas de la case où ils sont placés, dans l'exemple les textes sont alignés à droite:




Le widget  label « txt1 »  qui affiche « Nom » est en Row=1, et column=1  son texte est aligné à droite (sticky=E),  il se programmera :


txt1 = Label(fen1, text ='Nom')

txt1.grid(row =1, column =1, sticky =E)


Sticky veut dire « collé », on peut coller à droite (E) à gauche (W), en haut (N) ou en bas (S), ce sont les points cardinaux qui ont été retenus pour spécifier le positionnement.


Le widget canvas « can1 » a une largeur de 220 pixels (width =220) et une hauteur de 220 pixels (height=220) et  il a un fond blanc ( bg ='white') .  Il est positionné en row=1 et column=3, mais  il occupe 3 lignes soit une étendue (rowspan =3).  Il doit y avoir une marge de 10 px autour du widget  selon x (padx=10)  et une marge de 5 pixels  selon y  (pady=5; ce qui se programmera :  


can1 = Canvas(fen1, width = 220, height =220, bg ='white')

can1.grid(row =1, column =3, rowspan =3, padx =10, pady =5)


Le code complet:


- tester le code ci-dessous ( attention, télécharger (cliquez-ici) et placer le fichier 'Blaireau.gif'  dans le même dossier que le fichier du code python, dans l'exemple ci-dessous, le fichier python s'appelle code.py et il est au même endroit que l'image)


Le contenu de code.py:


from tkinter import Tk, messagebox, Label, Button, Entry, Canvas, E, PhotoImage



fen1 = Tk()

# création de widgets 'Label' et 'Entry' :

txt1 = Label(fen1, text ='Nom')

txt2 = Label(fen1, text ='Prénom')

txt3 = Label(fen1, text ='age')

entr1 = Entry(fen1)

entr2 = Entry(fen1)

entr3 = Entry(fen1)

# création d'un widget 'Canvas' contenant une image bitmap :

can1 = Canvas(fen1, width = 220, height = 220, bg ='white')

photo = PhotoImage(file ='Blaireau.gif')

# image centrée dans le canvas x=100 et y=110

item = can1.create_image(110,110,image = photo)

# Positionnement des widgets à l'aide de la méthode 'grid' :

txt1.grid(row =1, column =1, sticky =E)

txt2.grid(row =2, column =1,  sticky =E)

txt3.grid(row =3, column =1, sticky =E)

entr1.grid(row =1, column =2)

entr2.grid(row =2, column =2)

entr3.grid(row =3, column =2)

can1.grid(row =1, column =3, rowspan =3, padx =10, pady =5)

# démarrage de l'application:

fen1.mainloop()



Exercice 1 du niveau 3


Ajouter un bouton en ligne4 et colonne2 de la fenêtre, associer ce bouton à la fonction lecture_champ().

Récupérer le contenu des trois Entry et les copier dans une liste.

Afficher la liste avec un print.


Exemple de récupération du contenu d'une Entry puis affichage des données récupérées dans une messagebox:



  • Gérer le temps


Python propose le module time que vous pouvez importer pour connaître l'heure, faire des pauses dans un programme, etc..



L'heure POSIX:


L'heure Posix est une mesure qui représente le temps écoulé depuis le 1 janvier 1970. On peut se servir de cette information pour déterminer le temps écoulé entre deux instants par soustraction de deux lectures successives de l'heure Posix.


La fonction time() du module time renvoie l'heure Posix


La fonction sleep(x) du module time effectue une pose de x secondes



- Tester le programme ci-dessous:


import time

debut, actu = time.time(), time.time()

while actu - debut < 6 :

    print ("Le programme s'exécute depuis",int(actu - debut),"secondes.")

    # attente d'une seconde

    time.sleep(1)

    # actualisation du temps avant de reboucler

    actu = time.time()

# dés que la boucle while est finie

print ("C'est fini !")


Conclusion: ce programme compte 6s puis affiche c'est fini.


La structure temps


La structure temps est un tuple(1) de nombres entiers qui contient toutes les informations concernant le temps: l'année, le mois, le jour, l'heure, les minutes et les secondes. On peut accéder aux données en connaissant l'indice ou le nom de chaque info dans le tuple:


indice: 0 => nom= tm_year => année

indice: 1 => nom= tm_mon => mois  (la valeur est comprise entre  1 à 12)

indice: 2 => nom= tm_mday => jour = ( la valeur est comprise entre 1 et 31)

indice: 3 => nom= tm_hour => heure = ( la valeur est comprise entre 0 et 23)

indice: 4 => nom= tm_min => minutes

indice: 5 => nom= tm_sec => secondes



(1) rappel: un tuple est une liste d'éléments que l'on peut lire mais pas modifier.


On obtient une structure temps avec la fonction localtime(t) qui convertit une heure Posix t:


Exemple:


import time

# t est une variable qui contient l'heure posix

t = time.time()

# tmp est une variable tuple structure temps obtenue à partir de t

tmp = time.localtime(t)

# récupération de l'heure par l'indice dans le tuple

heure = tmp[3]

# autre méthode: récupération de l'heure par son nom dans le tuple

heure2 = tmp.tm_hour


Remarque:  la fonction mktime(tmp) convertit la structure temps tmp en heure Posix



Pour faciliter l'affichage de messages on dispose de deux autres fonctions qui permettent de passer d'une structure temps à une chaîne de caractères ou l'inverse:


strftime( fmt, tmp ) : renvoie une chaîne de caractères au format date  fmt  à partir d'une structure temps  tmp. Si le paramètre tmp n'est pas renseigné, l'affichage sera basé sur l'heure locale.


strptime( fmt, tmp ) : transforme la chaîne de caractères fmt  en structure temps.


Le format d'une chaîne de caractères date  fmt  ( voir exemple ci-dessous ) est une chaîne de caractères formatée avec des mots clés:


Le mot clé  %d  est remplacé dans la chaîne par le jour du mois.

Mot clé  %H  contient l'heure au format 24h.

Mot clé  %j  contient le numéro du jour de l'année soit un nombre entier compris entre 1 et 366.

Mot clé  %m  contient le numéro du mois soit un nombre entier compris entre 1 et 12.

Mot clé  %M  contient les minutes.

Mot clé  %S  contient les secondes.

Mot clé  %w  contient le jour de la semaine ( 0= lundi).

Mot clé  %y  contient les deux derniers chiffres de l'année.

Mot clé  %Y  contient l'année sur 4 chiffres.


Exemples:


import time

#la chaîne de caratères formatées

fmt = " nous sommes le %d/%m/%y, il est %H:%M:%S"

#affichage de la chaîne de caractères avec mise à jour par la fonction des infos temps:

 print( time.strftime(fmt))


En utilisant toutes les fonctions de conversion décrites précédemment, on obtiendrait le même résultat, exemple:


import time

# t est une variable qui contient l'heure posix

t = time.time()

# tmp est une variable tuple structure temps obtenue à partir de t

tmp = time.localtime(t)

# fmt est une chaîne de caractères formatée date

fmt = " nous sommes le %d/%m/%y, il est %H:%M:%S"

print (time.strftime( fmt, tmp))



Tester le programme précédent



Répéter à intervalle régulier:


Le module Tkinter propose la méthode after(.....) applicable à une fenêtre qui permet de déclencher une fonction après un délai précisé en millisecondes. Cette fonction peut être appelée à intervalle régulier pour obtenir un mouvement, un rafraîchissement d'infos, etc..


On procède ainsi:


nom_fenetre.after( delai_en_ms, fonction_à_appeler)



Tester le programme ci-dessous qui affiche l'heure dans une fenêtre:


#importation des modules

from tkinter import *

import time




#définition d'une fonction affiche()

def affiche():

    #formatage de la date et affichage dans le label lbl ( zone d'affichage dans la fenêtre)

    f="nous sommes le %d/%m/%y, il est %H:%M:%S"

    lbl.config(text=time.strftime(f))

    # Ici la fonction affiche se rappelle elle même toutes les 500 ms

    # ne pas mettre de parenthèses à la fonction affiche dans la méthode after 

    fenetre.after(500,affiche)


# Le programme principal:

#création de la fenêtre et configuration de ses propriétés

fenetre = Tk()

fenetre.geometry("300x50")

#création d'une zone d'affichage de texte sur la fenêtre

lbl=Label(fenetre,text="heure")

#positionnement du label dans la fenêtre

lbl.place(x=10,y=10)

'''Appel de la fonction affiche() par le programme principal

ce qui va lancer l'affichage toutes les 500ms'''

affiche()

# abonnement aux messages Windows

fenetre.mainloop()



Exercice 2 du niveau 3



Créer un minuteur graphique qui décompte de 60 s à 0.



  • Créer des mouvements



Pour gérer des déplacements dans une zone d'affichage (un canvas en python) il faut connaître le système de coordonnées de la zone d'affichage, voici le repérage d'une zone d'affichage de 200 px de large sur 150 px de haut:



Pour déplacer le point  A on doit changer ses coordonnées XA, YA en lui affectant une vitesse.  On décide un mouvement horizontal vers la gauche,  le vecteur vitesse aura une composante nulle selon Y ( VAy=0) et une composante négative selon X par exemple VAx= - 5 pour déplacer de 5 pixels (VAx est négatif parce que l'on doit diminuer la coordonnée XA du point A). Dés que le point atteint ou dépasse le bord, on peut inverser le sens du vecteur vitesse pour gérer un rebond par exemple. En python tout ça est simple à programmer:


VAx, VAY =  -5, 0

# mise à jour des coordonnées XA, YA 

XA, YA = XA + VAx , YA+ VAY


XA, YA, VAx, VAY  sont des variables associées à un nombre entier. Si le point se déplace, il faut répéter la mise à jour des coordonnées avec la méthode  after()  vue dans les exemples du niveau 2.


Tester le programme ci-dessous d'une balle qui rebondit sur les bords de la fenêtre:


from tkinter import *

#la fonction animation()qui gère le mouvement

def animation():

    global VX, VY, BalleX, BalleY

    futurX, futurY = BalleX + VX, BalleY + VY

    #détection des bords en tenant compte du rayon de la balle

    if futurX > 290 or futurX < 10 :

        VX = - VX

        futurX = BalleX + VX

    if futurY > 190 or futurY < 10 :

        VY = - VY        

        futurY = BalleY + VY

    # mise à jour du centre de la balle

    BalleX, BalleY = futurX, futurY

    # balle redessinée aux nouvelles coordonnées

    Fond.coords(Balle, BalleX - 10, BalleY - 10, BalleX + 10, BalleY + 10)

    # rappel de la fonction au bout de 40ms

    fenetre.after(40,animation)


# le programme principal

fenetre=Tk()

fenetre.geometry("300x200")

#la zone d'affichage

Fond=Canvas(fenetre,width=300,height=200,bg="white")

Fond.grid()

# la vitesse initiale

VX, VY = 2, 2

#la position initiale de la balle

BalleX, BalleY = 50, 100

# la balle (une forme ovale)

Balle = Fond.create_oval(40, 90, 60, 110, fill = 'red')

#appel de la fonction animation

animation()

# abonnement aux messages Windows

fenetre.mainloop()



  • Gérer le clavier



Chaque fois qu'une touche est enfoncée, on dit qu'un événement est déclenché. La fonction mainloop() surveille les événements.


Appui sur une touche classique


On doit définir une fonction qui s'exécutera dés que l'événement concernant l'appui sur une touche est détecté, on utilise pour ça la méthode  bind_all(............) de la fenêtre


La méthode se déclare toujours ainsi:


ma_fenetre.bind_all('<Key>', ma_fonction)


La fonction qui gérera l'événement clavier prendra un paramètre obligatoire qui doit s'appeler evt


def ma_fonction(evt):

    .................


Le paramètre evt  permet de récupérer la nature de l'événement produit, par exemple  evt.char renvoie le caractère correspondant à la touche qui vient d'être enfoncée ( voir exemple ci-dessous).


Voici un programme qui permet de déplacer une balle sur l'écran avec les touches A, S, Q, D:


- Tester le programme, ci dessous:


#importation des fonctions de tkinter

from tkinter import *


# Définition de la fonction touche qui gère l'appui sur les touches du clavier

#*****************************************************************************

def touche(evt):

    # on agit sur les variables X et Y du programme principal pour positionner la balle

    global X,Y

    '''la fonction upper() convertit en lettre capitale a => A,

       le nom de la touche est stockée dans la variable t '''

    t = evt.char.upper()

    # déplacement de 5 px selon touche enfoncée

    if t == 'A' :

        Y = Y - 5

    elif t == 'Q' :

        Y = Y + 5

    elif t =='S' :

        X = X - 5

    elif t =='D' :

        X = X + 5

    # on redessine la balle à ses nouvelles coordonnées

    Fond.coords(Balle,X-10, Y-10, X+10, Y+10)

#*******************************************************************************


#Le programme principal

#**************************************************************


fenetre = Tk()


# la zone de dessin

Fond=Canvas(fenetre,width=500,height=500,bg="white")

Fond.grid()


# variables globales X et Y ( position de la balle)

# les coordonnées initiales qu'aura la balle

X, Y = 60, 60


# Création de la balle

Balle = Fond.create_oval(50,50,70,70,fill='red')


# liaison de notre fonction "touche" avec les événements clavier

fenetre.bind_all('<Key>', touche)


# abonnement de la fenêtre aux événements détectés par Windows

fenetre.mainloop()


#**************************************************************



Exercice 3 du niveau 3



Modifier le programme précédent pour éviter à la balle de sortir de l'écran, il vous faut interdire le déplacement selon X et Y si les valeurs de X et Y sont celles des bords + le rayon balle.     





Créé avec HelpNDoc Personal Edition: Produire facilement des livres électroniques Kindle