Infoforall

Python 13 : Gestion graphiques des interfaces : Placement des éléments

Les prérequis à cette partie sont ici :

Nous avons vu pour l'instant la méthode pack qui place visiblement les widgets les uns sous les autres, et la méthode place qui permet de placer le widget à des coordonnées X Y précises. Nous allons voir qu'on peut faire beaucoup mieux que ce qu'on a fait jusqu'à présent !

1 - La méthode PACK

La méthode pack() est la méthode que nous avons employé jusqu'à présent pour faire s'afficher un widget dans notre application graphique :

Imaginons une interface comportant quatre boutons :

#!/usr/bin/env python

# -*- coding: utf-8 -*-


from tkinter import *


# DEFINITIONS DES FONCTIONS

def boutonFourreTout():

    return(0)


# CORPS PRINCIPAL DU PROGRAMME

fenetre = Tk()


bouRouge = Button(fenetre, text="FILE", fg="white", bg="red", command = boutonFourreTout)

bouVert = Button(fenetre, text="EDIT", fg="white", bg="green", command = boutonFourreTout)

bouBleu = Button(fenetre, text="RUN", fg="white", bg="blue", command = boutonFourreTout)

bouNoir = Button(fenetre, text="QUIT", fg="white", bg="black", command = boutonFourreTout)


bouRouge.pack()

bouVert.pack()

bouBleu.pack()

bouNoir.pack()


fenetre.mainloop()

Ce qui donne sans surprise :

4 boutons

C'est assez moche, non ?

En réalité, la méthode pack (ou fonction propre à un objet Widget) a été utilisée sans argument jusqu'à présent. Mais on peut lui en donner beaucoup ! On peut même lui donner des arguments nommés, ce qui permet de les donner dans n'importe quel ordre. Celui qui nous interesse se nomme side et on peut transmettre graçe à lui les valeurs LEFT, RIGHT, TOP et BOTTOM. Attention à la casse : il faut laisser les majuscules.

01° Modifier le programme pour tenter d'afficher 2 boutons sur une première ligne et les suivants sur la ligne d'après.

Pour l'exemple, on peut obtenir :

4 boutons

...EXEMPLE DE CORRECTION...

bouRouge.pack(side = LEFT)

bouVert.pack(side = TOP)

bouBleu.pack(side = TOP)

bouNoir.pack(side = TOP)

4 boutons

...EXEMPLE DE CORRECTION...

bouRouge.pack(side = LEFT)

bouVert.pack(side = LEFT)

bouBleu.pack(side = LEFT)

bouNoir.pack(side = LEFT)

4 boutons

...EXEMPLE DE CORRECTION...

bouRouge.pack(side = LEFT)

bouVert.pack(side = TOP)

bouBleu.pack(side = RIGHT)

bouNoir.pack(side = BOTTOM)

Bref, c'est pas facile, si ?

La méthode pack est donc très rapide à utiliser mais pas très pratique lorsqu'il y a beaucoup de widgets.

Bien. Nous n'arrivons pas à placer les widgets en 2x2, mais peut-on au moins leurs faire prendre un espacement maximum ?

La réponse est oui, à l'aide du paramètre nommé fill. On peut avoir :

02° En utilisant la méthode pack avec des arguments side et fill, tentez de retrouver le moyen de réaliser l'affichage suivant :

4 boutons

...EXEMPLE DE CORRECTION...

bouRouge.pack(side = LEFT, fill = Y)

bouVert.pack(side = TOP, fill = X)

bouBleu.pack(side = RIGHT, fill = X)

bouNoir.pack(side = BOTTOM, fill = X)

Le résultat a l'air beaucoup plus correct mais si on tente d'agrandir la fenêtre, cela peut donner ceci :

4 boutons

On peut faire un peu mieux en utilisant le paramètre expand.

03° En utilisant le code suivant, observer le rôle du paramètre expand lorsqu'on lui donne TRUE en argument.

bouRouge.pack(side = LEFT, fill = Y)

bouVert.pack(side = TOP, fill = X)

bouBleu.pack(expand = TRUE, side = RIGHT, fill = BOTH)

bouNoir.pack(side = BOTTOM, fill = BOTH)

Comme vous pouvez le constater, on peut donc faire quasiment ce qu'on veut, mais il faut réfléchir. Parfois, on ne trouve pas.

2 - La méthode GRID

Il existe heureusement une deuxième méthode permettant d'affecter une place aux widgets d'une fenêtre. Il s'agit de la méthode grid qui veut dire GRILLE en français.

