Avec Custom Tkinter et OpenCV
Lorsque j’étais en deuxième année d’études en génie informatique, je me suis vraiment intéressé au développement d’applications (en particulier des applications Web) et j’expérimentais différents frameworks pour différentes langues, etc.
Lors de la pratique de mes compétences en front-end, j’ai développé une application générateur/décodeur de code QR en Python avec Tkinter que j’ai ensuite améliorée avec Tkinter personnalisé, un module basé sur Tkinter qui est utilisé pour développer des interfaces graphiques pour les applications python.
Comme d’habitude, la première étape consistait à importer les bibliothèques que nous utiliserons pour développer l’application.
Pour ce projet, j’ai utilisé OpenCV (cv2) et QRcode pour le code barre, tkinter
et personnalisé tkinter
pour l’interface graphique et le module os pour localiser le dossier de téléchargements de l’utilisateur. Les modules utilisés peuvent être installés avec les lignes suivantes :
pip install opencv-python
pip install qrcode
pip install tkinter
pip install customtkinter
Une fois que nous les avons installés, nous pouvons maintenant les importer. De Tkinter, nous importerons uniquement PhotoImage
pour l’icône et filedialog
pour ouvrir une fenêtre de dialogue de fichier lors du décodage des codes QR. Nous importons Tkinter personnalisé pour l’interface graphique, le cv2
et QRcode pour traiter et générer le QR code :
from tkinter import PhotoImage, filedialog
import customtkinter
import qrcode
import cv2
import os
Maintenant que nous avons nos bibliothèques, la première chose que nous voudrons faire dans tout projet incluant un frontal est d’avoir une fenêtre vierge à afficher sur notre écran. Commençons donc par définir notre App
classe utilisant customtkinter.CTk
comme notre classe de base. CTk
est la coutume tkinter
équivalent de Tk
qui est la classe du corps principal de notre application (fenêtre) et qui sera la fenêtre racine de notre application.
Tout d’abord, pour ajouter un titre, nous utilisons le title
attribut de soi (la racine de notre application).
Après avoir ajouté un titre à notre application, pour éliminer l’icône (cette partie est facultative, vous ne voulez pas vous en soucier), nous utilisons d’abord PhotoImage
pour charger l’image, puis utilisez le iconbitmap
attribut pour définir une icône sur notre application (vous pouvez utiliser n’importe quelle icône avec l’extension de fichier « ico »).
Enfin, pour définir les dimensions de notre fenêtre d’application, nous utilisons le geometry
attribut pour les définir. Vous définissez les dimensions sous la forme d’une chaîne (300x300)
.
Pour cette application, j’ai utilisé les dimensions 300 par 300 car elles semblaient être des dimensions appropriées.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()self.title("QR Code Generator")
icon = PhotoImage("icon.ico")
self.iconbitmap(icon)
height = 300
width = 300
self.geometry(f"{width}x{height}")
if __name__ == "__main__":
app = App()
app.mainloop()
Une fois que nous avons exécuté le code, nous devrions voir une fenêtre vide de 300 par 300 assez semblable à la suivante :
Maintenant que nous pouvons obtenir une fenêtre vierge à afficher sur nos écrans, nous pouvons maintenant ajouter des éléments. Tout d’abord, nous ajouterons un cadre, qui est essentiellement un conteneur à l’intérieur de la fenêtre racine parente (le conteneur parent).
Nous appellerons le CTkFrame
pour ajouter le cadre à notre application. Nous fixerons self
(racine dans notre cas) comme son master
(conteneur parent), puis nous utiliserons le pack
attribut pour l’afficher sur notre écran. Avant de le finaliser cependant, nous ajouterons 20 unités de rembourrages sur les quatre côtés pour le rendre un peu moins à l’étroit en utilisant padx
et pady
, et nous le ferons remplir « dans les deux » sens et se développer. Notre classe et notre application devraient ressembler à ce qui suit.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()self.title("QR Code Generator")
icon = PhotoImage("icon.ico")
self.iconbitmap(icon)
height = 300
width = 300
self.geometry(f"{width}x{height}")
frame = customtkinter.CTkFrame(master=self)
frame.pack(pady=20,padx=20, fill="both", expand=True)
Maintenant que nous avons un conteneur, nous allons ajouter une étiquette (élément de texte) en utilisant CTkLabel
. Il va afficher un texte disant “QR Code\nGenerator & Decoder”
(\n est pour une nouvelle ligne), il utilisera la police « Berlin Sans FB » avec une taille de police de 18.
Après l’avoir appelé, nous allons encore une fois utiliser le pack
attribut pour l’afficher sur notre application. Une fois de plus, nous allons lui donner des rembourrages de 10 unités à la fois horizontalement et verticalement en utilisant padx
et pady
. Notre application devrait maintenant ressembler à ceci.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()self.title("QR Code Generator")
icon = PhotoImage("icon.ico")
self.iconbitmap(icon)
height = 300
width = 300
self.geometry(f"{width}x{height}")
frame = customtkinter.CTkFrame(master=self)
frame.pack(pady=20,padx=20, fill="both", expand=True)
label = customtkinter.CTkLabel(master=frame, text="QR Code\nGenerator & Decoder", font=("Berlin Sans FB", 18))
label.pack(pady=10, padx=10)
Noter: Dans Tkinter personnalisé ou tkinter
vous devriez pouvoir utiliser n’importe quelle police installée sur votre ordinateur. Pour Windows, si vous souhaitez connaître les polices que vous avez installées sur votre ordinateur, vous pouvez accéder à la barre de recherche de Windows et taper « police » et la vérifier dans les paramètres de police.
Maintenant que nous savons comment ajouter un widget, la première chose que nous voulons faire est d’ajouter un widget d’entrée en utilisant CTkEntry
suivi de l’ajout de deux boutons à l’aide CTkButton
un pour générer un code qr et un pour décoder les codes qr.
Pour notre champ de saisie, nous allons définir frame
comme son parent (maître) et il va avoir un width
de 200. Il y aura un texte d’espace réservé qui dit “Enter Text Here”
et pour centrer le texte à l’intérieur du champ de saisie, nous utiliserons justify="center"
.
Enfin, nous voulons qu’il utilise la police « Consolas » avec une taille de police de 16. Avant de l’afficher, cependant, il y aura 5 unités de rembourrage supérieur et inférieur aux côtés de 5 unités de rembourrage interne que nous ajouterons dans toutes les directions en utilisant ipadx
et ipady
.
Pour nos boutons, nous utiliserons le CTkButton
. Pour le premier, son conteneur parent va encore une fois être frame
il va afficher un texte de “Generate Code”
et utilisez la police « Berlin Sans FB » avec une taille de police de 16. Nous allons pack
avec des rembourrages x et y de 10 et un rembourrage interne de 5 dans toutes les directions.
Pour le deuxième bouton, nous allons copier et coller le premier avec un nom de variable différent et un texte de « Decode QR Code”
. À ce stade, notre code et notre application devraient ressembler un peu à ceci.
class App(customtkinter.CTk):
def __init__(self):
super().__init__()#Previous code
frame = customtkinter.CTkFrame(master=self)
frame.pack(pady=20,padx=20, fill="both", expand=True)
label = customtkinter.CTkLabel(master=frame, text="QR Code\nGenerator & Decoder", font=("Berlin Sans FB", 18))
label.pack(pady=10, padx=10)
url_input = customtkinter.CTkEntry(master=frame, placeholder_text="Enter Text Here",justify="center",width=200, font=("Consolas", 16))
url_input.pack(ipady=5,ipadx=5,pady=5)
btn_gen = customtkinter.CTkButton(master=frame, text="Generate Code", font=("Berlin Sans FB", 16))
btn_gen.pack(ipady=5,ipadx=5,pady=10,padx=10)
btn_dec = customtkinter.CTkButton(master=frame, text="Decode QR Code", font=("Berlin Sans FB", 16))
btn_dec.pack(ipady=5,ipadx=5,pady=10,padx=10)
Maintenant que nous en avons terminé avec la fenêtre principale de l’application, nous pouvons maintenant travailler sur la fonctionnalité. Mais avant cela, nous allons créer une fenêtre contextuelle que nous utiliserons plus tard lors de l’ajout de fonctionnalités.
Nous commençons par définir une fonction appelée pop_up, elle a un seul argument de chaîne de msg, qui est le message qui sera affiché sur la fenêtre pop-up.
Dans la fonction, nous allons d’abord définir une racine pour la fenêtre contextuelle en utilisant CTkTopLevel
. Nous lui ajoutons le titre de “For you!”
(puisque c’est un message pour l’utilisateur, j’ai pensé que cela conviendrait 😀 ), verrouillez sa taille à 300 par 180. Nous le faisons en définissant un minsize
et maxsize
qui est égal à un autre avant d’ajouter une icône de la même manière que nous l’avons fait dans la fenêtre principale de l’application (en utilisant iconbitmap
). Le code devrait ressembler à ceci.
def pop_up(msg:str):
win = customtkinter.CTkToplevel()
win.wm_title("For you!")
win.maxsize(300,180)
win.minsize(300,180)
icon = PhotoImage("code.ico")
win.iconbitmap(icon)
Pour tester le pop-up, nous pouvons l’appeler comme le command
de l’un de nos boutons comme ci-dessous. Veuillez noter que lors de l’appel de la fonction, nous devons utiliser lambda
puisque nous devons passer un argument à cette fonction.
btn_gen = customtkinter.CTkButton(master=frame, text="Generate Code", font=("Berlin Sans FB", 16), command=lambda:pop_up("dummy string that won't be displayed"))
btn_gen.pack(ipady=5,ipadx=5,pady=10,padx=10)
La fenêtre contextuelle suivante devrait apparaître une fois que nous avons cliqué sur le bouton.
Maintenant que nous pouvons afficher la fenêtre contextuelle, nous pouvons commencer à y ajouter des éléments.
Tout d’abord, nous ajouterons un cadre avec 20 unités de remplissage dans chaque direction, une étiquette qui affichera l’argument d’entrée qui utilise « Berlin Sans FB » comme police avec une taille de police de 16 et a 10 unités de remplissage dans chaque direction, et enfin un bouton qui fermera la fenêtre pop-up une fois pressé. Nous y parvenons en appelant win.destroy
qui se fermera (se détruira) une fois appelé.
Enfin, donnez à notre bouton des rembourrages internes de 5 dans chaque direction, des rembourrages externes de 10 dans chaque direction, un texte d’affichage de “OK”
choix de police de « Berlin Sans FB » avec une taille de police de 16. Une fois que nous avons tout fait, le code et la fenêtre contextuelle devraient ressembler à ceux ci-dessous.
def pop_up(msg:str):
win = customtkinter.CTkToplevel()
win.wm_title("For you!")
win.maxsize(300,180)
win.minsize(300,180)
icon = PhotoImage("code.ico")
win.iconbitmap(icon)frame = customtkinter.CTkFrame(master=win)
frame.pack(pady=20, padx=20,fill="both", expand=True)
label = customtkinter.CTkLabel(master=frame, text=msg, font=("Berlin Sans FB", 16))
label.pack(pady=10, padx=10)
btn = customtkinter.CTkButton(master=frame, text="OK", font=("Berlin Sans FB", 16),command=win.destroy)
btn.pack(ipady=5,ipadx=5,pady=10,padx=10)
Noter: La largeur de la fenêtre était peut-être un peu trop petite pour la chaîne affichée, n’hésitez donc pas à l’agrandir.
Maintenant que nous avons terminé toutes les parties liées à l’interface graphique, nous pouvons maintenant mettre en œuvre la fonctionnalité de l’application, ce qui peut surprendre, mais c’est la partie la plus simple de l’application.
Pour la génération de code QR, nous commencerons par définir une fonction appelée generate_code
. Il aura un seul argument de type chaîne appelé url
. Utilisant qrcode.make
nous le transformerons en code QR. Avant de l’enregistrer, nous devons d’abord localiser les téléchargements des utilisateurs (cette partie est facultative mais il était plus logique de l’enregistrer dans les téléchargements) en utilisant os.getenv(‘USERPROFILE’)
et en ajoutant “\\Downloads”
jusqu’au bout.
Après cela, nous sauvegardons notre code en utilisant code.save
. Une fois que tout est fait, le pop-up apparaîtra en disant « Le code est à C://user/downloads/folder
”. Le code devrait ressembler à ce qui suit.
def generate_code(url:str):
code = qrcode.make(url)
downloads = f"{os.getenv('USERPROFILE')}\\Downloads"
code.save(downloads + '/code.png')
pop_up("The QR code is at >>\n" + downloads)
Avant de pouvoir l’utiliser, nous devons cependant changer la commande de notre bouton de pop_up
à generate_code
et obtenez la chaîne de la zone de saisie. Pour obtenir la chaîne de la zone de saisie, nous pouvons simplement utiliser entry.get
qui renvoie la chaîne dans le champ de saisie et la transmet comme argument à notre fonction.
btn_gen = customtkinter.CTkButton(master=frame, text="Generate Code", font=("Berlin Sans FB", 16), command=lambda:generate_code(url_input.get()))
btn_gen.pack(ipady=5,ipadx=5,pady=10,padx=10)
Une fois que tout est fait, ce qui suit devrait être le résultat.
La dernière chose que nous devons faire maintenant que nous en avons fini avec tout le reste est d’ajouter la fonctionnalité de décodage à notre application.
Tout d’abord, nous devons pouvoir sélectionner un fichier contenant un code qr à décoder. Pour ce faire, nous utiliserons le filedialog
de tkinter
avec les types de fichiers de ((“image”, “.jpg”), (“image”, “.jpeg”), (“image”, “.png”))
. Une fois que nous pourrons sélectionner un fichier à décoder, nous utiliserons cv2.QRCodeDetector
pour le décoder. Avant de pouvoir le faire, nous devons cependant utiliser cv2.imread
pour le charger en tant qu’image dans notre détecteur. Une fois que tout est fait, un pop_up affichera le texte à l’intérieur du code.
def decode():
qr_code = filedialog.askopenfilename(initialdir="/", title="Select File", filetypes=(("image", ".jpg"), ("image", ".jpeg"), ("image", ".png")))
code_detector = cv2.QRCodeDetector()
code_str, _, _ = code_detector.detectAndDecode(cv2.imread(qr_code))
pop_up(code_str)
Après avoir ajouté cette fonction en tant que commande de notre bouton de décodage, notre application peut désormais décoder les codes QR.
Et enfin, nous avons une application entièrement fonctionnelle. Si vous souhaitez obtenir le code complet, vous pouvez le trouver sur :