IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Tkinter Python Discussion :

canavas dans fonction - PhotoImage - comportement bizarre


Sujet :

Tkinter Python

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 7
    Points : 5
    Points
    5
    Par défaut canavas dans fonction - PhotoImage - comportement bizarre
    Bonjour,

    Je suis face à un cas que je ne comprends pas.

    Je cherche à afficher une image dans un canevas, le but c'est de faire une petite appli pour ranger mes photos.

    Le code ci-dessous fonctionne et affiche bien mon image :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    from tkinter import *
    from PIL import Image, ImageFont, ImageDraw, ImageTk 
     
    fen=Tk()
    cadre=Canvas(fen,width=640,height=480,bg="black")
     
    cadre.pack(side=LEFT)
     
     
    pilImage=Image.open("image.jpg")
    im=ImageTk.PhotoImage(pilImage)
    cadre.create_image(320,240,image = im)
     
     
    fen.mainloop()
    maintenant je voudrais associer l'affichage de l'image à une action d'un bouton :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    from tkinter import *
    from PIL import Image, ImageFont, ImageDraw, ImageTk 
     
    fen=Tk()
     
    toto={}
     
    #----------- cette fonction marche, grâce au toto , pourquoi ?
     
    def chargerImage(): 
        im=Image.open("image.jpg") 
        im=im.resize((640,480))
        photo = ImageTk.PhotoImage(im) 
        toto['img1'] = photo
        item = cadre.create_image(320,240,image =photo) 
        print("charger image")
        print(im.format, im.size, im.mode)
        #im.show() --> montre image dans fenetre independante
     
     
    #----------- cette fonction ne fonctionne pas alors que c'est la même que dans le programme précédent.
     
    def chargerImage2():
    	pilImage=Image.open("image.jpg")
    	im=ImageTk.PhotoImage(pilImage)
    	cadre.create_image(320,240,image = im)
     
     
     
     
    cadre=Canvas(fen,width=640,height=480,bg="black")
    b=Button(fen,text="ON",command=chargerImage)
    c=Button(fen,text="2",command=chargerImage2)
    cadre.pack(side=LEFT)
     
    b.pack()
    c.pack()
    fen.mainloop()
    Je ne comprends ce que vient faire le dictionnaire toto, et pourquoi cela fonctionne avec lui... (je me suis inspiré de posts dans différents forum)

    Merci d'avance !

  2. #2
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Citation Envoyé par theboubs Voir le message
    Je ne comprends ce que vient faire le dictionnaire toto, et pourquoi cela fonctionne avec lui... (je me suis inspiré de posts dans différents forum)
    Le dictionnaire est référencé par une variable globale "toto". toto['img1'] = photo ajoute une clé au dictionnaire associé à une référence à "photo". L'intérêt est qu'à la fin de la fonction, les variables globales "persistent". La référence au différents objets aussi. Et l'image ("photo") ne sera pas détruite.

    Techniquement, créer une Image (ou une Variable) tkinter, côté Python, passe par la création d'objets correspondants côté TCL/Tk qui leur seront associés.
    Côté Python, lorsqu'il n'y a plus de référence, le garbage collector détruit l'objet. tkinter détruit l'objet TCL/Tk associé.
    L'image TCK/Tk n'existant plus, elle n'est plus affichéedisparaît.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Salut,

    Dans la deuxième fonction ton image n'existe que dans cet espace de nom (celui de la fonction, j'entends) elle est donc détruite aussitôt.

    L'histoire du dictionnaire toto est un horrible et honteux bricolage à éviter.

    Essaye ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    def chargerImage2():
        global im
        pilImage=Image.open("image.jpg")
        im=ImageTk.PhotoImage(pilImage)
        cadre.create_image(320,240,image = im)
    ... pas testé, bien sur.

  4. #4
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Citation Envoyé par VinsS Voir le message
    L'histoire du dictionnaire toto est un horrible et honteux bricolage à éviter.
    Cela n'a rien de honteux ou d'horrible: on peut avoir à gérer un tas d'images qui seront affichées de temps en temps. Les stocker dans un dico. global permet d'avoir un nom pour les adresser et éviter de les recharger à chaque fois. Évidement, s'il n'y a qu'une seule image, c'est juste "too much".

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Futur Membre du Club
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    7
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 7
    Points : 5
    Points
    5
    Par défaut
    re-bonjour et merci pour vos réponses, rapides qui plus est !.

    En gros, si je comprends, l'objet cadre(Canvas) est dans l'espace principal du programme.
    L'image est crée en local dans la fonction et quand la fonction s'arrête l'image "n'existe plus"...

    donc on est obligé d'utiliser une variable globale (je croyais que ce n'était pas bien) ou le dico (ce qui revient au même car il est dans l'espace principal du programme)

    Je pensais qu'il y avait moyen de faire cette manip sans passer par du "global", peut-être avec une programmation orientée objet pour la création des widget... je chercherais, j'avais vu il y a un moment des exemples sur un post de sebsauvage je crois que c'est celui là :
    http://sebsauvage.net/python/gui/index_fr.html

    du style ... : ça a l'air de marcher ... alors la question : est-ce plus "propre" ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    from tkinter import *
    from PIL import Image, ImageFont, ImageDraw, ImageTk 
     
    class Application:
    	def __init__(self):
    		self.fenetre = Tk()
    		self.can=Canvas(self.fenetre,width=480,height=240,bg='white')
    		self.im=Image.open('image.jpg')
    		self.photo=ImageTk.PhotoImage(self.im)
    		self.item = self.can.create_image(240,120,image=self.photo)
    		self.can.pack(side=LEFT)
    		Button(self.fenetre,text='Quitter',command=self.fenetre.quit).pack(side=BOTTOM)
    		Button(self.fenetre,text='Photo 1',command=self.change_photo).pack()  
     
    	def change_photo(self):
     
    		self.im2=Image.open('image.png')
    		self.photo=ImageTk.PhotoImage(self.im2)
    		self.can.itemconfigure(self.item,image=self.photo)
     
    app=Application()
    app.fenetre.mainloop()

    Merci encore à vous 2

  6. #6
    Expert éminent sénior
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 283
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 283
    Points : 36 770
    Points
    36 770
    Par défaut
    Salut,

    Citation Envoyé par theboubs Voir le message
    Je pensais qu'il y avait moyen de faire cette manip sans passer par du "global", peut-être avec une programmation orientée objet pour la création des widget...
    Dans ce cas, la variable globale est "app" et le dictionnaire est self.__dict__ dans lequel est stocké l'attribut "photo" associé à...
    Vous pourriez faire la même chose en ajoutant un attribut à "cadre" de votre premier code:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    from tkinter import *
    from PIL import Image, ImageFont, ImageDraw, ImageTk 
     
    fen=Tk()
     
     
     
    #----------- cette fonction marche, grâce au toto , pourquoi ?
     
    def chargerImage(): 
        im=Image.open("image.jpg") 
        im=im.resize((640,480))
        photo = ImageTk.PhotoImage(im) 
        cadre._image = photo
        item = cadre.create_image(320,240,image =photo) 
        print("charger image")
        print(im.format, im.size, im.mode)
     
     
    cadre=Canvas(fen,width=640,height=480,bg="black")
    b=Button(fen,text="ON",command=chargerImage)
    c=Button(fen,text="2",command=chargerImage2)
    cadre.pack(side=LEFT)
     
    b.pack()
    c.pack()
    fen.mainloop()
    L'important c'est que la référence survive à la fonction... Ce qui passe par une variable "globale" plus ou moins directement.
    Et comme les variables "globales" ont une portée limitée au module courant, c'est pas si mal.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. [Flex4] Doublons dans datagrid = comportement bizarre..
    Par baobab95 dans le forum Flex
    Réponses: 3
    Dernier message: 04/04/2012, 17h32
  2. [PHP 5.3] Comportement bizarre de la fonction is_array
    Par renaud26 dans le forum Langage
    Réponses: 7
    Dernier message: 12/05/2011, 16h46
  3. Comportement bizarre dans POI
    Par bruno.wiesen dans le forum Documents
    Réponses: 1
    Dernier message: 23/05/2007, 11h04
  4. Comportement bizarre de la fonction strlen
    Par clampin dans le forum C
    Réponses: 4
    Dernier message: 30/12/2006, 14h00

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo