Quelques exercices Tkinter utiles

Transcription

Quelques exercices Tkinter utiles
Quelques exercices Tkinter utiles
1. Gestion redimensionnement des fenêtres
Composition sur une grille :
-
-
Première ligne : une entry qui capte l’événement return et un bouton qui modifie le label central avec le
texte de l’entry suivi d’un texte précisant la méthode de validation (click sur le bouton ou retour
charriot).L’entry doit toujours rester collé à son élément de gauche et à son élément de droite, ainsi un
redimensionnement horizontal le forcera à s'agrandir proportionnellement
Deuxième ligne un label qui suit les redimensionnements de la fenêtre dans les 4 directions
Troisième ligne : gestion de deux cases à cocher pour avoir l'option de bloquer la possibilité de
redimensionner la fenêtre sur l'axe horizontal et/ou vertical. On les places sous le label l'une sous l'autre et
elles seront automatiquement redimensionnés sur l'axe horizontal le cas échéant. On crée un bouton quitter
à côté des deux cases à cocher - donc étendu sur deux lignes.
Pour imposer une taille minimale - celle de départ - en cas de redimensionnement de la fenêtre on utilise les
méthodes self.minsize, self.winfo_width() et self.winfo_height().
Pour imposer une taille maximale - 1/4 de l'écran - en cas de redimensionnement de la fenêtre : self.maxsize().
Pour placer le centre de la fenêtre au centre de l'écran on utilise les 4 méthodes précédentes et la méthode
'geometry'.
Si l'on veut permettre à un paramètre d'un widget de subir des modifications ultérieures une solution simple est
d'utiliser des variables Tkinter (ici l’entry, le label central et les cases à cocher) : les méthodes IntVar() et StringVar()
par exemple génèrent ce type de variable. Leur contenu est ensuite accessible et modifiable avec get() et set(). Toute
modification de la variable entraîne automatiquement la modification du paramètre du widget avec lequel elle est
liée. C'est très pratique !
La prise en compte de sticky ne sera généralement faite que lorsque vous aurez configurer les colonnes et/ou les
lignes concernées de la manière suivante :
-
on précise le numéro de la colonne et un poids. Celui-ci permet de gérer un redimensionnement dans des
proportions différentes selon la colonne. Ici la colonne 0 sera deux fois plus agrandie que la colonne 1 lors
d'un redimensionnement horizontal
self.grid_columnconfigure(0,weight=2)
self.grid_columnconfigure(1,weight=1)
-
idem pour un redimensionnement vertical
self.grid_rowconfigure(1,weight=1)
-
les deux lignes suivantes servent à empêcher tout redimensionnement automatique de la fenêtre en cas de
dépassement de la fenêtre d'un widget :
self.update()
self.geometry(self.geometry())
-
lors de la selection de la fenêtre on donne le focus à l'entry
self.entry.focus_set()
-
on sélectionne tout le contenu de l'entry automatiquement
self.entry.selection_range(0,END)
-
la méthode 'resizable' prend en paramètre deux booléens, le premier autorise le redimensionnement
horizontal et le second vertical. De plus la méthode 'resizable' sans arguments retourne une chaîne de 3
caractères : '0 0','0 1','1 0','1 1' selon les autorisations de redimensionnement :
self.resizable(not int(self.resizable()[0]),int(self.resizable()[2]))
2. Fenêtre avec scrollbar
Tester avec Idle le code suivant pour repérer le fonctionnement des barres de défilement : Tkinter fourni des objets
graphiques « défilables » (Entry, Text, Canvas et listbox), mais ceux-ci ne gèrent pas leurs propres barres de
défilement. Pour ce faire il est nécessaire d’ajouter un widget Scrollbar et l’attacher à l’objet graphique désiré.
La partie du code importante est en gras.
# -*- coding: cp1252 -*from Tkinter import *
class MaFrame(Frame):
def __init__(self,*args,**argw):
Frame.__init__(self,*args,**argw)
scrollbar = Scrollbar(self,orient=VERTICAL)
scrollbar.grid(row=0,column=8,sticky="ns")
listbox = Listbox(self)
listbox.grid(row=0,column=0,columnspan=8,sticky="nswe")
for i in range(30):
listbox.insert(END, i)
listbox.config(yscrollcommand=scrollbar.set)
scrollbar.config(command=listbox.yview)
for i in range(26):
row=i/8
col=i%8
Button(self,bg="black",fg="white",width=4,height=2,text="%s"
l=chr(i+65):self.commandeTest(l)).grid(row=row+1,column=col,padx=5,pady=5)
self.grid_columnconfigure(0,weight=1)
self.grid_columnconfigure(1,weight=1)
self.grid_columnconfigure(2,weight=1)
self.grid_columnconfigure(3,weight=1)
self.grid_columnconfigure(4,weight=1)
self.grid_columnconfigure(5,weight=1)
self.grid_columnconfigure(6,weight=1)
self.grid_columnconfigure(7,weight=1)
self.grid_rowconfigure(0,weight=1)
%(chr(i+65)),command=lambda
def commandeTest(self,lettre):
print lettre
class FenApp(Tk):
def __init__(self,*args,**argw):
Tk.__init__(self,*args,**argw)
MaFrame(self).grid(column=0,row=0,sticky="nsew")
Button(self,text="Quitter",command=self.quitter).grid(row=1,column=0,sticky="ew")
self.grid_columnconfigure(0,weight=1)
self.grid_rowconfigure(0,weight=1)
def quitter(self):
self.quit()
self.destroy()
if __name__=="__main__":
FenApp().mainloop()
Essayer ensuite le programme suivant et tester le une première fois.
# -*- coding: cp1252 -*from Tkinter import *
class FrameTest(Frame):
def __init__(self,*args,**argw):
Frame.__init__(self,*args,**argw)
for i in range(26):
row=i/8
col=i%8
Button(self,bg="black",fg="white",width=20,height=10,text="%s" %(chr(i+65)),
command=lambda l=chr(i+65):self.commandeTest(l)).grid(row=row,column=col,padx=5,pady=5)
#self.grid_columnconfigure(col,weight=1)
#self.grid_rowconfigure(row,weight=1)
self.lab=Label(self,text="",width=2,anchor='center',font=("Helvetica",100, "bold italic"))
self.lab.grid(row=4,column=3,columnspan=3,rowspan=2,pady=20)
#self.grid_rowconfigure(4,weight=1)
#self.grid_columnconfigure(3,weight=1)
def commandeTest(self,l):
self.lab.configure(text=l)
class FenScroll(Toplevel):
def __init__(self,*args,**argw):
Toplevel.__init__(self,*args,**argw)
FrameTest(self,*args,**argw).grid(column=0,row=0,sticky="nsew")
Button(self,text="Quitter",command=self.destroy).grid(column=0,row=1,sticky="sew")
self.grid_columnconfigure(0,weight=1)
self.grid_rowconfigure(0,weight=1)
class FenApp(Tk):
def __init__(self,*args,**argw):
Tk.__init__(self,*args,**argw)
Button(self,text="Fenêtre contenant une Frame scrollable", command=self.lanceToplevel).grid(column=0,row=0,
sticky="EWNS")
Button(self,text="Quitter",command=self.quitter).grid(column=1,row=0,sticky="EWNS")
self.grid_columnconfigure(0,weight=1)
self.grid_columnconfigure(1,weight=1)
self.grid_rowconfigure(0,weight=1)
def lanceToplevel(self):
FenScroll(bg="black")
def quitter(self):
self.quit()
self.destroy()
if __name__=="__main__":
FenApp().mainloop()
La Frame ne supporte pas les barres de défilement. Une première solution peut être envisagée en enlevant les 4
lignes de codes en commentaire afin de mieux gérer le redimensionnement de la fenêtre. Tester une deuxième
fois : la solution n’est pas forcément adaptée en raison des polices de caractère. Une seconde solution est de mettre
malgré tout des barres de défilement. Pour cela il vous faut modifier le code pour placer la Frame dans un Canvas
avec create_window puis d’ajouter des barres de défilement au canevas.
3. Drag and drop
Faire une classe CanvasDnD spécialisant un Canvas : deux méthodes movable et unmovable pourront rendre une
liste d’objets de dessin du Canvas déplaçable ou non à la souris. Trois méthodes « brouillées » géreront le drag and
drop : __drag, __drop et __release. Une fenêtre d’application permettra de tester le Canvas.
Indications :
-
Les méthodes de Canvas : tag_bind et tag_unbind, permettent d’associer un handler à un objet de dessin
Les événements à capter sont : "<Button-1>", ,"<Button1-ButtonRelease>", <Button1-Motion>"
La variable CURRENT contient toujours la référence de l’objet de dessin situé sous la souris
La méthode lift de la classe Canvas permet de faire passer sur le dessus de la pile un objet de dessin
4. Structure programme : classes / modules / packages
Observer dans le fichier testMesWidgets.py la manière dont est gérée l’importation des modules bouttons.py et
canvas.py inclus dans le package mesWidget (il s’agit du répertoire contenant un fichier vide __init__.py) et les
classes que ces modules contiennent.