Le principe est simple : on crée des lignes (row) et des colonnes (column). La taille des cellules n'est pas uniforme, elles sont fixées en fonction de la place disponible et des arguments transmis.

Numérotation : Comme dans la plupart des cas, le premier élément n'est pas l'élément 1 mais l'élément 0.

04° Reprendre le code précédent et remplacer les méthodes pack() par les méthodes grid() suivantes :

bouRouge.grid(row=0,column=0)

bouVert.grid(row=0,column=1)

bouBleu.grid(row=1,column=0)

bouNoir.grid(row=1,column=1)

Voilà le résultat en taille normale ou après augmentation de la taille :

4 boutons 4 boutons

05° Utiliser le paramètre nommé sticky pour améliorer un peu le rendu. Cela permet de coller le widget sur le côté indiqué.

Il faut utiliser les 4 points cardinaux en anglais (N (North), S(South), W(West) ou E(East)) ou une combinaison des 4 : N+E, S+W ...

Ainsi, sticky=E ou sticky=W+N sont valides.

On peut néanmoins imposer à un widget de prendre un peu plus de place SI NECESSAIRE: le paramètre nommé rowspan indique le nombre de lignes sur lesquelles un widget peut s'étaler. L'attribut columnspan fait la même chose pour les colonnes.

06° Tester le code suivant :

bouRouge.grid(row=0,column=0)

bouVert.grid(row=1,column=1)

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

bouNoir.grid(row=3,column=3)

On obtient :

4 boutons

07° Remplacer le grid pour bouVert : bouVert.grid(row=1,column=1,columnspan=2).

Assez "étrangement", on obtient ceci :

4 boutons

Explication : elle tient en deux choses :

08° Remplacer bouVert par ceci :

bouVert = Button(fenetre, text="EDIT EDIT EDIT", fg="white", bg="green", command = boutonFourreTout)

Cette fois, on peut voir l'intérêt du columnspan : plutôt que de repousser la 3e colonne, bouVert utilise la 2e colonne et la 3e colonne pour écrire son texte.

4 boutons

ATTENTION : Ne mélangez jamais (jamais) les méthodes pack et grid dans une même fenêtre graphique.

3 - Les marges internes : ipadx et ipady

Les deux méthodes précédentes savent également gérer

Pour augmenter la taille interne du widget, nous allons utiliser ipadx=10 pour créer 10 pixels de plus horizontalement et ipady=10 pour créer 10 pixels de plus verticalement.

09° Testez avec ceci :

bouRouge.grid(row=0,column=0, ipadx=20)

bouVert.grid(row=1,column=1,columnspan=2)

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

bouNoir.grid(row=3,column=3,ipady=20)

4 boutons

Vous pouvez utiliser ceci également avec pack. Même synthaxe.

bouRouge.pack(fill=X, ipady=10)

bouVert.pack(fill=X, ipady=20)

bouBleu.pack(fill=X, ipady=30)

bouNoir.pack(fill=X, ipady=60)

4 boutons

4 - Les marges externes : padx et pady

C'est exactement la même syntaxe que avec ipad mais sans le i pour interne : cette fois, on écarte les autres widgets en les repoussant. Mais la marge d'espace entre les deux widgets n'aura pas la couleur de background de widget mais celle de la fenêtre elle-même :

bouRouge.pack(fill=X, ipady=10, padx=10,pady=10)

bouVert.pack(fill=X, ipady=20, padx=10,pady=10)

bouBleu.pack(fill=X, ipady=30, padx=10,pady=10)

bouNoir.pack(fill=X, ipady=60, padx=10,pady=10)

Ce qui donne :

4 boutons

10° Modifier votre interface pour voir l'influence des deux arguments.

5 - Bouton QUIT

Si vous voulez un vrai bouton QUIT, il suffit de lui rajouter le code suivant dans la fonction que ce bouton appele : fenetre.destroy().

11° Modifier votre programme pour qu'il comporte au moins une touche QUIT fonctionnel.

6 - La fenêtre principale

On peut donner un nom à l'interface graphique ainsi que lui imposer une taille. Pour cela, il suffit de spécifier ainsi ces éléments :

fenetre = Tk()

fenetre.title("NOM DE VOTRE PROGRAMME")

fenetre.geometry("500x500")

12° Modifier votre code pour personnaliser le titre de l'interface et imposer la géométrie initiale.

4 boutons

7 - Les cadres : les frames

Parfois, on ne parvient pas à se débrouiller avec juste le pack() ou le grid(). Il faut alors associer l'une des deux méthodes à des cadres d'encadrement. Un cadre (frame) consiste en réalité à créer une sous-zone dans la zone de votre fenêtre. Or, vous pourrez très facilement placer votre cadre et le remplir ensuite à votre manière.

