Affichage successif d'images sur tkinter dans même cavnas
Résolu/Fermé
pycarpe
Messages postés
16
Date d'inscription
lundi 24 janvier 2022
Statut
Membre
Dernière intervention
9 août 2022
-
24 janv. 2022 à 14:00
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 26 janv. 2022 à 14:16
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 26 janv. 2022 à 14:16
A voir également:
- Affichage successif d'images sur tkinter dans même cavnas
- Affichage double ecran - Guide
- Des images - Guide
- Windows 11 affichage classique - Guide
- Problème affichage fenêtre windows 10 - Guide
- Modifier taille affichage outlook - Forum Outlook
7 réponses
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
Modifié le 24 janv. 2022 à 14:21
Modifié le 24 janv. 2022 à 14:21
Bonjour,
Peu importe le framework utilisé (ici Tk), l'idée générale consiste à un timer qui lorsqu'il expire, lève un événement que tu rattrapes à l'aide d'une fonction dédiée (appelée callback). C'est cette callback qui doit mettre à jour ton image. Ce faisant l'application n'est pas gelée (à cause du
Tu peux t'inspirer de cette discussion qui montre comment faire une horloge en Tk :
Dans cet exemple, la fenêtre est réalisée à l'aide d'une classe. Ce n'est pas obligatoire (comme le montre ton code), mais c'est la manière classique de procéder, donc je te recommande de faire pareil, car ça permet d'avoir un code mieux organiser.
Si tu n'as pas encore vu les classes, c'est juste une manière de déclarer un type personnalisé auquel est attaché un ensemble de fonctions (appelées méthodes). En fait, tu utilises déjà des classes sans le savoir (par exemple dans ton code
Quand tu crées une instance d'un objet (e.g.
La partie intéressante qui réalise cette notion de "timer" est réalisé dans la fonction
Par rapport à ton code, l'idéal serait de passer le chemin (
Bonne chance
Peu importe le framework utilisé (ici Tk), l'idée générale consiste à un timer qui lorsqu'il expire, lève un événement que tu rattrapes à l'aide d'une fonction dédiée (appelée callback). C'est cette callback qui doit mettre à jour ton image. Ce faisant l'application n'est pas gelée (à cause du
sleep).
Tu peux t'inspirer de cette discussion qui montre comment faire une horloge en Tk :
#!/usr/bin/env python3 # Display UTC. # started with https://docs.python.org/3.4/library/tkinter.html#module-tkinter import tkinter as tk import time def current_iso8601(): """Get current date and time in ISO8601""" # https://en.wikipedia.org/wiki/ISO_8601 # https://xkcd.com/1179/ return time.strftime("%Y%m%dT%H%M%SZ", time.gmtime()) class Application(tk.Frame): def __init__(self, master=None): tk.Frame.__init__(self, master) self.pack() self.createWidgets() def createWidgets(self): self.now = tk.StringVar() self.time = tk.Label(self, font=('Helvetica', 24)) self.time.pack(side="top") self.time["textvariable"] = self.now self.QUIT = tk.Button(self, text="QUIT", fg="red", command=root.destroy) self.QUIT.pack(side="bottom") # initial time display self.onUpdate() def onUpdate(self): # update displayed time self.now.set(current_iso8601()) # schedule timer to call myself after 1 second self.after(1000, self.onUpdate) root = tk.Tk() app = Application(master=root) root.mainloop()
Dans cet exemple, la fenêtre est réalisée à l'aide d'une classe. Ce n'est pas obligatoire (comme le montre ton code), mais c'est la manière classique de procéder, donc je te recommande de faire pareil, car ça permet d'avoir un code mieux organiser.
Si tu n'as pas encore vu les classes, c'est juste une manière de déclarer un type personnalisé auquel est attaché un ensemble de fonctions (appelées méthodes). En fait, tu utilises déjà des classes sans le savoir (par exemple dans ton code
Canvasest une classe,
canvas_logoest une instance de cette classe, et
create_rectangleest une méthode de la classe
Canvas.
Quand tu crées une instance d'un objet (e.g.
canvas = Canvas()), tu appelles le constructeur (méthode
__init__(), qui selon la classe, peut attendre ou non des paramètres). Dans l'exemple de code que j'ai reporté, c'est dans le constructeur appelle la méthode
createWidgetsqui place les composants de la fenêtre. Celle-ci appelle immédiatement
onUpdate(dans ton cas, cela te permettra d'afficher la première image). Note que les noms des méthodes (
createWidgetset
onUpdate) sont arbitraires, tu peux renommer ces méthodes si tu le souhaites.
La partie intéressante qui réalise cette notion de "timer" est réalisé dans la fonction
onUpdate: l'instruction
self.after(1000, self.onUpdate)permet de rappeler dans 1000ms (donc dans 1s) la méthode
self.onUpdate, et donc dans ton cas d'afficher l'image suivante. L'avantage c'est qu'entre temps, ton application n'est pas endormie et donc reste réactive.
Par rapport à ton code, l'idéal serait de passer le chemin (
path) au constructeur. Ça t'éviterait d'avoir une variable globale (qui est une mauvaise habitude de programmation). De même, ce que tu as appelé
varpourrait être une variable interne à ta classe.
Bonne chance
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
Modifié le 26 janv. 2022 à 16:32
Modifié le 26 janv. 2022 à 16:32
Bonjour,
Allez ça m'a permis de découvrir un peu Tk (et ses nombreux écueils :p, personnellement je fais rarement des interfaces graphiques et à choisir je préfère Qt) voici à quoi ça pourrait ressembler :
Ici j'en ai profité pour améliorer un peu le design de ton code même si le code que je partage est selon mes critères encore améliorable (voir fin du message). Par ailleurs, j'importe un peu différemment les objets Tk (c'est plus propre comme je fais car on garde l'espace de nommage et on évite les potentielles collisions entre les noms de classe Tk et les autres).
Explication du programme principal
On commence par regarder le programme principal, après la classe
Ensuite on crée une instance de notre classe
Synchrone vs asynchrone
il est primordial de comprendre que pendant toute la construction, l'application n'est pas encore lancée et le programme fonctionne donc de manière synchrone (il exécute les instructions le plus vite possible les unes à la suite des autres).
Ce n'est que quand on atteindra
Création de l'application (partie synchrone)
Regardons la partie construction (
Au moment de créer notre application, on entre dans
Ensuite je crée un attribut
On prépare aussi le bouton "Ajouter" qui te permettra de voir que ton programme n'est pas gelé par notre timer. Ici aussi, il serait plus judicieux d'utiliser des
Les dimensions de certains widgets sont calculés à partir de
Enfin, on termine le constructeur en armant le premier timer conformément à l'exemple de mon message précédent. À mon avis, c'est un peu bancale car la boucle d'exécution n'est pas encore lancée, donc dire de faire quelque chose dans 1s n'a pas de sens (et d'ailleurs ça lève un message d'avertissement). Ça mériterait de regarder si on ne peut pas faire plus propre et c'est l'une des améliorations à apporter à ce programme.
Une fois que tout ceci est fait, la prochaine instruction du programme principale lance la boucle d'exécution...
Mettre à jour l'image toute les secondes
Une fois dans la boucle d'exécution, le programme attend qu'un événement qui le concerne soit levé. Parmi eux, il y a le clic sur le bouton "Quitter", celui sur le bouton "Ajouter". L'énorme intérêt c'est qu'une boucle d'exécution quand elle est bien faite (et c'est le cas de Tk) n'est pas un
En particulier, la fonction
Tu noteras que j'ai un peu simplifié la mise à jour de l'image en me basant sur cette discussion. Il est important de garder trace du sous-canevas qui a été implicitement lors de l'instruction
Bonne chance
Allez ça m'a permis de découvrir un peu Tk (et ses nombreux écueils :p, personnellement je fais rarement des interfaces graphiques et à choisir je préfère Qt) voici à quoi ça pourrait ressembler :
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import tkinter as tk import time import os IMAGE_DIR = "/home/mando/Downloads" def find(dirname :str): return ( os.path.join(root, name) for (root, dirs, files) in os.walk(dirname, topdown=False) for name in files ) class Application(tk.Frame): def __init__(self, filenames=None, master=None): tk.Frame.__init__(self, master) self.pack(expand=True, fill="both") self.entries_y = 30 print(filenames) self.images = [ tk.PhotoImage(file=filename, master=self if master is None else master) for filename in filenames ] self.image_index = 0 self.create_widgets() # Prepare initial timer self.on_update() def create_widgets(self): if self.images: wi = 90 he = 90 image = self.images[self.image_index] self.canvas_logo = tk.Canvas(self, width = wi, height = he) self.canvas_logo.place(x = wi / 2, y = 0) #self.canvas_logo.create_rectangle(0, 0, 200, 50, fill="green") self.image_container = self.canvas_logo.create_image(wi / 2, he / 2, image=image) self.canvas_logo.pack() self.bu_ajout = tk.Button(self, text = "Ajout", command = self.add_entries) self.bu_ajout.pack(side="top") self.quit = tk.Button(self, text="Quitter", fg="red", command=root.destroy) self.quit.pack(side="bottom") def add_entries(self): self.add_entry("red") self.add_entry("yellow") def add_entry(self, color): canvas = tk.Canvas(self, width=200, height=50) canvas.create_rectangle(0, 0, 200, 50, fill=color) canvas.place(x=0, y=self.entries_y) myentry = tk.Entry(canvas, bd = 3) myentry.place(x = 5, y = 12.5) self.entries_y += 50 def update_image(self): if self.images: image = self.images[self.image_index] self.canvas_logo.itemconfigure(self.image_container, image=image) self.canvas_logo.pack() def on_update(self): if self.images: self.image_index += 1 self.image_index %= len(self.images) self.update_image() self.after(1000, self.on_update) root = tk.Tk() root.geometry("1000x720") #root.config(background='#7720B9') app = Application( filenames = [ f for f in find(IMAGE_DIR) if f.endswith(".gif") ], master = root ) root.mainloop()
Ici j'en ai profité pour améliorer un peu le design de ton code même si le code que je partage est selon mes critères encore améliorable (voir fin du message). Par ailleurs, j'importe un peu différemment les objets Tk (c'est plus propre comme je fais car on garde l'espace de nommage et on évite les potentielles collisions entre les noms de classe Tk et les autres).
Explication du programme principal
On commence par regarder le programme principal, après la classe
Application. Ici je suis exactement l'exemple que je t'ai donné auparavant. Plutôt que de coder en dur le chemin des fichiers, j'ai fait une petite fonction
findqui liste les fichiers
.gifdu dossier
IMAGE_DIR(et dans ses sous-dossiers).
Ensuite on crée une instance de notre classe
Applicationà laquelle je passe le pointeur
root(que tu appelais
win). On en aura besoin au moment de charger les images afin d'éviter l'erreur présentée lis cette discussion. Dans l'idée, les images doivent être chargées par "le bon interpréteur".
Synchrone vs asynchrone
il est primordial de comprendre que pendant toute la construction, l'application n'est pas encore lancée et le programme fonctionne donc de manière synchrone (il exécute les instructions le plus vite possible les unes à la suite des autres).
Ce n'est que quand on atteindra
root.mainloop()que l'application sera réellement lancée et réactive. Cette instruction lance "la boucle d'exécution". On bascule alors en mode asynchrone, c'est à dire que le programme ne "travaille" que lorsque les événements (prévus pour être rattrapés par ton application) sont déclenchés (par exemple, sur un clic de bouton ou dans ton cas, quand le timer expire). Ça veut aussi dire qu'en asynchrone, un
sleepest catastrophique car il gèle pendant tout ce temps l'application. Il est donc à proscrire. Une fois qu'on est en mode asynchrone, il ne faut raisonner qu'en réagissant à des événements (on parle de programmation événementielle, voir cette page -- rien à voir avec le concert de ton groupe préféré).
Création de l'application (partie synchrone)
Regardons la partie construction (
Application.__init__), donc avant que la boucle d'exécution ne soit lancée.
Au moment de créer notre application, on entre dans
__init__. On appelle le constructeur de la classe mère (qu'on récupère via
super()), puis première différence avec ton programme on fait un self.pack(expand=True, fill="both"). Celui-ci fait en sorte que notre
tk.Frameoccupe toute la fenêtre. Ici on devrait selon moi créer un
tk.Canvasprincipal qui pemettrait d'organiser tous les widgets de ta fenêtre. C'est recommandé pour avoir une interface graphique "responsive", c'est à dire dont les composants se réorganisent correctement quand la géométrie de la fenêtre change. Bref, ça vaudrait le coup que tu jettes un œil à tout ça et c'est un des points d'amélioration de ce script.
Ensuite je crée un attribut
self.imagesdans lequel je charge tous les images (formats valides : png, bmp, gif). Si tu veux considérer d'autres images (genre .jpg) il faudra utiliser PIL (voir cette discussion).
On prépare aussi le bouton "Ajouter" qui te permettra de voir que ton programme n'est pas gelé par notre timer. Ici aussi, il serait plus judicieux d'utiliser des
tk.Canvasdans lequel on empilerait les différents widgets que tu crées. J'ai gardé ton code pour que tu t'y retrouves, mais au lieu d'utiliser ta variable globale
var, j'utilise un attribut de classe
self.entries_y. C'est l'un des points qu'il faudrait améliorer.
Les dimensions de certains widgets sont calculés à partir de
heet
wiqui n'ont plus lieu d'être des variables globales. C'est donc un peu plus propre mais pas encore parfait. Il faudrait idéalement les calculer par rapport aux dimensions de ta
tk.Frame. C'est un point que je te laisse améliorer.
Enfin, on termine le constructeur en armant le premier timer conformément à l'exemple de mon message précédent. À mon avis, c'est un peu bancale car la boucle d'exécution n'est pas encore lancée, donc dire de faire quelque chose dans 1s n'a pas de sens (et d'ailleurs ça lève un message d'avertissement). Ça mériterait de regarder si on ne peut pas faire plus propre et c'est l'une des améliorations à apporter à ce programme.
Une fois que tout ceci est fait, la prochaine instruction du programme principale lance la boucle d'exécution...
Mettre à jour l'image toute les secondes
Une fois dans la boucle d'exécution, le programme attend qu'un événement qui le concerne soit levé. Parmi eux, il y a le clic sur le bouton "Quitter", celui sur le bouton "Ajouter". L'énorme intérêt c'est qu'une boucle d'exécution quand elle est bien faite (et c'est le cas de Tk) n'est pas un
while Trueet ne consomme donc pas 100% de CPU en passant son temps à examiner s'il y a eu une activité. Et c'est là toute la force de la programmation événementielle : le programme attend sagement que quelque chose se passe.
En particulier, la fonction
on_updatese déclenche au bout d'une seconde et réarme ce timer à chaque fois à l'aide de
self.after. Au passage elle met à jour l'image. Pour cela on charge directement le bon objet
tk.Image(toutes nos images sont stockées dans
self.images) en faisant un itérant sur nos images (d'où l'incrément) et en repartant en début de liste quand on les a toutes traitées (d'où le modulo) -- on aurait pu aussi remettre le compteur à 0 si
self.image_indexest supérieur ou égale à
len(self.images)(ici, ça revient au même, mais ces deux stratégies ont un comportement différent si l'incrément est plus grand que 1).
Tu noteras que j'ai un peu simplifié la mise à jour de l'image en me basant sur cette discussion. Il est important de garder trace du sous-canevas qui a été implicitement lors de l'instruction
self.image_container = self.canvas_logo.create_image(wi / 2, he / 2, image=image), c'est le premier paramètre attendus par
self.canvas_logo.itemconfigure(...).
Bonne chance
pycarpe
Messages postés
16
Date d'inscription
lundi 24 janvier 2022
Statut
Membre
Dernière intervention
9 août 2022
Modifié le 24 janv. 2022 à 14:55
Modifié le 24 janv. 2022 à 14:55
Merci pour ta diligence. Du coup, si j'ai bien compris, il faut que je joue avec l'horloge de mon pc pour temporiser l'affichage de chaque image c'est bien ca?
Ps : Merci pour le petit rappel pour les class. Mais j'ai pas voulu en utiliser pour cette exemple simple. Mais merci quand même vraiment ca change des autres forums qui ont 0 pédagogies.
Ps : Merci pour le petit rappel pour les class. Mais j'ai pas voulu en utiliser pour cette exemple simple. Mais merci quand même vraiment ca change des autres forums qui ont 0 pédagogies.
pycarpe
Messages postés
16
Date d'inscription
lundi 24 janvier 2022
Statut
Membre
Dernière intervention
9 août 2022
Modifié le 24 janv. 2022 à 17:58
Modifié le 24 janv. 2022 à 17:58
Alors déjà Merci infiniment pour le temps que tu as pris pour détailler les choses. Je ne suis pas sûr d'avoir tout compris mais je vais me pencher dessus jusqu'à que je sois à l'aise avec tout ca.
En effet, j'étais en train de gruger le truc avec un while mais ma consommation était en modéré contre très faible avec ta méthode.
Un grand merci à toi encore. Je n'hésiterai pas à revenir vers toi si j'ai des questions pour ma compréhension si tu as le temps biensûr.
Ps : Ce forum est génial comparé à d'autres que j'ai pu voir. C'est motivant de voir des gens qui se mettent à la place des autres. Car malheureusement certains pensent qui si c'est évident pour eux alors ca doit l'être pour les autres. Ce qui n'est pas forcément le cas.
Donc mille merci. A++++
En effet, j'étais en train de gruger le truc avec un while mais ma consommation était en modéré contre très faible avec ta méthode.
Un grand merci à toi encore. Je n'hésiterai pas à revenir vers toi si j'ai des questions pour ma compréhension si tu as le temps biensûr.
Ps : Ce forum est génial comparé à d'autres que j'ai pu voir. C'est motivant de voir des gens qui se mettent à la place des autres. Car malheureusement certains pensent qui si c'est évident pour eux alors ca doit l'être pour les autres. Ce qui n'est pas forcément le cas.
Donc mille merci. A++++
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
24 janv. 2022 à 18:06
24 janv. 2022 à 18:06
Re bonjour pycarpe,
Concernant la version avec un
Ensuite, un grand merci pour tes compliments qui me vont droit au cœur. C'est le genre de message qui fait bien plaisir et qui donne envie de continuer à être altruiste :-)
Bonne continuation
Concernant la version avec un
while Truec'était modéré car ton programme n'utilisait qu'un CPU parmi tous ceux dont ta machine dispose (mais probablement, saturait ce CPU à 100%), donc si tu as disons 8 CPU tu n'as l'impression d'utiliser "que" 12.5% de CPU :p (ce qui est en réalité énorme !). Et tu comprends bien entendu qu'on peut difficilement se permettre de sacrifier un CPU par application (surtout quand celle-ci ne fait pas de calcul !). Bref, si tu dois retenir une chose, c'est que la programmation événementielle permet précisément d'éviter ça.
Ensuite, un grand merci pour tes compliments qui me vont droit au cœur. C'est le genre de message qui fait bien plaisir et qui donne envie de continuer à être altruiste :-)
- Je bascule ton sujet en résolu, car le problème posé me paraît résolu. Sache qu'en tant qu'auteur de la discussion, c'est quel que chose que tu faire (voir ce lien).
- Si tu as besoin de plus de précisions sur cette discussion, n'hésite pas à poser tes questions. Et si tu rencontres de nouveaux problèmes indépendants, crée une nouvelle discussion.
Bonne continuation
Vous n’avez pas trouvé la réponse que vous recherchez ?
Posez votre question
pycarpe
Messages postés
16
Date d'inscription
lundi 24 janvier 2022
Statut
Membre
Dernière intervention
9 août 2022
25 janv. 2022 à 19:17
25 janv. 2022 à 19:17
Hello, j'espère que tu vas bien?
j'ai pris le temps d'analyser ta méthode pour essayer de bien tout comprendre. Et là je me suis dit "tiens et si je faisais une petite modification pour voir si j'ai bien compris", donc j'ai juste enlevé la fonction find et j'ai juste mis les chemins des fichiers en dur juste pour voir si j'avais le même résultat et j'ai lié l'index à file dans Photoimage au lieu de Photoimage tout court... Je me suis dit que cela allait revenir au même mais à ma grande surprise les images ne se chargent pas et le fait que je ne comprenne pas pourquoi prouve que je n'ai pas tout saisi finalement...
Si tu peux m'éclaircir chef, je pense que cela m'aiderait dans ma recherche de compréhension. Merci d'avance :)
Ci dessous le code modifié :
j'ai pris le temps d'analyser ta méthode pour essayer de bien tout comprendre. Et là je me suis dit "tiens et si je faisais une petite modification pour voir si j'ai bien compris", donc j'ai juste enlevé la fonction find et j'ai juste mis les chemins des fichiers en dur juste pour voir si j'avais le même résultat et j'ai lié l'index à file dans Photoimage au lieu de Photoimage tout court... Je me suis dit que cela allait revenir au même mais à ma grande surprise les images ne se chargent pas et le fait que je ne comprenne pas pourquoi prouve que je n'ai pas tout saisi finalement...
Si tu peux m'éclaircir chef, je pense que cela m'aiderait dans ma recherche de compréhension. Merci d'avance :)
Ci dessous le code modifié :
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import tkinter as tk import time import os class Application(tk.Frame): def __init__(self, master=None): tk.Frame.__init__(self, master) self.pack(expand=True, fill="both") self.entries_y = 30 self.tab = ["C:\\Users\\blabla\\Documents\\python\\images\\image1.gif", "C:\\Users\\blabla\\Documents\\python\\images\\image2.gif"] print(self.tab) self.tab_index = 0 self.create_widgets() # Prepare initial timer self.on_update() def create_widgets(self): if self.tab: wi = 90 he = 90 image = tk.PhotoImage(file=self.tab[self.tab_index], master=self) self.canvas_logo = tk.Canvas(self, width = wi, height = he) self.canvas_logo.place(x = wi / 2, y = 0) #self.canvas_logo.create_rectangle(0, 0, 200, 50, fill="green") self.image_container = self.canvas_logo.create_image(wi / 2, he / 2, image=image) self.canvas_logo.pack() self.bu_ajout = tk.Button(self, text = "Ajout", command = self.add_entries) self.bu_ajout.pack(side="top") self.quit = tk.Button(self, text="Quitter", fg="red", command=root.destroy) self.quit.pack(side="bottom") def add_entries(self): self.add_entry("red") self.add_entry("yellow") def add_entry(self, color): canvas = tk.Canvas(self, width=200, height=50) canvas.create_rectangle(0, 0, 200, 50, fill=color) canvas.place(x=0, y=self.entries_y) myentry = tk.Entry(canvas, bd = 3) myentry.place(x = 5, y = 12.5) self.entries_y += 50 def update_image(self): if self.tab: image = tk.PhotoImage(file=self.tab[self.tab_index], master=self) self.canvas_logo.itemconfigure(self.image_container, image=image) self.canvas_logo.pack() def on_update(self): if self.tab: self.tab_index += 1 self.tab_index %= len(self.tab) # permet de rester entre index 0 et et len self.images non inclus. self.update_image() print(self.tab_index)# pourtant l'index change bien à chaque appel self.after(500, self.on_update) root = tk.Tk() root.geometry("1000x720") #root.config(background='#7720B9') app = Application( master = root ) root.mainloop()
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
Modifié le 26 janv. 2022 à 12:19
Modifié le 26 janv. 2022 à 12:19
Bonjour,
Alors en fait l'erreur n'est pas algorithmique, mais lié à une subtilité de Tk dont j'ai peu parlé brièvement dans mon message précédent :
Ensuite je crée un attribut self.images dans lequel je charge tous les images (formats valides : png, bmp, gif).
Si tu lis ce lien, tu verras qu'il faut garder une référence vers l'image chargée par ta classe
Même si j'ai bien compris que tu retapais le code pour voir si tu le maîtrisais, garde à l'esprit qu'en terme de design de classe, il est mieux que ta classe
Bonne chance
Alors en fait l'erreur n'est pas algorithmique, mais lié à une subtilité de Tk dont j'ai peu parlé brièvement dans mon message précédent :
Ensuite je crée un attribut self.images dans lequel je charge tous les images (formats valides : png, bmp, gif).
Si tu lis ce lien, tu verras qu'il faut garder une référence vers l'image chargée par ta classe
Application, sans quoi elle ne parviendra pas à afficher les images. C'est pourquoi dans mon cas je les stockais dans
self.images. Si tu n'avais eu qu'une image tu aurais pu directement avoir un attribut
self.image.
Même si j'ai bien compris que tu retapais le code pour voir si tu le maîtrisais, garde à l'esprit qu'en terme de design de classe, il est mieux que ta classe
Applicationprennent en paramètre la liste des fichiers plutôt que de les coder en dur en interne. Ainsi elle est utilisable si les fichiers sont dans un autre dossier et/ou dispersées dans plusieurs dossiers.
Bonne chance
pycarpe
Messages postés
16
Date d'inscription
lundi 24 janvier 2022
Statut
Membre
Dernière intervention
9 août 2022
26 janv. 2022 à 12:31
26 janv. 2022 à 12:31
J'ai compris pourquoi ma modif ne fonctionnait pas. Désolé du dérangement. J'ai simplement oublié de déclarer l'attribut représentant les images dans l'instance app = Application() ce qui devient :
Et là ca marche. Evidemment c'était juste pour tester en mettant les images en dur juste pour voir si j'avais bien compris. Merci encore a+++
tab = ["C:\\Users\\blabla\\Documents\\python\\images\\image1.gif", "C:\\Users\\blabla\\Documents\\python\\images\\image2.gif"] root = tk.Tk() root.geometry("1000x720") #root.config(background='#7720B9') app = Application( filenames = [ f for f in tab ], master = root ) root.mainloop()
Et là ca marche. Evidemment c'était juste pour tester en mettant les images en dur juste pour voir si j'avais bien compris. Merci encore a+++
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
26 janv. 2022 à 14:16
26 janv. 2022 à 14:16
Pas de soucis, bonne continuation, et si tu as d'autres questions, n'hésite pas.