#1 Le 24/03/2019, à 13:11
- kholo
[résolu] subtilité python ; image dans tkinter
Bonjour,
de la page de Fabrice Sincère
j'ai pris le code Exemple n°8 pour afficher des images pour en faire une class
qui affiche d'autres type d'images que les gif
donc j'ai ajouté PIL et nettoyé un peu le code
code origine :
# script lecture_gif.py
#(C) Fabrice Sincère
from tkinter import *
import tkinter.messagebox
import tkinter.filedialog
def Ouvrir():
Canevas.delete(ALL) # on efface la zone graphique
filename = tkinter.filedialog.askopenfilename(title="Ouvrir une image",filetypes=[('gif files','.gif'),('all files','.*')])
print(filename)
photo = PhotoImage(file=filename)
gifdict[filename] = photo # référence
print(gifdict)
Canevas.create_image(0,0,anchor=NW,image=photo)
Canevas.config(height=photo.height(),width=photo.width())
Mafenetre.title("Image "+str(photo.width())+" x "+str(photo.height()))
def Fermer():
Canevas.delete(ALL)
Mafenetre.title("Image")
def Apropos():
tkinter.messagebox.showinfo("A propos","Tutorial Python Tkinter\n(C) Fabrice Sincère")
# Main window
Mafenetre = Tk()
Mafenetre.title("Image")
# Création d'un widget Menu
menubar = Menu(Mafenetre)
menufichier = Menu(menubar,tearoff=0)
menufichier.add_command(label="Ouvrir une image",command=Ouvrir)
menufichier.add_command(label="Fermer l'image",command=Fermer)
menufichier.add_command(label="Quitter",command=Mafenetre.destroy)
menubar.add_cascade(label="Fichier", menu=menufichier)
menuaide = Menu(menubar,tearoff=0)
menuaide.add_command(label="A propos",command=Apropos)
menubar.add_cascade(label="Aide", menu=menuaide)
# Affichage du menu
Mafenetre.config(menu=menubar)
# Création d'un widget Canvas
Canevas = Canvas(Mafenetre)
Canevas.pack(padx=5,pady=5)
# Utilisation d'un dictionnaire pour conserver une référence
gifdict={}
Mafenetre.mainloop()
mon code issue de ce code
#!/usr/bin/env python3
# -*- coding: UTF8 -*-
"""
# script lecture_gif.py
#(C) Fabrice Sincère
modifié pour les images d'autres formats
"""
import tkinter as tk
import tkinter.messagebox
import tkinter.filedialog as fd
from PIL.ImageTk import PhotoImage
class Display_Image(tk.Tk):
""" afficheur d'image """
def __init__(self):
""" init """
# tk.Tk.__init__(self)
super().__init__()
self.title("Image")
self.affiche_menu()
self.canevas = tk.Canvas(self)
self.canevas.pack(padx=5,pady=5)
self.imgdict = {} # dictionnaire pour conserver une référence
def ouvrir_image(self):
""" Ouvrir image """
self.canevas.delete(tk.ALL) # on efface la zone graphique
titre = "Ouvrir une image"
fitres = [('all files','.*'), ('gif files','.gif')]
filename = fd.askopenfilename(title=titre,filetypes=fitres)
# photo = tk.PhotoImage(file=filename) # PhotoImage de tk
photo = PhotoImage(file=filename) # PhotoImage de PIL
self.imgdict[filename] = photo # référence
self.canevas.create_image(0,0,anchor=tk.NW,image=photo)
self.canevas.config(height=photo.height(),width=photo.width())
self.title("Image "+str(photo.width())+" x "+str(photo.height()))
def fermer_image(self):
""" Fermer image"""
self.canevas.delete(tk.ALL)
self.title("Image")
def fenetre_a_propos(self):
""" fenetre Apropos """
titre, message = "A propos", "Tutorial Python Tkinter\n(C) Fabrice Sincère"
tkinter.messagebox.showinfo(titre, message)
def affiche_menu(self):
""" Création d'un widget Menu """
menubar = tk.Menu(self)
menufichier = tk.Menu(menubar,tearoff=0)
menufichier.add_command(label="Ouvrir une image",command=self.ouvrir_image)
menufichier.add_command(label="Fermer l'image",command=self.fermer_image)
menufichier.add_command(label="Quitter",command=self.destroy)
menubar.add_cascade(label="Fichier", menu=menufichier)
menuaide = tk.Menu(menubar,tearoff=0)
menuaide.add_command(label="A propos",command=self.fenetre_a_propos)
menubar.add_cascade(label="Aide", menu=menuaide)
#Affichage du menu
self.config(menu=menubar)
def run(self):
""" Main window """
self.mainloop()
if __name__ == "__main__":
fenetre = Display_Image()
fenetre.run()
c'est comme ça que je me suis rendu compte que ce code utilise un dictionnaire qui me semblait il, ne sert à rien
self.imgdict = {} # dictionnaire pour conserver une référence
puis
self.imgdict[filename] = photo # référence
donc je commente ces deux lignes et l'image ne s'affiche plus dans la fenêtre qui pourtant se met bien à la dimension
dans le code d'origine ce dico s'appelle gifdict mais cela ne change rien en soit
j'ai loupé un truc ?
Dernière modification par kholo (Le 26/03/2019, à 08:57)
Hors ligne
#2 Le 26/03/2019, à 08:56
- kholo
Re : [résolu] subtilité python ; image dans tkinter
Voici ce qui doit être la réponse :
... j'ai eu grâce à Fabrice Sincère une partie voire la réponse à cette question... alors je la partage :
dans ma version avec le passage en classe j'ai utilisé une variable locale pour créer l'objet PhotoImage. Cette variable doit être détruite par le Garbage Collector à la fin de la fonction et l'image "disparaît" (ou plutôt sa référence).
Avec la variable locale, le fait de mettre l'image dans un objet en référence permet de conserver le référencement actif. Pour les versions en ligne ou en fonction, un objet liste ou dico conserve l'image
Pour ma version en Class, le passage de l'objet PhotoImage peut être simplement conservé en rendant la variable locale à la classe (self) plutôt qu'à la fonction.
Ainsi plus besoin de liste, de Dico ou même de variable globale ! Subtile !
je partage ici les codes de Fabrice Sincère que je remercie ici publiquement:
UNE solution en classe :
#!/usr/bin/env python3
# -*- coding: UTF8 -*-
"""
# script lecture_gif.py
# (C) Fabrice Sincère
# (C) kholo (encapsulation dans une classe)
modifié pour les images d'autres formats
"""
import tkinter as tk
import tkinter.messagebox
import tkinter.filedialog as fd
#from PIL.ImageTk import PhotoImage
class Display_Image(tk.Tk):
""" afficheur d'image """
def __init__(self):
""" init """
# tk.Tk.__init__(self)
super().__init__()
self.title("Image")
self.affiche_menu()
self.canevas = tk.Canvas(self)
self.canevas.pack(padx=5,pady=5)
def ouvrir_image(self):
""" Ouvrir image """
self.canevas.delete(tk.ALL) # on efface la zone graphique
titre = "Ouvrir une image"
fitres = [('all files','.*'), ('gif files','.gif')]
filename = fd.askopenfilename(title=titre,filetypes=fitres)
self.photo = tk.PhotoImage(file=filename) # PhotoImage de tk
#self.photo = PhotoImage(file=filename) # PhotoImage de PIL pour ouvrir plus de formats que tk
self.canevas.create_image(0,0,anchor=tk.NW,image=self.photo)
self.canevas.config(height=self.photo.height(),width=self.photo.width())
self.title("Image "+str(self.photo.width())+" x "+str(self.photo.height()))
def fermer_image(self):
""" Fermer image"""
self.canevas.delete(tk.ALL)
self.title("Image")
def fenetre_a_propos(self):
""" fenetre Apropos """
titre, message = "A propos", "Tutorial Python Tkinter\n(C) Fabrice Sincère ; Cyril Ury"
tkinter.messagebox.showinfo(titre, message)
def affiche_menu(self):
""" Création d'un widget Menu """
menubar = tk.Menu(self)
menufichier = tk.Menu(menubar,tearoff=0)
menufichier.add_command(label="Ouvrir une image",command=self.ouvrir_image)
menufichier.add_command(label="Fermer l'image",command=self.fermer_image)
menufichier.add_command(label="Quitter",command=self.destroy)
menubar.add_cascade(label="Fichier", menu=menufichier)
menuaide = tk.Menu(menubar,tearoff=0)
menuaide.add_command(label="A propos",command=self.fenetre_a_propos)
menubar.add_cascade(label="Aide", menu=menuaide)
#Affichage du menu
self.config(menu=menubar)
def run(self):
""" Main window """
self.mainloop()
if __name__ == "__main__":
fenetre = Display_Image()
fenetre.run()
ici, plus de variable englobante, la variable de Class jouant ce rôle
la version de Fabrice qui utilise une variable globale
# script lecture_gif.py
# python 3
#(C) Fabrice Sincère
from tkinter import *
import tkinter.messagebox
import tkinter.filedialog
def Ouvrir():
# variable globale pour conserver une référence
global photo
Canevas.delete(ALL) # on efface la zone graphique
filename = tkinter.filedialog.askopenfilename(title="Ouvrir une image",filetypes=[('gif files','.gif'),('all files','.*')])
print(filename)
photo = PhotoImage(file=filename)
Canevas.create_image(0,0,anchor=NW,image=photo)
Canevas.config(height=photo.height(),width=photo.width())
Mafenetre.title("Image "+str(photo.width())+" x "+str(photo.height()))
def Fermer():
Canevas.delete(ALL)
Mafenetre.title("Image")
def Apropos():
tkinter.messagebox.showinfo("A propos","Tutorial Python Tkinter\n(C) Fabrice Sincère")
# Main window
Mafenetre = Tk()
Mafenetre.title("Image")
# Création d'un widget Menu
menubar = Menu(Mafenetre)
menufichier = Menu(menubar,tearoff=0)
menufichier.add_command(label="Ouvrir une image",command=Ouvrir)
menufichier.add_command(label="Fermer l'image",command=Fermer)
menufichier.add_command(label="Quitter",command=Mafenetre.destroy)
menubar.add_cascade(label="Fichier", menu=menufichier)
menuaide = Menu(menubar,tearoff=0)
menuaide.add_command(label="A propos",command=Apropos)
menubar.add_cascade(label="Aide", menu=menuaide)
# Affichage du menu
Mafenetre.config(menu=menubar)
# Création d'un widget Canvas
Canevas = Canvas(Mafenetre)
Canevas.pack(padx=5,pady=5)
Mafenetre.mainloop()
ici la version qui utilise une liste qui, en fin de compte, joue le même rôle que la variable "global" précédente
# script lecture_gif.py
# python 3
#(C) Fabrice Sincère
from tkinter import *
import tkinter.messagebox
import tkinter.filedialog
def Ouvrir():
Canevas.delete(ALL) # on efface la zone graphique
filename = tkinter.filedialog.askopenfilename(title="Ouvrir une image",filetypes=[('gif files','.gif'),('all files','.*')])
print(filename)
photo = PhotoImage(file=filename)
giflist.append(photo) # référence
print(giflist)
Canevas.create_image(0,0,anchor=NW,image=photo)
Canevas.config(height=photo.height(),width=photo.width())
Mafenetre.title("Image "+str(photo.width())+" x "+str(photo.height()))
def Fermer():
Canevas.delete(ALL)
Mafenetre.title("Image")
def Apropos():
tkinter.messagebox.showinfo("A propos","Tutorial Python Tkinter\n(C) Fabrice Sincère")
# Main window
Mafenetre = Tk()
Mafenetre.title("Image")
# Création d'un widget Menu
menubar = Menu(Mafenetre)
menufichier = Menu(menubar,tearoff=0)
menufichier.add_command(label="Ouvrir une image",command=Ouvrir)
menufichier.add_command(label="Fermer l'image",command=Fermer)
menufichier.add_command(label="Quitter",command=Mafenetre.destroy)
menubar.add_cascade(label="Fichier", menu=menufichier)
menuaide = Menu(menubar,tearoff=0)
menuaide.add_command(label="A propos",command=Apropos)
menubar.add_cascade(label="Aide", menu=menuaide)
# Affichage du menu
Mafenetre.config(menu=menubar)
# Création d'un widget Canvas
Canevas = Canvas(Mafenetre)
Canevas.pack(padx=5,pady=5)
# Utilisation d'une liste pour conserver une référence
giflist = []
Mafenetre.mainloop()
... et je passe fièrement en résolu !
Hors ligne