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.