trouver un expert Python
Python possède de nombreux frameworks GUI, mais Tkinter est le seul framework intégré à la bibliothèque standard Python. Tkinter a plusieurs atouts. Ses multiplateforme, de sorte que le même code fonctionne sous Windows, macOS et Linux. Les éléments visuels sont rendus à l'aide d'éléments du système d'exploitation natif, de sorte que les applications créées avec Tkinter semblent appartenir à la plate-forme sur laquelle elles sont exécutées.
Bien que Tkinter soit considéré comme le cadre de facto de l'interface graphique Python, ce n'est pas sans critique. Une critique notable est que les interfaces graphiques construites avec Tkinter semblent obsolètes. Si vous voulez une interface moderne et brillante, alors Tkinter n'est peut-être pas ce que vous recherchez.
Cependant, Tkinter est léger et relativement indolore à utiliser par rapport aux autres frameworks. Cela en fait un choix incontournable pour la création d'applications GUI en Python, en particulier pour les applications où un reflet moderne n'est pas nécessaire, et la priorité absolue est de créer quelque chose de fonctionnel et multiplateforme rapidement.
Dans ce didacticiel, vous allez apprendre à:
- Commencer avec Tkinter avec une application "Hello, World!"
- Travail avec des widgets, tels que des boutons et des zones de texte
- Contrôle la disposition de votre application avec les gestionnaires de géométrie
- Faire vos applications interactives en associant les clics de bouton aux fonctions Python
Une fois que vous avez maîtrisé ces compétences en travaillant à travers les exercices à la fin de chaque section, vous allez tout lier ensemble en créant deux applications. Le premier est un convertisseur de température et le second est un éditeur de texte. Il est temps de plonger et de voir comment créer une application avec Tkinter!
Remarque: Ce tutoriel est adapté du chapitre "Interfaces utilisateur graphiques" de Bases de Python: une introduction pratique à Python 3.
Le livre utilise l'éditeur IDLE intégré de Python pour créer et modifier des fichiers Python et interagir avec le shell Python. Dans ce didacticiel, les références à IDLE ont été supprimées au profit d'un langage plus général.
La majeure partie du contenu de ce didacticiel n'a pas été modifiée et vous ne devriez rencontrer aucun problème lors de l'exécution de l'exemple de code à partir de l'éditeur et de l'environnement de votre choix.
Bonus gratuit: 5 réflexions sur la maîtrise de Python, un cours gratuit pour les développeurs Python qui vous montre la feuille de route et l'état d'esprit dont vous aurez besoin pour faire passer vos compétences Python au niveau supérieur.
Construire votre première application GUI Python avec Tkinter
L'élément fondamental d'une interface graphique Tkinter est le fenêtre. Les fenêtres sont les conteneurs dans lesquels vivent tous les autres éléments de l'interface graphique. Ces autres éléments de l'interface graphique, tels que les zones de texte, les étiquettes et les boutons, sont appelés widgets. Les widgets sont contenus à l'intérieur des fenêtres.
Créez d'abord une fenêtre contenant un seul widget. Démarrez une nouvelle session shell Python et suivez-la!
Remarque: Les exemples de code de ce didacticiel ont tous été testés sur Windows, macOS et Ubuntu Linux 18.04 avec les versions Python 3.6, 3.7 et 3.8.
Si vous avez installé Python avec les programmes d'installation officiels disponibles pour Windows et macOS à partir de python.org, vous ne devriez avoir aucun problème à exécuter l'exemple de code. Vous pouvez ignorer le reste de cette note en toute sécurité et poursuivre le didacticiel!
Si vous n'avez pas installé Python avec les programmes d'installation officiels ou s'il n'y a pas de distribution officielle pour votre système, voici quelques conseils pour vous mettre en route.
Python sur macOS avec Homebrew:
La distribution Python pour macOS disponible sur Homebrew n'est pas fournie avec la dépendance Tcl / Tk Tkinter. La version système par défaut est utilisée à la place. Cette version peut être obsolète et vous empêcher d'importer le module Python GUI Tkinter. Pour éviter ce problème, utilisez le programme d'installation officiel de macOS.
Ubuntu Linux 16.04:
La dernière version de Python disponible dans le référentiel Univers Ubuntu Linux 16.04 est 3.5. Vous pouvez installer la dernière version avec le PPA Deadsnakes. Voici les commandes pour configurer le PPA et télécharger la dernière version de Python avec la bonne version Tcl / Tk:
$ sudo add-apt-repository ppa: deadsnakes / ppa
$ mise à jour sudo apt-get
$ sudo apt-get install python3.8 python3-tk
Les deux premières commandes ajoutent le PPA deadsnakes à la liste des référentiels de votre système, et la dernière commande installe Python 3.8 et le module Python GUI Tkinter.
Ubuntu Linux 18.04:
Vous pouvez installer la dernière version de Python avec la bonne version Tcl / Tk à partir du référentiel Universe avec la commande suivante:
$ sudo apt-get install python3.8 python3-tk
Cela installe Python 3.8, ainsi que le module Python GUI Tkinter.
Autres saveurs Linux:
Si vous ne parvenez pas à obtenir une installation Python fonctionnelle sur votre version de Linux, vous pouvez créer Python avec la bonne version de Tcl / Tk à partir du code source. Pour une procédure pas à pas de ce processus, consultez le Guide d'installation et de configuration de Python 3.
Avec votre shell Python ouvert, la première chose que vous devez faire est d'importer le module Python GUI Tkinter:
>>> importation tkinter comme tk
UNE fenêtre est une instance de Tkinter Tk
classe. Allez-y, créez une nouvelle fenêtre et affectez-la à la variable fenêtre
:
Lorsque vous exécutez le code ci-dessus, une nouvelle fenêtre apparaît sur votre écran. L'aspect dépend de votre système d'exploitation:
Dans le reste de ce didacticiel, vous verrez des captures d'écran de Windows.
Ajout d'un widget
Maintenant que vous avez une fenêtre, vous pouvez ajouter un widget. Utilisez le tk.Label
pour ajouter du texte à une fenêtre. Créer un Étiquette
widget avec le texte "Bonjour, Tkinter"
et l'affecter à une variable appelée salutation
:
>>> salutation = tk.Étiquette(texte="Bonjour, Tkinter")
La fenêtre que vous avez créée précédemment ne change pas. Vous venez de créer un Étiquette
widget, mais vous ne l'avez pas encore ajouté à la fenêtre. Il existe plusieurs façons d'ajouter des widgets à une fenêtre. Pour le moment, vous pouvez utiliser le Étiquette
widget .pack()
méthode:
La fenêtre ressemble maintenant à ceci:
Quand vous .pack()
un widget dans une fenêtre, Tkinter dimensionne la fenêtre aussi petite que possible tout en englobant pleinement le widget. Exécutez maintenant ce qui suit:
Rien ne semble se produire, mais notez qu'une nouvelle invite n'apparaît pas dans le shell.
window.mainloop ()
dit à Python d'exécuter le Tkinter boucle d'événement. Cette méthode écoute les événements, tels que les clics sur les boutons ou les touches, et blocs tout code qui vient après son exécution jusqu'à la fermeture de la fenêtre appelée. Allez-y et fermez la fenêtre que vous avez créée, et vous verrez une nouvelle invite s'afficher dans le shell.
Avertissement: Lorsque vous travaillez avec Tkinter à partir d'un Python REPL, les mises à jour des fenêtres sont appliquées lors de l'exécution de chaque ligne. C'est pas le cas quand un programme Tkinter est exécuté à partir d'un fichier Python!
Si vous n'incluez pas window.mainloop ()
à la fin d'un programme dans un fichier Python, alors l'application Tkinter ne s'exécutera jamais et rien ne s'affichera.
La création d'une fenêtre avec Tkinter ne prend que quelques lignes de code. Mais les fenêtres vierges ne sont pas très utiles! Dans la section suivante, vous découvrirez certains des widgets disponibles dans Tkinter et comment les personnaliser pour répondre aux besoins de votre application.
Vérifie ta compréhension
Développez les blocs de code ci-dessous pour vérifier votre compréhension:
Écrire un script Python complet qui crée une fenêtre Tkinter avec le texte "Des roches en python!"
.
La fenêtre devrait ressembler à ceci:
Essayez cet exercice maintenant.
Vous pouvez développer le bloc de code ci-dessous pour voir une solution:
Voici une solution possible:
importation tkinter comme tk
fenêtre = tk.Tk()
étiquette = tk.Étiquette(texte="Des roches en python!")
étiquette.pack()
fenêtre.boucle principale()
Gardez à l'esprit que votre code peut être différent.
Lorsque vous êtes prêt, vous pouvez passer à la section suivante.
Les widgets sont le pain et le beurre du framework Python GUI Tkinter. Ce sont les éléments par lesquels les utilisateurs interagissent avec votre programme. Chaque widget dans Tkinter est défini par une classe. Voici quelques-uns des widgets disponibles:
Classe de widget | La description |
---|---|
Étiquette |
Un widget utilisé pour afficher du texte à l'écran |
Bouton |
Un bouton qui peut contenir du texte et peut effectuer une action lorsque vous cliquez dessus |
Entrée |
Un widget de saisie de texte qui ne permet qu'une seule ligne de texte |
Texte |
Un widget de saisie de texte qui permet la saisie de texte multiligne |
Cadre |
Une région rectangulaire utilisée pour regrouper des widgets associés ou fournir un remplissage entre les widgets |
Vous verrez comment travailler avec chacun d'eux dans les sections suivantes. Notez que Tkinter a beaucoup plus de widgets que ceux répertoriés ici. Pour une liste complète, consultez les widgets de base et plus de widgets dans le didacticiel TkDocs. Pour l'instant, regardez de plus près le Étiquette
widget.
Affichage de texte et d'images avec Étiquette
Widgets
Étiquette
les widgets sont utilisés pour afficher du texte ou des images. Le texte affiché par un Étiquette
le widget ne peut pas être modifié par l'utilisateur. C'est uniquement à des fins d'affichage. Comme vous l'avez vu dans l'exemple au début de ce didacticiel, vous pouvez créer un Étiquette
widget en instanciant le Étiquette
classe et passer une chaîne à la texte
paramètre:
étiquette = tk.Étiquette(texte="Bonjour, Tkinter")
Étiquette
les widgets affichent le texte avec la couleur de texte système par défaut et la couleur d'arrière-plan du texte système par défaut. Ce sont généralement du noir et du blanc, respectivement, mais vous pouvez voir des couleurs différentes si vous avez modifié ces paramètres dans votre système d'exploitation.
Vous pouvez contrôler Étiquette
couleurs du texte et de l'arrière-plan premier plan
et Contexte
paramètres:
étiquette = tk.Étiquette(
texte="Bonjour, Tkinter",
premier plan="blanc", # Définissez la couleur du texte sur blanc
Contexte="noir" # Définissez la couleur d'arrière-plan sur noir
)
Il existe de nombreux noms de couleurs valides, notamment:
"rouge"
"Orange"
"Jaune"
"vert"
"bleu"
"violet"
De nombreux noms de couleurs HTML fonctionnent avec Tkinter. Un tableau avec la plupart des noms de couleurs valides est disponible ici. Pour une référence complète, y compris les couleurs système spécifiques à macOS et Windows qui sont contrôlées par le thème système actuel, consultez la page de manuel des couleurs.
Vous pouvez également spécifier une couleur à l'aide de valeurs RVB hexadécimales:
étiquette = tk.Étiquette(texte="Bonjour, Tkinter", Contexte="# 34A2FE")
Cela donne à l'arrière-plan de l'étiquette une belle couleur bleu clair. Les valeurs RVB hexadécimales sont plus cryptiques que les couleurs nommées, mais elles sont également plus flexibles. Heureusement, il existe des outils qui permettent d'obtenir des codes de couleur hexadécimaux relativement indolores.
Si vous n’avez pas envie de taper premier plan
et Contexte
tout le temps, alors vous pouvez utiliser le raccourci fg
et bg
paramètres pour définir les couleurs de premier plan et d'arrière-plan:
étiquette = tk.Étiquette(texte="Bonjour, Tkinter", fg="blanc", bg="noir")
Vous pouvez également contrôler la largeur et la hauteur d'une étiquette avec le largeur
et la taille
paramètres:
étiquette = tk.Étiquette(
texte="Bonjour, Tkinter",
fg="blanc",
bg="noir",
largeur=dix,
la taille=dix
)
Voici à quoi ressemble cette étiquette dans une fenêtre:
Il peut sembler étrange que l’étiquette dans la fenêtre ne soit pas un événement carré bien que la largeur et la hauteur soient toutes deux définies sur dix
. En effet, la largeur et la hauteur sont mesurées en unités de texte. Une unité de texte horizontale est déterminée par la largeur du caractère "0"
ou le nombre zéro, dans la police système par défaut. De même, une unité de texte verticale est déterminée par la hauteur du caractère "0"
.
Remarque: Tkinter utilise des unités de texte pour les mesures de largeur et de hauteur, au lieu de quelque chose comme des pouces, des centimètres ou des pixels, pour assurer un comportement cohérent de l'application sur toutes les plateformes.
La mesure des unités par la largeur d'un caractère signifie que la taille d'un widget est relative à la police par défaut sur la machine d'un utilisateur. Cela garantit que le texte tient correctement dans les étiquettes et les boutons, quel que soit l'endroit où l'application s'exécute.
Les étiquettes sont idéales pour afficher du texte, mais elles ne vous aident pas à obtenir la contribution d'un utilisateur. Les trois widgets suivants que vous examinerez sont tous utilisés pour obtenir les commentaires des utilisateurs.
Affichage des boutons cliquables avec Bouton
Widgets
Bouton
les widgets sont utilisés pour afficher boutons cliquables. Ils peuvent être configurés pour appeler une fonction chaque fois qu’on clique dessus. Vous découvrirez comment appeler des fonctions à partir de clics sur les boutons dans la section suivante. Pour l'instant, regardez comment créer et styliser un Bouton
.
Il existe de nombreuses similitudes entre Bouton
et Étiquette
widgets. À bien des égards, un Bouton
est juste un Étiquette
que vous pouvez cliquer! Les mêmes arguments de mots clés que vous utilisez pour créer et styliser un Étiquette
travaillera avec Bouton
widgets. Par exemple, le code suivant crée un Bouton
avec un fond bleu et un texte jaune. Il définit également la hauteur et la largeur sur dix
et 5
unités de texte, respectivement:
bouton = tk.Bouton(
texte="Cliquez-moi!",
largeur=25,
la taille=5,
bg="bleu",
fg="Jaune",
)
Voici à quoi ressemble le bouton dans une fenêtre:
Assez astucieux! Les deux widgets suivants que vous verrez sont utilisés pour collecter la saisie de texte d'un utilisateur.
Obtenir la saisie des utilisateurs avec Entrée
Widgets
Lorsque vous avez besoin d'obtenir un peu de texte d'un utilisateur, comme un nom ou une adresse e-mail, utilisez un Entrée
widget. Ils affichent un petite zone de texte dans lequel l'utilisateur peut taper du texte. Créer et styliser un Entrée
widget fonctionne à peu près exactement comme Étiquette
et Bouton
widgets. Par exemple, le code suivant crée un widget avec un fond bleu, du texte jaune et une largeur de 50
unités de texte:
entrée = tk.Entrée(fg="Jaune", bg="bleu", largeur=50)
La partie intéressante de Entrée
cependant, les widgets ne sont pas comment les styliser. C'est comment les utiliser pour obtenir la contribution d'un utilisateur. Vous pouvez effectuer trois opérations principales avec Entrée
widgets:
- Récupération de texte avec
.avoir()
- Suppression de texte avec
.supprimer()
- Insérer du texte avec
.insérer()
La meilleure façon de comprendre Entrée
widgets consiste à en créer un et à interagir avec lui. Ouvrez un shell Python et suivez les exemples de cette section. Tout d'abord, importez tkinter
et créez une nouvelle fenêtre:
>>> importation tkinter comme tk
>>> fenêtre = tk.Tk()
Créez maintenant un Étiquette
Et un Entrée
widget:
>>> étiquette = tk.Étiquette(texte="Nom")
>>> entrée = tk.Entrée()
le Étiquette
décrit quel type de texte doit aller dans le Entrée
widget. Il n'applique aucune sorte d'exigences sur le Entrée
, mais il indique à l'utilisateur ce que votre programme attend d'eux. Tu dois .pack()
les widgets dans la fenêtre pour qu'ils soient visibles:
>>> étiquette.pack()
>>> entrée.pack()
Voici à quoi cela ressemble:
Notez que Tkinter centre automatiquement le Étiquette
au dessus de Entrée
widget dans la fenêtre. C'est une caractéristique de .pack()
, dont vous découvrirez plus dans les sections suivantes.
Cliquez à l'intérieur du Entrée
widget avec votre souris et tapez "Real Python"
:
Maintenant, vous avez un texte entré dans le Entrée
widget, mais ce texte n'a pas encore été envoyé à votre programme. Vous pouvez utiliser .avoir()
pour récupérer le texte et l'affecter à une variable appelée Nom
:
>>> Nom = entrée.avoir()
>>> Nom
«Real Python»
Vous pouvez .supprimer()
texte aussi. Cette méthode prend un argument entier qui indique à Python le caractère à supprimer. Par exemple, le bloc de code ci-dessous montre comment .delete (0)
supprime le premier caractère de la Entrée
:
Le texte restant dans le widget est maintenant "eal python"
:
Notez que, tout comme les objets chaîne Python, le texte dans un Entrée
le widget est indexé en commençant par 0
.
Si vous devez supprimer plusieurs caractères d'un Entrée
, puis passez un deuxième argument entier à .supprimer()
indiquant l'index du caractère où la suppression doit s'arrêter. Par exemple, le code suivant supprime les quatre premières lettres de la Entrée
:
>>> entrée.supprimer(0, 4)
Le texte restant se lit maintenant "Python"
:
Entry.delete ()
fonctionne comme le tranchage de cordes. Le premier argument détermine l'indice de départ et la suppression se poursuit jusqu'à mais non compris l'index est passé comme deuxième argument. Utilisez la constante spéciale tk.END
pour le deuxième argument de .supprimer()
pour supprimer tout le texte d'un Entrée
:
>>> entrée.supprimer(0, tk.FIN)
Vous verrez maintenant une zone de texte vide:
À l'autre extrémité du spectre, vous pouvez également .insérer()
texte dans un Entrée
widget:
>>> entrée.insérer(0, "Python")
La fenêtre ressemble maintenant à ceci:
Le premier argument raconte .insérer()
où insérer le texte. S'il n'y a pas de texte dans le Entrée
, le nouveau texte sera toujours inséré au début du widget, quelle que soit la valeur que vous passerez comme premier argument. Par exemple, appeler .insérer()
avec 100
comme premier argument au lieu de 0
, comme vous l'avez fait ci-dessus, aurait généré la même sortie.
Si un Entrée
contient déjà du texte, alors .insérer()
va insérer le nouveau texte à la position spécifiée et déplacer tout le texte existant vers la droite:
>>> entrée.insérer(0, "Réel ")
Le texte du widget se lit maintenant "Real Python"
:
Entrée
les widgets sont parfaits pour capturer de petites quantités de texte d'un utilisateur, mais comme ils ne sont affichés que sur une seule ligne, ils ne sont pas idéaux pour rassembler de grandes quantités de texte. C'est là que Texte
les widgets arrivent!
Obtenir une entrée utilisateur multiligne avec Texte
Widgets
Texte
les widgets sont utilisés pour saisir du texte, tout comme Entrée
widgets. La différence est que Texte
les widgets peuvent contenir plusieurs lignes de texte. Avec un Texte
widget, un utilisateur peut saisir un paragraphe entier ou même plusieurs pages de texte! Juste comme Entrée
widgets, vous pouvez effectuer trois opérations principales avec Texte
widgets:
- Récupérer du texte avec
.avoir()
- Supprimer le texte avec
.supprimer()
- Insérer du texte avec
.insérer()
Bien que les noms de méthode soient les mêmes que Entrée
méthodes, ils fonctionnent un peu différemment. Il est temps de se salir les mains en créant un Texte
widget et voir tout ce qu'il peut faire.
Remarque: Avez-vous toujours la fenêtre de la section précédente ouverte?
Si c'est le cas, vous pouvez le fermer en exécutant ce qui suit:
Vous pouvez également le fermer manuellement en cliquant sur le Fermer bouton.
Dans votre shell Python, créez une nouvelle fenêtre vierge et .pack()
une Texte()
widget dedans:
>>> fenêtre = tk.Tk()
>>> zone de texte = tk.Texte()
>>> zone de texte.pack()
Les zones de texte sont beaucoup plus grandes que Entrée
widgets par défaut. Voici à quoi ressemble la fenêtre créée ci-dessus:
Cliquez n'importe où dans la fenêtre pour activer la zone de texte. Tapez le mot "Bonjour"
. Puis appuyez Entrer et tapez "Monde"
sur la deuxième ligne. La fenêtre devrait maintenant ressembler à ceci:
Juste comme Entrée
widgets, vous pouvez récupérer le texte Texte
widget utilisant .avoir()
. Cependant, appeler .avoir()
sans argument ne renvoie pas le texte intégral dans la zone de texte comme il le fait pour Entrée
widgets. Cela soulève une exception:
>>> zone de texte.avoir()
Traceback (dernier appel le plus récent):
Fichier "" , ligne 1, dans
zone de texte.avoir()
Erreur-type: get () manque 1 argument positionnel requis: 'index1'
Text.get ()
requis au moins un argument. Appel .avoir()
avec un seul index renvoie un seul caractère. Pour récupérer plusieurs caractères, vous devez passer un index de départ Et un index de fin. Indices en Texte
les widgets fonctionnent différemment de Entrée
widgets. Puisque Texte
les widgets peuvent avoir plusieurs lignes de texte, un index doit contenir deux informations:
- Le numéro de ligne d'un personnage
- La position d'un personnage sur cette ligne
Les numéros de ligne commencent par 1
et la position des caractères commence par 0
. Pour créer un index, vous créez une chaîne du formulaire "
, remplacement
avec le numéro de ligne et
avec le numéro de caractère. Par exemple, "1.0"
représente le premier caractère sur la première ligne, et "2.3"
représente le quatrième caractère sur la deuxième ligne.
Utilisez l'index "1.0"
pour obtenir la première lettre de la zone de texte que vous avez créée précédemment:
>>> zone de texte.avoir("1.0")
«H»
Il y a cinq lettres dans le mot "Bonjour"
et le nombre de caractères de o
est 4
, puisque les numéros de caractères commencent à partir de 0
et le mot "Bonjour"
commence à la première position dans la zone de texte. Tout comme les tranches de chaîne Python, afin d'obtenir le mot entier "Bonjour"
dans la zone de texte, l'index de fin doit être un de plus que l'index du dernier caractère à lire.
Donc, pour avoir le mot "Bonjour"
dans la zone de texte, utilisez "1.0"
pour le premier indice et "1,5"
pour le deuxième indice:
>>> zone de texte.avoir("1.0", "1,5")
'Bonjour'
Pour avoir le mot "Monde"
sur la deuxième ligne de la zone de texte, remplacez les numéros de ligne de chaque index par 2
:
>>> zone de texte.avoir("2.0", "2,5")
'Monde'
Pour obtenir tout le texte dans une zone de texte, définissez l'index de départ dans "1.0"
et utilisez le spécial tk.END
constante pour le deuxième indice:
>>> zone de texte.avoir("1.0", tk.FIN)
«Bonjour nMonde n»
Notez que le texte renvoyé par .avoir()
inclut tous les caractères de nouvelle ligne. Vous pouvez également voir dans cet exemple que chaque ligne d'un Texte
widget a un caractère de nouvelle ligne à la fin, y compris la dernière ligne de texte dans la zone de texte.
.supprimer()
est utilisé pour supprimer des caractères d'une zone de texte. Cela fonctionne comme .supprimer()
pour Entrée
widgets. Il existe deux façons d'utiliser .supprimer()
:
- Avec un seul argument
- Avec deux arguments
En utilisant la version à argument unique, vous passez à .supprimer()
l'index d'un seul caractère à supprimer. Par exemple, ce qui suit supprime le premier caractère H
dans la zone de texte:
>>> zone de texte.supprimer("1.0")
La première ligne de texte de la fenêtre indique maintenant "bonjour"
:
Avec la version à deux arguments, vous passez deux index pour supprimer une plage de caractères commençant au premier index et jusqu'au, mais sans inclure, le deuxième index.
Par exemple, pour supprimer le reste "bonjour"
sur la première ligne de la zone de texte, utilisez les indices "1.0"
et "1,4"
:
>>> zone de texte.supprimer("1.0", "1,4")
Notez que le texte a disparu de la première ligne. Cela laisse une ligne vide suivie du mot Monde
sur la deuxième ligne:
Même si vous ne le voyez pas, il y a toujours un personnage sur la première ligne. C’est un caractère de nouvelle ligne! Vous pouvez le vérifier en utilisant .avoir()
:
>>> zone de texte.avoir("1.0")
' n'
Si vous supprimez ce caractère, le reste du contenu de la zone de texte se déplacera d'une ligne vers le haut:
>>> zone de texte.supprimer("1.0")
Maintenant, "Monde"
est sur la première ligne de la zone de texte:
Essayez d'effacer le reste du texte dans la zone de texte. Ensemble "1.0"
comme index de départ et utiliser tk.END
pour le deuxième indice:
>>> zone de texte.supprimer("1.0", tk.FIN)
La zone de texte est maintenant vide:
Vous pouvez insérer du texte dans une zone de texte en utilisant .insérer()
:
>>> zone de texte.insérer("1.0", "Bonjour")
Cela insère le mot "Bonjour"
au début de la zone de texte, en utilisant le même "
format utilisé par .avoir()
pour spécifier la position d'insertion:
Découvrez ce qui se passe si vous essayez d'insérer le mot "Monde"
sur la deuxième ligne:
>>> zone de texte.insérer("2.0", "Monde")
Au lieu d'insérer le texte sur la deuxième ligne, le texte est inséré à la fin de la première ligne:
Si vous souhaitez insérer du texte sur une nouvelle ligne, vous devez insérer manuellement un caractère de nouvelle ligne dans la chaîne insérée:
>>> zone de texte.insérer("2.0", " nMonde")
Maintenant "Monde"
est sur la deuxième ligne de la zone de texte:
.insérer()
fera l'une des deux choses suivantes:
- Insérer du texte à la position spécifiée s'il y a déjà du texte à cette position ou après.
- Ajouter du texte à la ligne spécifiée si le nombre de caractères est supérieur à l'index du dernier caractère de la zone de texte.
Il est généralement impossible d’essayer de garder une trace de l’index du dernier caractère. La meilleure façon d'insérer du texte à la fin d'un Texte
widget est de passer tk.END
au premier paramètre de .insérer()
:
zone de texte.insérer(tk.FIN, "Mettez-moi à la fin!")
N'oubliez pas d'inclure le caractère de nouvelle ligne ( n
) au début du texte si vous souhaitez le mettre sur une nouvelle ligne:
zone de texte.insérer(tk.FIN, " nMettez-moi sur une nouvelle ligne! ")
Étiquette
, Bouton
, Entrée
, et Texte
les widgets ne sont que quelques-uns des widgets disponibles dans Tkinter. Il en existe plusieurs autres, notamment des widgets pour les cases à cocher, les boutons radio, les barres de défilement et les barres de progression. Pour plus d'informations sur tous les widgets disponibles, consultez la liste des widgets supplémentaires dans la section Ressources supplémentaires.
Attribuer des widgets aux cadres avec Cadre
Widgets
Dans ce didacticiel, vous allez travailler avec seulement cinq widgets. Ce sont les quatre que vous avez vus jusqu'à présent, plus les Cadre
widget. Cadre
les widgets sont importants pour organiser la mise en page de vos widgets dans une application.
Avant d'entrer dans les détails de la présentation visuelle de vos widgets, regardez de plus près comment Cadre
les widgets fonctionnent et comment vous pouvez leur attribuer d'autres widgets. Le script suivant crée un espace Cadre
widget et l'assigne à la fenêtre principale de l'application:
importation tkinter comme tk
fenêtre = tk.Tk()
Cadre = tk.Cadre()
Cadre.pack()
fenêtre.boucle principale()
frame.pack ()
emballe le cadre dans la fenêtre de sorte que la fenêtre se taille aussi petite que possible pour englober le cadre. Lorsque vous exécutez le script ci-dessus, vous obtenez une sortie vraiment inintéressante:
Un vide Cadre
le widget est pratiquement invisible. Les cadres sont mieux considérés comme conteneurs pour d'autres widgets. Vous pouvez attribuer un widget à un cadre en définissant la Maître
attribut:
Cadre = tk.Cadre()
étiquette = tk.Étiquette(Maître=Cadre)
Pour comprendre comment cela fonctionne, écrivez un script qui crée deux Cadre
widgets appelés frame_a
et frame_b
. Dans ce script, frame_a
contient une étiquette avec le texte "Je suis dans le cadre A"
, et frame_b
contient l'étiquette "Je suis dans le cadre B"
. Voici une façon de procéder:
importation tkinter comme tk
fenêtre = tk.Tk()
frame_a = tk.Cadre()
frame_b = tk.Cadre()
label_a = tk.Étiquette(Maître=frame_a, texte="Je suis dans le cadre A")
label_a.pack()
label_b = tk.Étiquette(Maître=frame_b, texte="Je suis dans le cadre B")
label_b.pack()
frame_a.pack()
frame_b.pack()
fenêtre.boucle principale()
Notez que frame_a
est emballé dans la fenêtre avant frame_b
. La fenêtre qui s'ouvre montre l'étiquette dans frame_a
au-dessus de l'étiquette frame_b
:
Maintenant, voyez ce qui se passe lorsque vous échangez l'ordre des frame_a.pack ()
et frame_b.pack ()
:
importation tkinter comme tk
fenêtre = tk.Tk()
frame_a = tk.Cadre()
label_a = tk.Étiquette(Maître=frame_a, texte="Je suis dans le cadre A")
label_a.pack()
frame_b = tk.Cadre()
label_b = tk.Étiquette(Maître=frame_b, texte="Je suis dans le cadre B")
label_b.pack()
# Échangez l'ordre de `frame_a` et` frame_b`
frame_b.pack()
frame_a.pack()
fenêtre.boucle principale()
La sortie ressemble à ceci:
Maintenant label_b
est au top. Puisque label_b
est affecté à frame_b
, il se déplace partout frame_b
est positionné.
Les quatre types de widgets dont vous avez entendu parler—Étiquette
, Bouton
, Entrée
, et Texte
-avoir un Maître
attribut défini lorsque vous les instanciez. De cette façon, vous pouvez contrôler Cadre
un widget est affecté à. Cadre
les widgets sont parfaits pour organiser d'autres widgets de manière logique. Les widgets associés peuvent être affectés au même cadre de sorte que, si le cadre est déplacé dans la fenêtre, les widgets associés restent ensemble.
Outre le regroupement logique de vos widgets, Cadre
les widgets peuvent ajouter une petite touche présentation visuelle de votre candidature. Lisez la suite pour voir comment créer diverses bordures pour Cadre
widgets.
Réglage de l'apparence du cadre avec des reliefs
Cadre
les widgets peuvent être configurés avec un le soulagement
attribut qui crée une bordure autour du cadre. Vous pouvez définir le soulagement
être l'une des valeurs suivantes:
tk.FLAT
: N'a aucun effet de bordure (la valeur par défaut).tk.SUNKEN
: Crée un effet coulé.tk.RAISED
: Crée un effet surélevé.tk.GROOVE
: Crée un effet de bordure rainurée.tk.RIDGE
: Crée un effet strié.
Pour appliquer l'effet de bordure, vous devez définir largeur de la bordure
attribuer à une valeur supérieure à 1
. Cet attribut ajuste la largeur de la bordure en pixels. La meilleure façon d'avoir une idée de l'apparence de chaque effet est de les voir par vous-même. Voici un script qui en contient cinq Cadre
widgets dans une fenêtre, chacun avec une valeur différente pour le le soulagement
argument:
1 importation tkinter comme tk
2
3 border_effects =
4 "plat": tk.PLAT,
5 "creux": tk.CREUX,
6 "élevé": tk.SOULEVÉ,
sept "rainure": tk.RAINURE,
8 "crête": tk.CRÊTE,
9
dix
11 fenêtre = tk.Tk()
12
13 pour relief_name, le soulagement dans border_effects.articles():
14 Cadre = tk.Cadre(Maître=fenêtre, le soulagement=le soulagement, largeur de la bordure=5)
15 Cadre.pack(côté=tk.LA GAUCHE)
16 étiquette = tk.Étiquette(Maître=Cadre, texte=relief_name)
17 étiquette.pack()
18
19 fenêtre.boucle principale()
Voici une ventilation de ce script:
-
Lignes 3 à 9 créer un dictionnaire dont les clés sont les noms des différents effets de relief disponibles dans Tkinter. Les valeurs sont les objets Tkinter correspondants. Ce dictionnaire est affecté au
border_effects
variable. -
Ligne 13 commence un
pour
boucle pour parcourir chaque élément duborder_effects
dictionnaire. -
Ligne 14 crée un nouveau
Cadre
widget et l'assigne à lafenêtre
objet. lele soulagement
attribut est défini sur le relief correspondant dans leborder_effects
dictionnaire et lefrontière
l'attribut est défini sur5
pour que l'effet soit visible. -
Ligne 15 emballe le
Cadre
dans la fenêtre en utilisant.pack()
. lecôté
L'argument mot-clé indique à Tkinter dans quelle directionCadre
objets. Vous en saurez plus sur son fonctionnement dans la section suivante. -
Lignes 16 et 17 créer un
Étiquette
widget pour afficher le nom du relief et le placer dans leCadre
objet que vous venez de créer.
La fenêtre produite par le script ci-dessus ressemble à ceci:
Dans cette image, vous pouvez voir les effets suivants:
tk.FLAT
crée un cadre qui semble plat.tk.SUNKEN
ajoute une bordure qui donne au cadre l'apparence d'être enfoncé dans la fenêtre.tk.RAISED
donne au cadre une bordure qui le fait sembler dépasser de l'écran.tk.GROOVE
ajoute une bordure qui apparaît comme une rainure enfoncée autour d'un cadre par ailleurs plat.tk.RIDGE
donne l'apparence d'une lèvre surélevée autour du bord du cadre.
Ces effets donnent à votre application Python GUI Tkinter un attrait visuel.
Comprendre les conventions de dénomination des widgets
Lorsque vous créez un widget, vous pouvez lui donner le nom de votre choix, à condition identifiant Python valide. C'est généralement une bonne idée d'inclure le nom de la classe de widget dans le nom de variable que vous attribuez à l'instance de widget. Par exemple, si un Étiquette
widget est utilisé pour afficher le nom d'un utilisateur, vous pouvez alors nommer le widget label_user_name
. Un Entrée
Le widget utilisé pour collecter l'âge d'un utilisateur peut être appelé entry_age
.
Lorsque vous incluez le nom de classe de widget dans le nom de variable, vous vous aidez (ainsi que toute autre personne qui a besoin de lire votre code) à comprendre à quel type de widget le nom de variable fait référence. Cependant, l'utilisation du nom complet de la classe de widget peut conduire à des noms de variable longs, vous pouvez donc adopter un raccourci pour faire référence à chaque type de widget. Pour le reste de ce didacticiel, vous utiliserez les préfixes abrégés suivants pour nommer les widgets:
Classe de widget | Préfixe de nom de variable | Exemple |
---|---|---|
Étiquette |
lbl |
lbl_name |
Bouton |
btn |
btn_submit |
Entrée |
ent |
ent_age |
Texte |
SMS |
txt_notes |
Cadre |
frm |
frm_address |
Dans cette section, vous avez appris à créer une fenêtre, à utiliser des widgets et à utiliser des cadres. À ce stade, vous pouvez créer des fenêtres simples qui affichent des messages, mais vous devez encore créer une application complète. Dans la section suivante, vous apprendrez à contrôler la disposition de vos applications à l'aide des puissants gestionnaires de géométrie de Tkinter.
Vérifie ta compréhension
Développez le bloc de code ci-dessous pour un exercice afin de vérifier votre compréhension:
Écrivez un script complet qui affiche un Entrée
widget de 40 unités de texte de large avec un fond blanc et du texte noir. Utilisation .insérer()
pour afficher du texte dans le widget qui lit "Quel est votre nom?"
.
La fenêtre de sortie devrait ressembler à ceci:
Essayez cet exercice maintenant.
Vous pouvez développer le bloc de code ci-dessous pour voir une solution:
Il existe plusieurs façons de résoudre cet exercice. Voici une solution qui utilise le bg
et fg
paramètres pour définir la Entrée
couleurs d'arrière-plan et de premier plan du widget:
importation tkinter comme tk
fenêtre = tk.Tk()
entrée = tk.Entrée(largeur=40, bg="blanc", fg="noir")
entrée.pack()
entrée.insérer(0, "Quel est votre nom?")
fenêtre.boucle principale()
Cette solution est excellente car elle définit explicitement les couleurs d'arrière-plan et de premier plan pour le Entrée
widget.
Sur la plupart des systèmes, la couleur d'arrière-plan par défaut d'un Entrée
le widget est blanc et la couleur de premier plan par défaut est le noir. So, you might be able to generate the same window with the bg
et fg
parameters left out:
import tkinter comme tk
window = tk.Tk()
entry = tk.Entrée(width=40)
entry.pack()
entry.insert(0, "What is your name?")
window.mainloop()
Keep in mind your code may look different.
When you’re ready, you can move on to the next section.
Controlling Layout With Geometry Managers
Up until now, you’ve been adding widgets to windows and Cadre
widgets using .pack()
, but you haven’t learned what exactly this method does. Let’s clear things up! Application layout in Tkinter is controlled with geometry managers. Tandis que .pack()
is an example of a geometry manager, it isn’t the only one. Tkinter has two others:
Each window and Cadre
in your application can use only one geometry manager. However, different frames can use different geometry managers, even if they’re assigned to a frame or window using another geometry manager. Start by taking a closer look at .pack()
.
le .pack()
Geometry Manager
.pack()
uses a packing algorithm to place widgets in a Cadre
or window in a specified order. For a given widget, the packing algorithm has two primary steps:
- Compute a rectangular area called a parcel that’s just tall (or wide) enough to hold the widget and fills the remaining width (or height) in the window with blank space.
- Center the widget in the parcel unless a different location is specified.
.pack()
is powerful, but it can be difficult to visualize. The best way to get a feel for .pack()
is to look at some examples. See what happens when you .pack()
Trois Étiquette
widgets into a Cadre
:
import tkinter comme tk
window = tk.Tk()
frame1 = tk.Cadre(Maître=window, width=100, height=100, bg="red")
frame1.pack()
frame2 = tk.Cadre(Maître=window, width=50, height=50, bg="yellow")
frame2.pack()
frame3 = tk.Cadre(Maître=window, width=25, height=25, bg="blue")
frame3.pack()
window.mainloop()
.pack()
places each Cadre
below the previous one by default, in the order that they’re assigned to the window:
Each Cadre
is placed at the top-most available position. The red Cadre
is placed at the top of the window. Then the yellow Cadre
is placed just below the red one and the blue Cadre
just below the yellow one.
There are three invisible parcels containing each of the three Cadre
widgets. Each parcel is as wide as the window and as tall as the Cadre
that it contains. Since no anchor point was specified when .pack()
was called for each Frame,
they’re all centered inside of their parcels. That’s why each Cadre
is centered in the window.
.pack()
accepts some keyword arguments for more precisely configuring widget placement. For example, you can set the fill
keyword argument to specify in which direction the frames should fill. The options are tk.X
to fill in the horizontal direction, tk.Y
to fill vertically, and tk.BOTH
to fill in both directions. Here’s how you would stack the three frames so that each one fills the whole window horizontally:
import tkinter comme tk
window = tk.Tk()
frame1 = tk.Cadre(Maître=window, height=100, bg="red")
frame1.pack(fill=tk.X)
frame2 = tk.Cadre(Maître=window, height=50, bg="yellow")
frame2.pack(fill=tk.X)
frame3 = tk.Cadre(Maître=window, height=25, bg="blue")
frame3.pack(fill=tk.X)
window.mainloop()
Notice that the width
is not set on any of the Cadre
widgets. width
is no longer necessary because each frame sets .pack()
to fill horizontally, overriding any width you may set.
The window produced by this script looks like this:
One of the nice things about filling the window with .pack()
is that the fill is responsive to window resizing. Try widening the window generated by the previous script to see how this works. As you widen the window, the width of the three Cadre
widgets grow to fill the window:
Notice, though, that the Cadre
widgets don’t expand in the vertical direction.
le côté
keyword argument of .pack()
specifies on which side of the window the widget should be placed. These are the available options:
tk.TOP
tk.BOTTOM
tk.LEFT
tk.RIGHT
If you don’t set côté
, then .pack()
will automatically use tk.TOP
and place new widgets at the top of the window, or at the top-most portion of the window that isn’t already occupied by a widget. For example, the following script places three frames side-by-side from left to right and expands each frame to fill the window vertically:
import tkinter comme tk
window = tk.Tk()
frame1 = tk.Cadre(Maître=window, width=200, height=100, bg="red")
frame1.pack(fill=tk.Oui, côté=tk.LEFT)
frame2 = tk.Cadre(Maître=window, width=100, bg="yellow")
frame2.pack(fill=tk.Oui, côté=tk.LEFT)
frame3 = tk.Cadre(Maître=window, width=50, bg="blue")
frame3.pack(fill=tk.Oui, côté=tk.LEFT)
window.mainloop()
This time, you have to specify the height
keyword argument on at least one of the frames to force the window to have some height.
The resulting window looks like this:
Just like when you set fill=tk.X
to make the frames responsive when you resized the window horizontally, you can set fill=tk.Y
to make the frames responsive when you resize the window vertically:
To make the layout truly responsive, you can set an initial size for your frames using the width
et height
les attributs. Then, set the fill
keyword argument of .pack()
à tk.BOTH
and set the expand
keyword argument to True
:
import tkinter comme tk
window = tk.Tk()
frame1 = tk.Cadre(Maître=window, width=200, height=100, bg="red")
frame1.pack(fill=tk.TOUS LES DEUX, côté=tk.LEFT, expand=True)
frame2 = tk.Cadre(Maître=window, width=100, bg="yellow")
frame2.pack(fill=tk.TOUS LES DEUX, côté=tk.LEFT, expand=True)
frame3 = tk.Cadre(Maître=window, width=50, bg="blue")
frame3.pack(fill=tk.TOUS LES DEUX, côté=tk.LEFT, expand=True)
window.mainloop()
When you run the above script, you’ll see a window that initially looks the same as the one you generated in the previous example. The difference is that now you can resize the window however you want and the frames will expand and fill the window responsively:
Plutôt cool!
le .place()
Geometry Manager
Vous pouvez utiliser .place()
à control the precise location that a widget should occupy in a window or Cadre
. You must provide two keyword arguments, X
et y
, which specify the x- and y-coordinates for the top-left corner of the widget. Tous les deux X
et y
are measured in pixels, not text units.
Keep in mind that the origin (where X
et y
are both 0
) is the top-left corner of the Cadre
or window. So, you can think of the y
argument of .place()
as the number of pixels from the top of the window, and the X
argument as the number of pixels from the left of the window.
Here’s an example of how the .place()
geometry manager works:
1 import tkinter comme tk
2
3 window = tk.Tk()
4
5 frame = tk.Cadre(Maître=window, width=150, height=150)
6 frame.pack()
sept
8 label1 = tk.Étiquette(Maître=frame, text="I'm at (0, 0)", bg="red")
9 label1.endroit(X=0, y=0)
dix
11 label2 = tk.Étiquette(Maître=frame, text="I'm at (75, 75)", bg="yellow")
12 label2.endroit(X=75, y=75)
13
14 window.mainloop()
Here’s how this code works:
- Lines 5 and 6 create a new
Cadre
widget calledframe1
, one that’s150
pixels wide and150
pixels tall, and pack it into the window with.pack()
. - Lines 8 and 9 create a new
Étiquette
appelélabel1
with a yellow background and place it inframe1
at position (0, 0). - Lines 11 and 12 create a second
Étiquette
appelélabel2
with a red background and place it inframe1
at position (75, 75).
Here’s the window the code produces:
.place()
is not used often. It has two main drawbacks:
- Layout can be difficult to manage with
.place()
. This is especially true if your application has lots of widgets. - Layouts created with
.place()
are not responsive. They don’t change as the window is resized.
One of the main challenges of cross-platform GUI development is making layouts that look good no matter which platform they are viewed on, and .place()
is a poor choice for making responsive and cross-platform layouts.
That’s not to say .place()
should never be used! In some cases, it might be just what you need. For example, if you’re creating a GUI interface for a map, then .place()
might be the perfect choice to ensure widgets are placed at the correct distance from each other on the map.
.pack()
is usually a better choice than .place()
, but even .pack()
has some downsides. The placement of widgets depends on the order in which .pack()
is called, so it can be difficult to modify existing applications without fully understanding the code controlling the layout. le .grid()
geometry manager solves a lot of these issues, as you’ll see in the next section.
le .grid()
Geometry Manager
The geometry manager you’ll likely use most often is .grid()
, which provides all the power of .pack()
in a format that’s easier to understand and maintain.
.grid()
works by splitting a window or Cadre
into rows and columns. You specify the location of a widget by calling .grid()
and passing the row and column indices to the row
et column
keyword arguments, respectively. Both row and column indices start at 0
, so a row index of 1
and a column index of 2
tells .grid()
to place a widget in the third column of the second row.
The following script creates a 3 × 3 grid of frames with Étiquette
widgets packed into them:
import tkinter comme tk
window = tk.Tk()
pour je dans intervalle(3):
pour j dans intervalle(3):
frame = tk.Cadre(
Maître=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=je, column=j)
label = tk.Étiquette(Maître=frame, text=f"Row i nColonne j")
label.pack()
window.mainloop()
Here’s what the resulting window looks like:
Two geometry managers are being used in this example. Each Cadre
is attached to the window
avec le .grid()
geometry manager:
import tkinter comme tk
window = tk.Tk()
pour je dans intervalle(3):
pour j dans intervalle(3):
frame = tk.Cadre(
Maître=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=je, column=j)
label = tk.Étiquette(Maître=frame, text=f"Row i nColonne j")
label.pack()
window.mainloop()
Each label
is attached to its master Cadre
avec .pack()
:
import tkinter comme tk
window = tk.Tk()
pour je dans intervalle(3):
pour j dans intervalle(3):
frame = tk.Cadre(
Maître=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=je, column=j)
label = tk.Étiquette(Maître=frame, text=f"Row i nColonne j")
label.pack()
window.mainloop()
The important thing to realize here is that even though .grid()
is called on each Cadre
object, the geometry manager applies to the window
object. Similarly, the layout of each frame
is controlled with the .pack()
geometry manager.
The frames in the previous example are placed tightly next to one another. To add some space around each Cadre
, you can set the padding of each cell in the grid. Padding is just some blank space that surrounds a widget and separates it visually from its contents.
The two types of padding are external et internal padding. External padding adds some space around the outside of a grid cell. It’s controlled with two keyword arguments to .grid()
:
padx
adds padding in the horizontal direction.pady
adds padding in the vertical direction.
Tous les deux padx
et pady
are measured in pixels, not text units, so setting both of them to the same value will create the same amount of padding in both directions. Try to add some padding around the outside of the frames in the previous example:
import tkinter comme tk
window = tk.Tk()
pour je dans intervalle(3):
pour j dans intervalle(3):
frame = tk.Cadre(
Maître=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=je, column=j, padx=5, pady=5)
label = tk.Étiquette(Maître=frame, text=f"Row i nColonne j")
label.pack()
window.mainloop()
Here’s the resulting window:
.pack()
also has padx
et pady
parameters. The following code is nearly identical to the previous code, except that you add 5 pixels of additional padding around each Étiquette
in both the X
et y
directions:
import tkinter comme tk
window = tk.Tk()
pour je dans intervalle(3):
pour j dans intervalle(3):
frame = tk.Cadre(
Maître=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=je, column=j, padx=5, pady=5)
label = tk.Étiquette(Maître=frame, text=f"Row i nColonne j")
label.pack(padx=5, pady=5)
window.mainloop()
The extra padding around the Étiquette
widgets gives each cell in the grid a little bit of breathing room between the Cadre
border and the text in the Étiquette
:
That looks pretty nice! But if you try and expand the window in any direction, then you’ll notice that the layout isn’t very responsive:
The whole grid stays at the top-left corner as the window expands.
You can adjust how the rows and columns of the grid grow as the window is resized using .columnconfigure()
et .rowconfigure()
sur le window
object. Remember, the grid is attached to window
, even though you’re calling .grid()
on each Cadre
widget. Tous les deux .columnconfigure()
et .rowconfigure()
take three essential arguments:
- The index of the grid column or row that you want to configure (or a list of indices to configure multiple rows or columns at the same time)
- A keyword argument called
weight
that determines how the column or row should respond to window resizing, relative to the other columns and rows - A keyword argument called
minsize
that sets the minimum size of the row height or column width in pixels
weight
is set to 0
by default, which means that the column or row doesn’t expand as the window resizes. If every column and row is given a weight of 1
, then they all grow at the same rate. If one column has a weight of 1
and another a weight of 2
, then the second column expands at twice the rate of the first. Adjust the previous script to better handle window resizing:
import tkinter comme tk
window = tk.Tk()
pour je dans intervalle(3):
window.columnconfigure(je, weight=1, minsize=75)
window.rowconfigure(je, weight=1, minsize=50)
pour j dans intervalle(0, 3):
frame = tk.Cadre(
Maître=window,
relief=tk.RAISED,
borderwidth=1
)
frame.grid(row=je, column=j, padx=5, pady=5)
label = tk.Étiquette(Maître=frame, text=f"Row i nColonne j")
label.pack(padx=5, pady=5)
window.mainloop()
.columnconfigure()
et .rowconfigure()
are placed in the body of the outer pour
loop. (You could explicitly configure each column and row outside of the pour
loop, but that would require writing an additional six lines of code.)
On each iteration of the loop, the je
-th column and row are configured to have a weight
de 1
. This ensures that each row and column expands at the same rate whenever the window is resized. le minsize
argument is set to 75
for each column and 50
for each row. This makes sure the Étiquette
widget always displays its text without chopping off any characters, even if the window size is extremely small.
The result is a grid layout that expands and contracts smoothly as the window is resized:
Try it yourself to get a feel for how it works! Play around with the weight
et minsize
parameters to see how they affect the grid.
By default, widgets are centered in their grid cells. For example, the following code creates two Étiquette
widgets and places them in a grid with one column and two rows:
import tkinter comme tk
window = tk.Tk()
window.columnconfigure(0, minsize=250)
window.rowconfigure([[[[0, 1], minsize=100)
label1 = tk.Étiquette(text="A")
label1.grid(row=0, column=0)
label2 = tk.Étiquette(text="B")
label2.grid(row=1, column=0)
window.mainloop()
Each grid cell is 250
pixels wide and 100
pixels tall. The labels are placed in the center of each cell, as you can see in the following figure:
You can change the location of each label inside of the grid cell using the sticky
parameter. sticky
accepts a string containing one or more of the following letters:
"n"
ou"N"
to align to the top-center part of the cell"e"
ou"E"
to align to the right-center side of the cell"s"
ou"S"
to align to the bottom-center part of the cell"w"
ou"W"
to align to the left-center side of the cell
The letters "n"
, "s"
, "e"
, et "w"
come from the cardinal directions north, south, east, and west. Réglage sticky
à "n"
on both Labels
in the previous code positions each Étiquette
at the top-center of its grid cell:
import tkinter comme tk
window = tk.Tk()
window.columnconfigure(0, minsize=250)
window.rowconfigure([[[[0, 1], minsize=100)
label1 = tk.Étiquette(text="A")
label1.grid(row=0, column=0, sticky="n")
label2 = tk.Étiquette(text="B")
label2.grid(row=1, column=0, sticky="n")
window.mainloop()
Here’s the output:
You can combine multiple letters in a single string to position each Étiquette
in the corner of its grid cell:
import tkinter comme tk
window = tk.Tk()
window.columnconfigure(0, minsize=250)
window.rowconfigure([[[[0, 1], minsize=100)
label1 = tk.Étiquette(text="A")
label1.grid(row=0, column=0, sticky="ne")
label2 = tk.Étiquette(text="B")
label2.grid(row=1, column=0, sticky="sw")
window.mainloop()
In this example, the sticky
parameter of label1
is set to "ne"
, which places the label at the top-right corner of its grid cell. label2
is positioned in the bottom-left corner by passing "sw"
à sticky
. Here’s what that looks like in the window:
When a widget is positioned with sticky
, the size of the widget itself is just big enough to contain any text and other contents inside of it. It won’t fill the entire grid cell. In order to fill the grid, you can specify "ns"
to force the widget to fill the cell in the vertical direction, or "ew"
to fill the cell in the vertical direction. To fill the entire cell, set sticky
à "nsew"
. The following example illustrates each of these options:
import tkinter comme tk
window = tk.Tk()
window.rowconfigure(0, minsize=50)
window.columnconfigure([[[[0, 1, 2, 3], minsize=50)
label1 = tk.Étiquette(text="1", bg="black", fg="white")
label2 = tk.Étiquette(text="2", bg="black", fg="white")
label3 = tk.Étiquette(text="3", bg="black", fg="white")
label4 = tk.Étiquette(text="4", bg="black", fg="white")
label1.grid(row=0, column=0)
label2.grid(row=0, column=1, sticky="ew")
label3.grid(row=0, column=2, sticky="ns")
label4.grid(row=0, column=3, sticky="nsew")
window.mainloop()
Here’s what the output looks like:
What the above example illustrates is that the .grid()
geometry manager’s sticky
parameter can be used to achieve the same effects as the .pack()
geometry manager’s fill
parameter. The correspondence between the sticky
et fill
parameters is summarized in the following table:
.grid() |
.pack() |
---|---|
sticky="ns" |
fill=tk.Y |
sticky="ew" |
fill=tk.X |
sticky="nsew" |
fill=tk.BOTH |
.grid()
is a powerful geometry manager. It’s often easier to understand than .pack()
and is much more flexible than .place()
. When you’re creating new Tkinter applications, you should consider using .grid()
as your primary geometry manager.
Remarque: .grid()
offers much more flexibility than you’ve seen here. For example, you can configure cells to span multiple rows and columns. For more information, check out the Grid Geometry Manager section of the TkDocs tutorial.
Now that you’ve got the fundamentals of geometry managers down for the Python GUI framework Tkinter, the next step is to assign actions to buttons to bring your applications to life.
Check Your Understanding
Expand the code block below for an exercise to check your understanding:
Below is an image of an address entry form made with Tkinter.
Write a complete script that re-creates the window. You may use any geometry manager you like.
You can expand the code block below to see a solution:
There are many different ways to solve this exercise. If your solution generates a window identical to the one in the exercise statement, then congratulations! You’ve successfully solved the exercise! Below, you can look at two solutions that use the .grid()
geometry manager.
One solution creates a Étiquette
et Entrée
widget for each field with the desired settings:
import tkinter comme tk
# Create a new window with the title "Address Entry Form"
window = tk.Tk()
window.title("Address Entry Form")
# Create a new frame `frm_form` to contain the Label
# and Entry widgets for entering address information.
frm_form = tk.Cadre(relief=tk.SUNKEN, borderwidth=3)
# Pack the frame into the window
frm_form.pack()
# Create the Label and Entry widgets for "First Name"
lbl_first_name = tk.Étiquette(Maître=frm_form, text="First Name:")
ent_first_name = tk.Entrée(Maître=frm_form, width=50)
# Use the grid geometry manager to place the Label and
# Entry widgets in the first and second columns of the
# first row of the grid
lbl_first_name.grid(row=0, column=0, sticky="e")
ent_first_name.grid(row=0, column=1)
# Create the Label and Entry widgets for "Last Name"
lbl_last_name = tk.Étiquette(Maître=frm_form, text="Last Name:")
ent_last_name = tk.Entrée(Maître=frm_form, width=50)
# Place the widgets in the second row of the grid
lbl_last_name.grid(row=1, column=0, sticky="e")
ent_last_name.grid(row=1, column=1)
# Create the Label and Entry widgets for "Address Line 1"
lbl_address1 = tk.Étiquette(Maître=frm_form, text="Address Line 1:")
ent_address1 = tk.Entrée(Maître=frm_form, width=50)
# Place the widgets in the third row of the grid
lbl_address1.grid(row=2, column=0, sticky="e")
ent_address1.grid(row=2, column=1)
# Create the Label and Entry widgets for "Address Line 2"
lbl_address2 = tk.Étiquette(Maître=frm_form, text="Address Line 2:")
ent_address2 = tk.Entrée(Maître=frm_form, width=5)
# Place the widgets in the fourth row of the grid
lbl_address2.grid(row=3, column=0, sticky=tk.E)
ent_address2.grid(row=3, column=1)
# Create the Label and Entry widgets for "City"
lbl_city = tk.Étiquette(Maître=frm_form, text="City:")
ent_city = tk.Entrée(Maître=frm_form, width=50)
# Place the widgets in the fifth row of the grid
lbl_city.grid(row=4, column=0, sticky=tk.E)
ent_city.grid(row=4, column=1)
# Create the Label and Entry widgets for "State/Province"
lbl_state = tk.Étiquette(Maître=frm_form, text="State/Province:")
ent_state = tk.Entrée(Maître=frm_form, width=50)
# Place the widgets in the sixth row of the grid
lbl_state.grid(row=5, column=0, sticky=tk.E)
ent_state.grid(row=5, column=1)
# Create the Label and Entry widgets for "Postal Code"
lbl_postal_code = tk.Étiquette(Maître=frm_form, text="Postal Code:")
ent_postal_code = tk.Entrée(Maître=frm_form, width=50)
# Place the widgets in the seventh row of the grid
lbl_postal_code.grid(row=6, column=0, sticky=tk.E)
ent_postal_code.grid(row=6, column=1)
# Create the Label and Entry widgets for "Country"
lbl_country = tk.Étiquette(Maître=frm_form, text="Country:")
ent_country = tk.Entrée(Maître=frm_form, width=50)
# Place the widgets in the eight row of the grid
lbl_country.grid(row=sept, column=0, sticky=tk.E)
ent_country.grid(row=sept, column=1)
# Create a new frame `frm_buttons` to contain the
# Submit and Clear buttons. This frame fills the
# whole window in the horizontal direction and has
# 5 pixels of horizontal and vertical padding.
frm_buttons = tk.Cadre()
frm_buttons.pack(fill=tk.X, ipadx=5, ipady=5)
# Create the "Submit" button and pack it to the
# right side of `frm_buttons`
btn_submit = tk.Bouton(Maître=frm_buttons, text="Submit")
btn_submit.pack(côté=tk.RIGHT, padx=dix, ipadx=dix)
# Create the "Clear" button and pack it to the
# right side of `frm_buttons`
btn_clear = tk.Bouton(Maître=frm_buttons, text="Clear")
btn_clear.pack(côté=tk.RIGHT, ipadx=dix)
# Start the application
window.mainloop()
There’s nothing wrong with this solution. It’s a bit long, but everything is very explicit. If you want to change something, then it’s clear to see exactly where to do so.
That said, the solution can be considerably shortened by recognizing that each Entrée
has the same width, and that all you need for each Étiquette
is the text:
import tkinter comme tk
# Create a new window with the title "Address Entry Form"
window = tk.Tk()
window.title("Address Entry Form")
# Create a new frame `frm_form` to contain the Label
# and Entry widgets for entering address information.
frm_form = tk.Cadre(relief=tk.SUNKEN, borderwidth=3)
# Pack the frame into the window
frm_form.pack()
# List of field labels
labels = [[[[
"First Name:",
"Last Name:",
"Address Line 1:",
"Address Line 2:",
"City:",
"State/Province:",
"Postal Code:",
"Country:",
]
# Loop over the list of field labels
pour idx, text dans enumerate(labels):
# Create a Label widget with the text from the labels list
label = tk.Étiquette(Maître=frm_form, text=text)
# Create an Entry widget
entry = tk.Entrée(Maître=frm_form, width=50)
# Use the grid geometry manager to place the Label and
# Entry widgets in the row whose index is idx
label.grid(row=idx, column=0, sticky="e")
entry.grid(row=idx, column=1)
# Create a new frame `frm_buttons` to contain the
# Submit and Clear buttons. This frame fills the
# whole window in the horizontal direction and has
# 5 pixels of horizontal and vertical padding.
frm_buttons = tk.Cadre()
frm_buttons.pack(fill=tk.X, ipadx=5, ipady=5)
# Create the "Submit" button and pack it to the
# right side of `frm_buttons`
btn_submit = tk.Bouton(Maître=frm_buttons, text="Submit")
btn_submit.pack(côté=tk.RIGHT, padx=dix, ipadx=dix)
# Create the "Clear" button and pack it to the
# right side of `frm_buttons`
btn_clear = tk.Bouton(Maître=frm_buttons, text="Clear")
btn_clear.pack(côté=tk.RIGHT, ipadx=dix)
# Start the application
window.mainloop()
In this solution, a list is used to store the strings for each Étiquette
in the form. They’re stored in the order that each form field should appear. Alors, enumerate()
gets both the index and string from each value in the labels
liste.
When you’re ready, you can move on to the next section.
Making Your Applications Interactive
By now, you have a pretty good idea of how to create a window with Tkinter, add some widgets, and control the application layout. That’s great, but applications shouldn’t just look good—they actually need to do something! In this section, you’ll learn how to bring your applications to life by performing actions whenever certain événements occur.
Using Events and Event Handlers
When you create a Tkinter application, you must call window.mainloop()
to start the event loop. During the event loop, your application checks if an event has occurred. If so, then some code can be executed in response.
The event loop is provided for you with Tkinter, so you don’t have to write any code that checks for events yourself. However, you do have to write the code that will be executed in response to an event. In Tkinter, you write functions called event handlers for the events that you use in your application.
Remarque: Un un événement is any action that occurs during the event loop that might trigger some behavior in the application, such as when a key or mouse button is pressed.
When an event occurs, an event object is emitted, which means that an instance of a class representing the event is instantiated. You don’t need to worry about creating these classes yourself. Tkinter will create instances of event classes for you automatically.
You’ll write your own event loop in order to understand better how Tkinter’s event loop works. That way, you can see how Tkinter’s event loop fits into your application, and which parts you need to write yourself.
Assume there’s a list called events_list
that contains event objects. A new event object is automatically appended to events_list
every time an event occurs in your program. (You don’t need to implement this updating mechanism. It just automatically happens for you in this conceptual example.) Using an infinite loop, you can continually check if there are any event objects in events_list
:
# Assume that this list gets updated automatically
events_list = []
# Run the event loop
tandis que True:
# If events_list is empty, then no events have occurred and you
# can skip to the next iteration of the loop
si events_list == []:
continue
# If execution reaches this point, then there is at least one
# event object in events_list
un événement = events_list[[[[0]
Right now, the event loop you’ve created doesn’t do anything with un événement
. Let’s change that. Suppose your application needs to respond to keypresses. You need to check that un événement
was generated by a user pressing a key on their keyboard, and, if so, pass un événement
to an event handler function for key presses.
Assume that un événement
has a .type
attribute set to the string "keypress"
if the event is a keypress event object, and a .char
attribute containing the character of the key that was pressed. Create a new function handle_keypress()
and update your event loop code:
events_list = []
# Create an event handler
def handle_keypress(un événement):
"""Print the character associated to the key pressed"""
impression(un événement.char)
tandis que True:
si events_list == []:
continue
un événement = events_list[[[[0]
# If event is a keypress event object
si un événement.type == "keypress":
# Call the keypress event handler
handle_keypress(un événement)
When you call window.mainloop()
, something like the above loop is run for you. This method takes care of two parts of the loop for you:
- It maintains a list of events that have occurred.
- It runs an event handler any time a new event is added to that list.
Update your event loop to use window.mainloop()
instead of your own event loop:
import tkinter comme tk
# Create a window object
window = tk.Tk()
# Create an event handler
def handle_keypress(un événement):
"""Print the character associated to the key pressed"""
impression(un événement.char)
# Run the event loop
window.mainloop()
.mainloop()
takes care of a lot for you, but there’s something missing from the above code. How does Tkinter know when to use handle_keypress()
? Tkinter widgets have a method called .bind()
for just this purpose.
En utilisant .bind()
To call an event handler whenever an event occurs on a widget, use .bind()
. The event handler is said to be bound to the event because it’s called every time the event occurs. You’ll continue with the keypress example from the previous section and use .bind()
to bind handle_keypress()
to the keypress event:
import tkinter comme tk
window = tk.Tk()
def handle_keypress(un événement):
"""Print the character associated to the key pressed"""
impression(un événement.char)
# Bind keypress event to handle_keypress()
window.bind("" , handle_keypress)
window.mainloop()
Here, the handle_keypress()
event handler is bound to a "
event using window.bind()
. Whenever a key is pressed while the application is running, your program will print the character of the key pressed.
.bind()
always takes at least two arguments:
- An event that’s represented by a string of the form
"
, where" event_name
can be any of Tkinter’s events - An event handler that’s the name of the function to be called whenever the event occurs
The event handler is bound to the widget on which .bind()
is called. When the event handler is called, the event object is passed to the event handler function.
In the example above, the event handler is bound to the window itself, but you can bind an event handler to any widget in your application. For example, you can bind an event handler to a Bouton
widget that will perform some action whenever the button is pressed:
def handle_click(un événement):
impression("The button was clicked!")
bouton = tk.Bouton(text="Click me!")
bouton.bind("" , handle_click)
In this example, the "
event on the bouton
widget is bound to the handle_click
event handler. le "
event occurs whenever the left mouse button is pressed while the mouse is over the widget. There are other events for mouse button clicks, including "
for the middle mouse button and "
for the right mouse button.
You can bind any event handler to any kind of widget with .bind()
, but there’s an easier way to bind event handlers to button clicks using the Bouton
widget’s command
attribute.
En utilisant command
Every Bouton
widget has a command
attribute that you can assign to a function. Whenever the button is pressed, the function is executed.
Take a look at an example. First, you’ll create a window with a Étiquette
widget that holds a numerical value. You’ll put buttons on the left and right side of the label. The left button will be used to decrease the value in the Étiquette
, and the right one will increase the value. Here’s the code for the window:
import tkinter comme tk
window = tk.Tk()
window.rowconfigure(0, minsize=50, weight=1)
window.columnconfigure([[[[0, 1, 2], minsize=50, weight=1)
btn_decrease = tk.Bouton(Maître=window, text="-")
btn_decrease.grid(row=0, column=0, sticky="nsew")
lbl_value = tk.Étiquette(Maître=window, text="0")
lbl_value.grid(row=0, column=1)
btn_increase = tk.Bouton(Maître=window, text="+")
btn_increase.grid(row=0, column=2, sticky="nsew")
window.mainloop()
The window looks like this:
With the app layout defined, you can bring it to life by giving the buttons some commands. Start with the left button. When this button is pressed, it should decrease the value in the label by 1. There are two things you need to know how to do in order to do this:
- How do you get the text in a
Étiquette
? - How do you update the text in a
Étiquette
?
Étiquette
widgets don’t have .get()
comme Entrée
et Texte
widgets do. However, you can retrieve the text from the label by accessing the text
attribute with a dictionary-style subscript notation:
label = Tk.Étiquette(text="Hello")
# Retrieve a Label's text
text = label[[[["text"]
# Set new text for the label
label[[[["text"] = "Good bye"
Now that you know how to get and set a label’s text, write a function increase()
that increases the value in the lbl_value
by 1:
def increase():
valeur = int(lbl_value[[[["text"])
lbl_value[[[["text"] = f"value + 1"
increase()
gets the text from lbl_value
and converts it to an integer with int()
. Then, it increases this value by 1 and sets the label’s text
attribute to this new value.
You’ll also need decrease()
to decrease the value in value_label
by 1:
def decrease():
valeur = int(lbl_value[[[["text"])
lbl_value[[[["text"] = f"value - 1"
Put increase()
et decrease()
in your code just after the import
statement.
To connect the buttons to the functions, assign the function to the button’s command
attribute. You can do this when you instantiate the button. For example, to assign increase()
à increase_button
, update the line that instantiates the button to the following:
btn_increase = tk.Bouton(Maître=window, text="+", command=increase)
Now assign decrease()
à decrease_button
:
btn_decrease = tk.Bouton(Maître=window, text="-", command=decrease)
That’s all you need to do to bind the buttons to increase()
et decrease()
and make the program functional. Try saving your changes and running the application! Click the buttons to increase and decrease the value in the center of the window:
Here’s the full application code for your reference:
import tkinter comme tk
def increase():
valeur = int(lbl_value[[[["text"])
lbl_value[[[["text"] = f"value + 1"
def decrease():
valeur = int(lbl_value[[[["text"])
lbl_value[[[["text"] = f"value - 1"
window = tk.Tk()
window.rowconfigure(0, minsize=50, weight=1)
window.columnconfigure([[[[0, 1, 2], minsize=50, weight=1)
btn_decrease = tk.Bouton(Maître=window, text="-", command=decrease)
btn_decrease.grid(row=0, column=0, sticky="nsew")
lbl_value = tk.Étiquette(Maître=window, text="0")
lbl_value.grid(row=0, column=1)
btn_increase = tk.Bouton(Maître=window, text="+", command=increase)
btn_increase.grid(row=0, column=2, sticky="nsew")
window.mainloop()
This app is not particularly useful, but the skills you learned here apply to every app you’ll make:
- Use widgets to create the components of the user interface.
- Use geometry managers to control the layout of the application.
- Write functions that interact with various components to capture and transform user input.
In the next two sections, you’ll build apps that do something useful. First, you’ll build a temperature converter that converts a temperature value from Fahrenheit to Celsius. After that, you’ll build a text editor that can open, edit, and save text files!
Check Your Understanding
Expand the code block below for an exercise to check your understanding:
Write a program that simulates rolling a six-sided die. There should be one button with the text "Roll"
. When the user clicks the button, a random integer from 1
à 6
should be displayed.
The application window should look something like this:
Try this exercise now.
You can expand the code block below to see a solution:
Here’s one possible solution:
import random
import tkinter comme tk
def roll():
lbl_result[[[["text"] = str(random.randint(1, 6))
window = tk.Tk()
window.columnconfigure(0, minsize=150)
window.rowconfigure([[[[0, 1], minsize=50)
btn_roll = tk.Bouton(text="Roll", command=roll)
lbl_result = tk.Étiquette()
btn_roll.grid(row=0, column=0, sticky="nsew")
lbl_result.grid(row=1, column=0)
window.mainloop()
Keep in mind your code may look different.
When you’re ready, you can move on to the next section.
Building a Temperature Converter (Example App)
In this section, you’ll build a temperature converter application that allows the user to input temperature in degrees Fahrenheit and push a button to convert that temperature to degrees Celsius. You’ll walk through the code step by step. You can also find the full source code at the end of this section for your reference.
Remarque: To get the most out of this section, follow along in a Python shell.
Before you start coding, you’ll first design the app. You need three elements:
- Un
Entrée
widget appeléent_temperature
to enter the Fahrenheit value - UNE
Étiquette
widget appelélbl_result
to display the Celsius result - UNE
Bouton
widget appelébtn_convert
that reads the value from theEntrée
widget, converts it from Fahrenheit to Celsius, and sets the text of theÉtiquette
widget to the result when clicked
You can arrange these in a grid with a single row and one column for each widget. That gets you a minimally working application, but it isn’t very user-friendly. Everything needs to have labels.
You’ll put a label directly to the right of the ent_temperature
widget containing the Fahrenheit symbol (℉) so that the user knows that the value ent_temperature
should be in degrees Fahrenheit. To do this, set the label text to "NDEGREES FAHRENHEIT"
, which uses Python’s named Unicode character support to display the Fahrenheit symbol.
You can give btn_convert
a little flair by setting it’s text to the value "NRIGHTWARDS BLACK ARROW"
, which displays a black arrow pointing to the right. You’ll also make sure that lbl_result
always has the Celsius symbol (℃) following the label text "NDEGREES CELSIUS"
to indicate that the result is in degrees Celsius. Here’s what the final window will look like:
Now that you know what widgets you need and what the window is going to look like, you can start coding it up! First, import tkinter
and create a new window:
import tkinter comme tk
window = tk.Tk()
window.title("Temperature Converter")
window.title()
sets the title of an existing window. When you finally run this application, the window will have the text Temperature Converter in its title bar. Next, create the ent_temperature
widget with a label called lbl_temp
and assign both to a Cadre
widget called frm_entry
:
frm_entry = tk.Cadre(Maître=window)
ent_temperature = tk.Entrée(Maître=frm_entry, width=dix)
lbl_temp = tk.Étiquette(Maître=frm_entry, text="NDEGREE FAHRENHEIT")
ent_temperature
is where the user will enter the Fahrenheit value. lbl_temp
is used to label ent_temperature
with the Fahrenheit symbol. frm_entry
is a container that groups ent_temperature
et lbl_temp
ensemble.
Tu veux lbl_temp
to be placed directly to the right of ent_temperature
. You can lay them out in the frm_entry
using the .grid()
geometry manager with one row and two columns:
ent_temperature.grid(row=0, column=0, sticky="e")
lbl_temp.grid(row=0, column=1, sticky="w")
You’ve set the sticky
parameter to "e"
pour ent_temperature
so that it always sticks to the right-most edge of its grid cell. You also set sticky
à "w"
pour lbl_temp
to keep it stuck to the left-most edge of its grid cell. This ensures that lbl_temp
is always located immediately to the right of ent_temperature
.
Now, make the btn_convert
et le lbl_result
for converting the temperature entered into ent_temperature
and displaying the results:
btn_convert = tk.Bouton(
Maître=window,
text="NRIGHTWARDS BLACK ARROW"
)
lbl_result = tk.Étiquette(Maître=window, text="NDEGREE CELSIUS")
Comme frm_entry
, both btn_convert
et lbl_result
are assigned to window
. Together, these three widgets make up the three cells in the main application grid. Use .grid()
to go ahead and lay them out now:
frm_entry.grid(row=0, column=0, padx=dix)
btn_convert.grid(row=0, column=1, pady=dix)
lbl_result.grid(row=0, column=2, padx=dix)
Finally, run the application:
That looks great! But the button doesn’t do anything just yet. At the top of your script file, just below the import
line, add a function called fahrenheit_to_celsius()
:
def fahrenheit_to_celsius():
"""Convert the value for Fahrenheit to Celsius and insert the
result into lbl_result.
"""
fahrenheit = ent_temperature.avoir()
celsius = (5/9) * (float(fahrenheit) - 32)
lbl_result[[[["text"] = f"round(celsius, 2) NDEGREE CELSIUS"
This function reads the value from ent_temperature
, converts it from Fahrenheit to Celsius, and then displays the result in lbl_result
.
Now go down to the line where you define btn_convert
and set its command
parameter to fahrenheit_to_celsius
:
btn_convert = tk.Bouton(
Maître=window,
text="NRIGHTWARDS BLACK ARROW",
command=fahrenheit_to_celsius # <--- Add this line
)
C'est ça! You’ve created a fully functional temperature converter app in just 26 lines of code! Pretty cool, right?
You can expand the code block below to see the full script:
Here’s the full script for your reference:
import tkinter comme tk
def fahrenheit_to_celsius():
"""Convert the value for Fahrenheit to Celsius and insert the
result into lbl_result.
"""
fahrenheit = ent_temperature.avoir()
celsius = (5/9) * (float(fahrenheit) - 32)
lbl_result[[[["text"] = f"round(celsius, 2) NDEGREE CELSIUS"
# Set-up the window
window = tk.Tk()
window.title("Temperature Converter")
window.resizable(width=Faux, height=Faux)
# Create the Fahrenheit entry frame with an Entry
# widget and label in it
frm_entry = tk.Cadre(Maître=window)
ent_temperature = tk.Entrée(Maître=frm_entry, width=dix)
lbl_temp = tk.Étiquette(Maître=frm_entry, text="NDEGREE FAHRENHEIT")
# Layout the temperature Entry and Label in frm_entry
# using the .grid() geometry manager
ent_temperature.grid(row=0, column=0, sticky="e")
lbl_temp.grid(row=0, column=1, sticky="w")
# Create the conversion Button and result display Label
btn_convert = tk.Bouton(
Maître=window,
text="NRIGHTWARDS BLACK ARROW",
command=fahrenheit_to_celsius
)
lbl_result = tk.Étiquette(Maître=window, text="NDEGREE CELSIUS")
# Set-up the layout using the .grid() geometry manager
frm_entry.grid(row=0, column=0, padx=dix)
btn_convert.grid(row=0, column=1, pady=dix)
lbl_result.grid(row=0, column=2, padx=dix)
# Run the application
window.mainloop()
It’s time to kick things up a notch! Read on to learn how to build a text editor.
Building a Text Editor (Example App)
In this section, you’ll build a text editor application that can create, open, edit, and save text files. There are three essential elements in the application:
- UNE
Bouton
widget calledbtn_open
for opening a file for editing - UNE
Bouton
widget calledbtn_save
for saving a file - UNE
TextBox
widget calledtxt_edit
for creating and editing the text file
The three widgets will be arranged so that the two buttons are on the left-hand side of the window, and the text box is on the right-hand side. The whole window should have a minimum height of 800 pixels, and txt_edit
should have a minimum width of 800 pixels. The whole layout should be responsive so that if the window is resized, then txt_edit
is resized as well. The width of the Cadre
holding the buttons should not change, however.
Here’s a sketch of how the window will look:
You can achieve the desired layout using the .grid()
geometry manager. The layout contains a single row and two columns:
- A narrow column on the left for the buttons
- A wider column on the right for the text box
To set the minimum sizes for the window and txt_edit
, you can set the minsize
parameters of the window methods .rowconfigure()
et .columnconfigure()
to 800. To handle resizing, you can set the weight
parameters of these methods to 1.
In order to get both buttons into the same column, you’ll need to create a Cadre
widget called fr_buttons
. According to the sketch, the two buttons should be stacked vertically inside of this frame, with btn_open
on top. You can do that with either the .grid()
ou .pack()
geometry manager. For now, you’ll stick with .grid()
since it’s a little easier to work with.
Now that you have a plan, you can start coding the application. The first step is to create the all of the widgets you need:
1 import tkinter comme tk
2
3 window = tk.Tk()
4 window.title("Simple Text Editor")
5
6 window.rowconfigure(0, minsize=800, weight=1)
sept window.columnconfigure(1, minsize=800, weight=1)
8
9 txt_edit = tk.Texte(window)
dix fr_buttons = tk.Cadre(window)
11 btn_open = tk.Bouton(fr_buttons, text="Open")
12 btn_save = tk.Bouton(fr_buttons, text="Save As...")
Here’s a breakdown of this code:
- Line 1 imports
tkinter
. - Lines 3 and 4 create a new window with the title
"Simple Text Editor"
. - Lines 6 and 7 set the row and column configurations.
- Lines 9 to 12 create the four widgets you’ll need for the text box, the frame, and the open and save buttons.
Take a look at line 6 more closely. le minsize
parameter of .rowconfigure()
is set to 800
et weight
is set to 1
:
window.rowconfigure(0, minsize=800, weight=1)
The first argument is 0
, which sets the height of the first row to 800
pixels and makes sure that the height of the row grows proportionally to the height of the window. There’s only one row in the application layout, so these settings apply to the entire window.
Let’s also take a closer look at line 7. Here, you use .columnconfigure()
to set the width
et weight
attributes of the column with index 1
à 800
et 1
, respectively:
window.columnconfigure(1, minsize=800, weight=1)
Remember, row and column indices are zero-based, so these settings apply only to the second column. By configuring just the second column, the text box will expand and contract naturally when the window is resized, while the column containing the buttons will remain at a fixed width.
Now you can work on the application layout. First, assign the two buttons to the fr_buttons
frame using the .grid()
geometry manager:
btn_open.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
btn_save.grid(row=1, column=0, sticky="ew", padx=5)
These two lines of code create a grid with two rows and one column in the fr_buttons
frame since both btn_open
et btn_save
have their Maître
attribute set to fr_buttons
. btn_open
is put in the first row and btn_save
in the second row so that btn_open
appears above btn_save
in the layout, just you planned in your sketch.
Tous les deux btn_open
et btn_save
have their sticky
attributes set to "ew"
, which forces the buttons to expand horizontally in both directions and fill the entire frame. This makes sure both buttons are the same size.
You place 5 pixels of padding around each button by setting the padx
et pady
parameters to 5. Only btn_open
has vertical padding. Since it’s on top, the vertical padding offsets the button down from the top of the window a bit and makes sure that there’s a small gap between it and btn_save
.
Maintenant que fr_buttons
is laid out and ready to go, you can set up the grid layout for the rest of the window:
fr_buttons.grid(row=0, column=0, sticky="ns")
txt_edit.grid(row=0, column=1, sticky="nsew")
These two lines of code create a grid with one row and two columns for window
. You place fr_buttons
in the first column and txt_edit
in the second column so that fr_buttons
appears to the left of txt_edit
in the window layout.
le sticky
parameter for fr_buttons
is set to "ns"
, which forces the whole frame to expand vertically and fill the entire height of its column. txt_edit
fills its entire grid cell because you set its sticky
parameter to "nsew"
, which forces it to expand in every direction.
Now that the application layout is complete, add window.mainloop()
to the bottom of the program and save and run the file. The following window is displayed:
That looks great! But it doesn’t do anything just yet, so you need to start writing the commands for the buttons. btn_open
needs to show a file open dialog and allow the user to select a file. It then needs to open that file and set the text of txt_edit
to the contents of the file. Here’s a function open_file()
that does just this:
1 def open_file():
2 """Open a file for editing."""
3 filepath = askopenfilename(
4 filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")]
5 )
6 si ne pas filepath:
sept revenir
8 txt_edit.delete("1.0", tk.END)
9 avec open(filepath, "r") comme input_file:
dix text = input_file.lis()
11 txt_edit.insert(tk.END, text)
12 window.title(f"Simple Text Editor - filepath")
Here’s a breakdown of this function:
- Lines 3 to 5 use the
askopenfilename
dialog from thetkinter.filedialog
module to display a file open dialog and store the selected file path tofilepath
. - Lines 6 and 7 check to see if the user closes the dialog box or clicks the Annuler bouton. If so, then
filepath
will beAucun
, and the function willrevenir
without executing any of the code to read the file and set the text oftxt_edit
. - Line 8 clears the current contents of
txt_edit
en utilisant.delete()
. - Lines 9 and 10 open the selected file and
.read()
its contents before storing thetext
as a string. - Line 11 assigns he string
text
àtxt_edit
en utilisant.insert()
. - Line 12 sets the title of the window so that it contains the path of the open file.
Now you can update the program so that btn_open
calls open_file()
whenever it’s clicked. There are a few things you need to do to update the program. First, import askopenfilename()
de tkinter.filedialog
by adding the following import to the top of your program:
import tkinter comme tk
de tkinter.filedialog import askopenfilename
window = tk.Tk()
window.title("Simple Text Editor")
window.rowconfigure(0, minsize=800, weight=1)
window.columnconfigure(1, minsize=800, weight=1)
txt_edit = tk.Texte(window)
fr_buttons = tk.Cadre(window)
btn_open = tk.Bouton(fr_buttons, text="Open")
btn_save = tk.Bouton(fr_buttons, text="Save As...")
Next, add the definition of open_file()
just below the import statements:
import tkinter comme tk
de tkinter.filedialog import askopenfilename
def open_file():
"""Open a file for editing."""
filepath = askopenfilename(
filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")]
)
si ne pas filepath:
revenir
txt_edit.delete("1.0", tk.END)
avec open(filepath, "r") comme input_file:
text = input_file.lis()
txt_edit.insert(tk.END, text)
window.title(f"Simple Text Editor - filepath")
window = tk.Tk()
window.title("Simple Text Editor")
window.rowconfigure(0, minsize=800, weight=1)
window.columnconfigure(1, minsize=800, weight=1)
txt_edit = tk.Texte(window)
fr_buttons = tk.Cadre(window)
btn_open = tk.Bouton(fr_buttons, text="Open")
btn_save = tk.Bouton(fr_buttons, text="Save As...")
Finally, set the command
attribute of btn_opn
à open_file
:
import tkinter comme tk
de tkinter.filedialog import askopenfilename
def open_file():
"""Open a file for editing."""
filepath = askopenfilename(
filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")]
)
si ne pas filepath:
revenir
txt_edit.delete("1.0", tk.END)
avec open(filepath, "r") comme input_file:
text = input_file.lis()
txt_edit.insert(tk.END, text)
window.title(f"Simple Text Editor - filepath")
window = tk.Tk()
window.title("Simple Text Editor")
window.rowconfigure(0, minsize=800, weight=1)
window.columnconfigure(1, minsize=800, weight=1)
txt_edit = tk.Texte(window)
fr_buttons = tk.Cadre(window)
btn_open = tk.Bouton(fr_buttons, text="Open", command=open_file)
btn_save = tk.Bouton(fr_buttons, text="Save As...")
Save the file and run it to check that everything is working. Then try opening a text file!
Avec btn_open
working, it’s time to work on the function for btn_save
. This needs to open a save file dialog box so that the user can choose where they would like to save the file. You’ll use the asksaveasfilename
dialog in the tkinter.filedialog
module for this. This function also needs to extract the text currently in txt_edit
and write this to a file at the selected location. Here’s a function that does just this:
1 def save_file():
2 """Save the current file as a new file."""
3 filepath = asksaveasfilename(
4 defaultextension="txt",
5 filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")],
6 )
sept si ne pas filepath:
8 revenir
9 avec open(filepath, "w") comme output_file:
dix text = txt_edit.avoir("1.0", tk.END)
11 output_file.écrire(text)
12 window.title(f"Simple Text Editor - filepath")
Here’s how this code works:
- Lines 3 to 6 use the
asksaveasfilename
dialog box to get the desired save location from the user. The selected file path is stored in thefilepath
variable. - Lines 7 and 8 check to see if the user closes the dialog box or clicks the Annuler bouton. If so, then
filepath
will beAucun
, and the function will return without executing any of the code to save the text to a file. - Line 9 creates a new file at the selected file path.
- Line 10 extracts the text from
txt_edit
avec.get()
method and assigns it to the variabletext
. - Line 11 writes
text
to the output file. - Line 12 updates the title of the window so that the new file path is displayed in the window title.
Now you can update the program so that btn_save
calls save_file()
when it’s clicked. Again, there are a few things you need to do in order to update the program. First, import asksaveasfilename()
de tkinter.filedialog
by updating the import at the top of your script, like so:
import tkinter comme tk
de tkinter.filedialog import askopenfilename, asksaveasfilename
def open_file():
"""Open a file for editing."""
filepath = askopenfilename(
filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")]
)
si ne pas filepath:
revenir
txt_edit.delete(1.0, tk.END)
avec open(filepath, "r") comme input_file:
text = input_file.lis()
txt_edit.insert(tk.END, text)
window.title(f"Simple Text Editor - filepath")
window = tk.Tk()
window.title("Simple Text Editor")
window.rowconfigure(0, minsize=800, weight=1)
window.columnconfigure(1, minsize=800, weight=1)
txt_edit = tk.Texte(window)
fr_buttons = tk.Cadre(window, relief=tk.RAISED, bd=2)
btn_open = tk.Bouton(fr_buttons, text="Open", command=open_file)
btn_save = tk.Bouton(fr_buttons, text="Save As...")
btn_open.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
btn_save.grid(row=1, column=0, sticky="ew", padx=5)
fr_buttons.grid(row=0, column=0, sticky="ns")
txt_edit.grid(row=0, column=1, sticky="nsew")
window.mainloop()
Next, add the definition of save_file()
just below the open_file()
definition:
import tkinter comme tk
de tkinter.filedialog import askopenfilename, asksaveasfilename
def open_file():
"""Open a file for editing."""
filepath = askopenfilename(
filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")]
)
si ne pas filepath:
revenir
txt_edit.delete(1.0, tk.END)
avec open(filepath, "r") comme input_file:
text = input_file.lis()
txt_edit.insert(tk.END, text)
window.title(f"Simple Text Editor - filepath")
def save_file():
"""Save the current file as a new file."""
filepath = asksaveasfilename(
defaultextension="txt",
filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")],
)
si ne pas filepath:
revenir
avec open(filepath, "w") comme output_file:
text = txt_edit.avoir(1.0, tk.END)
output_file.écrire(text)
window.title(f"Simple Text Editor - filepath")
window = tk.Tk()
window.title("Simple Text Editor")
window.rowconfigure(0, minsize=800, weight=1)
window.columnconfigure(1, minsize=800, weight=1)
txt_edit = tk.Texte(window)
fr_buttons = tk.Cadre(window, relief=tk.RAISED, bd=2)
btn_open = tk.Bouton(fr_buttons, text="Open", command=open_file)
btn_save = tk.Bouton(fr_buttons, text="Save As...")
btn_open.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
btn_save.grid(row=1, column=0, sticky="ew", padx=5)
fr_buttons.grid(row=0, column=0, sticky="ns")
txt_edit.grid(row=0, column=1, sticky="nsew")
window.mainloop()
Finally, set the command
attribute of btn_save
à save_file
:
import tkinter comme tk
de tkinter.filedialog import askopenfilename, asksaveasfilename
def open_file():
"""Open a file for editing."""
filepath = askopenfilename(
filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")]
)
si ne pas filepath:
revenir
txt_edit.delete(1.0, tk.END)
avec open(filepath, "r") comme input_file:
text = input_file.lis()
txt_edit.insert(tk.END, text)
window.title(f"Simple Text Editor - filepath")
def save_file():
"""Save the current file as a new file."""
filepath = asksaveasfilename(
defaultextension="txt",
filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")],
)
si ne pas filepath:
revenir
avec open(filepath, "w") comme output_file:
text = txt_edit.avoir(1.0, tk.END)
output_file.écrire(text)
window.title(f"Simple Text Editor - filepath")
window = tk.Tk()
window.title("Simple Text Editor")
window.rowconfigure(0, minsize=800, weight=1)
window.columnconfigure(1, minsize=800, weight=1)
txt_edit = tk.Texte(window)
fr_buttons = tk.Cadre(window, relief=tk.RAISED, bd=2)
btn_open = tk.Bouton(fr_buttons, text="Open", command=open_file)
btn_save = tk.Bouton(fr_buttons, text="Save As...", command=save_file)
btn_open.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
btn_save.grid(row=1, column=0, sticky="ew", padx=5)
fr_buttons.grid(row=0, column=0, sticky="ns")
txt_edit.grid(row=0, column=1, sticky="nsew")
window.mainloop()
Save the file and run it. You’ve now got a minimal yet fully-functional text editor!
You can expand the code block below to see the full script:
Here’s the full script for your reference:
import tkinter comme tk
de tkinter.filedialog import askopenfilename, asksaveasfilename
def open_file():
"""Open a file for editing."""
filepath = askopenfilename(
filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")]
)
si ne pas filepath:
revenir
txt_edit.delete(1.0, tk.END)
avec open(filepath, "r") comme input_file:
text = input_file.lis()
txt_edit.insert(tk.END, text)
window.title(f"Simple Text Editor - filepath")
def save_file():
"""Save the current file as a new file."""
filepath = asksaveasfilename(
defaultextension="txt",
filetypes=[([([([("Text Files", "*.txt"), ("All Files", "*.*")],
)
si ne pas filepath:
revenir
avec open(filepath, "w") comme output_file:
text = txt_edit.avoir(1.0, tk.END)
output_file.écrire(text)
window.title(f"Simple Text Editor - filepath")
window = tk.Tk()
window.title("Simple Text Editor")
window.rowconfigure(0, minsize=800, weight=1)
window.columnconfigure(1, minsize=800, weight=1)
txt_edit = tk.Texte(window)
fr_buttons = tk.Cadre(window, relief=tk.RAISED, bd=2)
btn_open = tk.Bouton(fr_buttons, text="Open", command=open_file)
btn_save = tk.Bouton(fr_buttons, text="Save As...", command=save_file)
btn_open.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
btn_save.grid(row=1, column=0, sticky="ew", padx=5)
fr_buttons.grid(row=0, column=0, sticky="ns")
txt_edit.grid(row=0, column=1, sticky="nsew")
window.mainloop()
You’ve now built two GUI applications in Python and applied many of the topics you’ve learned about throughout this tutorial. That’s no small achievement, so take some time to feel good about what you’ve done. You’re now ready to tackle some applications on your own!
Conclusion
In this tutorial, you learned how to get started with Python GUI programming. Tkinter is a compelling choice for a Python GUI framework because it’s built into the Python standard library, and it’s relatively painless to make applications with this framework.
Throughout this tutorial, you’ve learned several important Tkinter concepts:
- How to work with widgets
- How to control your application layout with geometry managers
- How to make your applications interactive
- How to use five basic Tkinter widgets (
Étiquette
,Bouton
,Entrée
,Texte
, etCadre
)
Now that you’ve mastered the foundations of Python GUI programming with Tkinter, the next step is to build some of your own applications. What will you create? Share your fun projects down in the comments below!
Ressources supplémentaires
In this tutorial, you touched on just the foundations of creating Python GUI applications with Tkinter. There are a number of additional topics that aren’t covered here. In this section, you’ll find some of the best resources available to help you continue on your journey.
Tkinter References
Here are some official resources to check out:
- The official Python Tkinter tutorial covers Python’s Tkinter module in moderate depth. It’s written for more advanced Python developers and is not the best resource for beginners.
- Tkinter 8.5 reference: a GUI for Python is an extensive reference covering the majority of the Tkinter module. It’s exhaustive, but it’s written in the reference style without commentary or examples.
- The Tk Commands reference is the definitive guide to commands in the Tk library. It’s written for the Tcl language, but it answers a lot of questions about why things work the way they do in Tkinter. The official Python docs have a section on mapping basic Tk into Tkinter that’s indispensable when you’re reading the Tk Commands doc.
Additional Widgets
In this tutorial, you learned about the Étiquette
, Bouton
, Entrée
, Texte
, et Cadre
widgets. There are several other widgets in Tkinter, all of which are essential for building real-world applications. Here are some resources to continue learning about widgets:
- The TkDocs Tkinter Tutorial is a fairly comprehensive guide for Tk, the underlying code library used by Tkinter. Examples are presented in Python, Ruby, Perl, and Tcl. You can find several examples of widgets beyond those covered here in two sections:
- Basic Widgets covers the same widgets as this tutorial, plus a few more.
- More Widgets covers several additional widgets.
- The official Python docs have three sections covering additional widgets:
- ttk themed widgets covers the Tk themed widget set.
- Extension widgets for Tk covers widgets in the Tk Interface Extension set.
- Scrolled Text Widget details a
Texte
widget combined with a vertical scroll bar.
Application Distribution
Once you’ve created an application with Tkinter, you probably want to distribute that to your colleagues and friends. Here are some tutorials to get you going with that process:
Other GUI Frameworks
Tkinter is not your only choice for a Python GUI framework. If Tkinter doesn’t meet the needs of your project, then here are some other frameworks to consider:
[ad_2]