Le mieux est encore de faire un exemple :

#!/usr/bin/env python

# -*- coding: utf-8 -*-


from tkinter import *


# DEFINITIONS DES FONCTIONS

def boutonFourreTout():

    fenetre.destroy()

    return(0)


# CORPS PRINCIPAL DU PROGRAMME

fenetre = Tk()

fenetre.title("NOM DE VOTRE PROGRAMME")

fenetre.geometry("500x400")


bouRouge = Button(fenetre, text="FILE", fg="white", bg="red", command = boutonFourreTout)

bouVert = Button(fenetre, text="EDIT EDIT EDIT", fg="white", bg="green", command = boutonFourreTout)


# - - - - - C'est sur cette zone qu'on définit une Frame - - - -

zone2 = Frame(fenetre, bg='#777777')

bouBleua = Button(zone2, text="RUN", fg="white", bg="#BBBB55", command = boutonFourreTout)

bouBleub = Button(zone2, text="RUN", fg="white", bg='#BBBB77', command = boutonFourreTout)

bouBleuc = Button(zone2, text="RUN", fg="white", bg='#BBBB99', command = boutonFourreTout)


bouNoir = Button(fenetre, text="QUIT", fg="white", bg="black", command = boutonFourreTout)


bouRouge.pack(fill=X, ipady=10, padx=10,pady=10)

bouVert.pack(fill=X, ipady=20, padx=10,pady=10)


zone2.pack(fill=Y, padx=10,pady=10)

bouBleua.pack(side=LEFT, fill=Y, ipady=30, padx=10,pady=10)

bouBleub.pack(side=LEFT, fill=Y, ipady=30, padx=10,pady=10)

bouBleuc.pack(side=LEFT, fill=Y, ipady=30, padx=10,pady=10)


bouNoir.pack(fill=X, ipady=60, padx=10,pady=10)


fenetre.mainloop()

13° Tester ce programme pour voir le peu de difficulté à créer une frame/cadre. Il s'agit vraiment de presque créer une fenêtre dans la fenêtre principale et d'y rattacher des widgets, ici les boutons bouBleua, bouBleub et bouBleuc.

4 boutons

Il reste encore énormément de choses à dire ou à faire mais il faut vous documenter si vous voulez aller plus loin dans cette direction. Une recherche sur "python tkinter" plus la chose que vous voulez afficher porte habituellement ses fruits.

Il nous reste encore à voir les insertions d'images classiques (sans traitement), les canvas pour traçer des dessins et la gestion des événements sur votre interface (souris, touches ...)

Et nous finirons enfin à réaliser notre première animation et notre premier jeu.

8 - La méthode place

Il reste encore une méthode permettant de placer les widgets : la méthode place.

Commençons par créer un widget que nous allons voir dans la partie suivante : le Canvas.

Exemple :

monCanvas = Canvas(fen_princ, width=500, height=500, bg='ivory').

14° Utiliser le code suivant pour créer un Canvas de 500x500 dans une fenêtre de 600x600. On utilisera la méthode pack pour l'afficher dans la fenêtre fen_princ.

#!/usr/bin/env python

# -*- coding: utf-8 -*-

from tkinter import *


fen_princ = Tk()

fen_princ.title("ESSAI AVEC CANVAS")

fen_princ.geometry("600x600")


monCanvas = Canvas(fen_princ, width=500, height=500, bg='ivory')

monCanvas.pack()


fen_princ.mainloop()

4 boutons

Comme vous pouvez le voir, le Canvas n'est pas très bien centré. Nous allons voir une troisième méthode pour placer les widgets, à n'utiliser que lorsqu'ils sont peu nombreux de préférence. La méthode place possède de nombreux arguments, nous n'allons en utiliser que deux : la position x et y du point haut et gauche de votre widget.

Ainsi monCanvas.place(x=100,y=100) va placer le début du Canvas aux coordonnées (100,100).

15° Modifier le code en remplaçant la méthode pack par la méthode place de façon à obtenir l'affichage suivant. Il faudra modifier les valeurs des coordonnées x et y.

4 boutons

Pour rappel, voici les axes de coordonnées :

4 boutons

Si vous voulez décaler le widget vers la droite, il faut donc imposer une coordonnée x de plus en plus grande.

Si vous voulez décaler le widget vers le bas, il faut également imposer une coordonnée y de plus en plus grande.

Voilà, nous allons maintenant réutiliser ces méthodes dans toutes les autres activités. Il faudra choisir la méthode la plus adaptée avec votre projet :