Ouvrir une image en cliquant sur une image (Python-Tkinter)

Résolu
Bonjour, j'ai un projet à réaliser en ISN pour le BAC, et je suis bloqué à une étape. Je dois créer une fenêtre dans laquelle plusieurs images sont disposées. Cette étape est déjà faite (voir screen)
Et maintenant, je dois de faire en sorte que ces images soient cliquables et qu'elles renvoient une nouvelle image. Je ne vois pas du tout comment faire ... Merci à tous ceux qui répondront et qui m'aiderons je l'espère.
Bonne journée à vous

35 réponses

Résumé de la discussion

La problématique porte sur rendre cliquables des images disposées dans une fenêtre Tkinter afin qu’un clic affiche une image différente dans une autre zone ou fenêtre. Plusieurs intervenants recommandent d’utiliser un Canvas et de récupérer les coordonnées de clic pour déterminer quelle image est touchée, puis d’employer une boucle et un dictionnaire pour gérer les associations image/classement. Des exemples montrent la création dynamique des images avec PhotoImage et une boucle qui parcourt le dictionnaire d’images, puis l’ouverture d’une seconde fenêtre (Toplevel) avec l’image remplaçante lorsque le clic correspond. D'autres conseils insistent sur l'utilisation de dictionnaires simples pour lier chaque image à ses coordonnées et à son image remplaçante, afin de simplifier le code et limiter les répétitions.

Bobot (l’IA à votre service)
  1. Bonsoir MrLemon,

    Tu as cherché dans la doc Tkinter ?

    Tu y verrais que l'on peut récupérer les coordonnées d'un clic de souris sur un 'canvas'

    C'est un début, à toi d'imaginer la suite … :-)

    Une doc sympa:

    https://www.inforef.be/swi/download/apprendre_python3.pdf
    2
    1. Ah ok, ta demande n'était pas correcte :

      ".... Incruster ce programme dans une page WEB"

      En fait, tu veux l'exécuter le script à partir de la page web !

      Alors, là, je ne sais pas du tout ...

      Je te propose de conclure cet appel et d'en recréer un nouveau avec la question :

      "Comment exécuter un script Python à partir d'une page web ? "

      Après tout, c'est un nouveau sujet, et du coup, quelqu'un d'autre pourra répondre
      0
      1. Pas de problème merci pour tout !
        0
    2. Non pas du tout, j'aimerais que le programme que l'on vient de faire soit exécutable dans une page html, en gros j'aimerais que sur une page WEB on puisse cliquer sur les images et qu'on puisse voir leurs définitions.
      0
      1. Et ce n'est pas ça que tu veux ?
        0
        1. Bonjour MrLemon,

          As-tu récupéré mon dernier code html (celui du 28 à 11h24) ?

          Et l'as-tu exécuté pour voir ce qu'il affiche ?

          Dis moi ce que tu vois sur la page qui s'affiche ...
          0
          1. Oui bien sur, et pour le html il faut juste que je rajoute ce que vous avez marqué ? Je veux intégrer mon programme a une page html
            Bonne soirée
            0
            1. Bonjour MrLemon,

              Si tous les problèmes sont réglés, je pense que tu peux marquer cet appel comme "résolu"

              :-)
              0
              1. ou comme ça:
                <!doctype html>
                	<head>
                		<title>Mon programme d'images</title>
                		<style type="text/css">
                			p {color: #006666; font-family: Verdana; font-size : 20px}
                		</style>
                	</head>
                
                	<body>
                		<p>Voici mon superbe programme Python :</p>
                		<pre>
                # -*- coding:Latin-1 -*-
                # 09/10/2015 12:50:11
                
                prenom = input('\nEntrez votre prénom: ')
                if(prenom == 'toto'):
                	print('Bonjour', prenom)
                		</pre>
                		<p>Chouette, non ?</p>
                	</body>
                </html>
                
                0
                1. Oui voilà le 2e
                  0
              2. Hello !

                Comme ça, alors ? :

                <!DOCTYPE HTML>
                <HEAD>
                <TITLE>Mon programme d'images</TITLE>
                </HEAD>
                
                <BODY>
                <PRE>
                # -*- coding:Latin-1 -*-
                # 09/10/2015 12:50:11
                
                prenom = input('\nEntrez votre prénom: ')
                if(prenom == 'toto'):
                	print('Bonjour', prenom)
                </PRE>
                </BODY>
                </HTML>
                
                0
                1. Un html que je crée moi même sur Notepad++
                  0
                  1. une page web existante ?

                    ou un html que tu créé toi-même ?
                    0
                    1. Holà MrLemon,

                      Je sais bien que tu fais avec tes connaissances :-)

                      Donc, justement, suis bien ce que je te racontes !

                      Dans ma réponse du 19 avril à 15h09 , je te disais:

                      "J'aurais donc pu écrire la ligne 40 comme ceci: "

                      for k in range(len(images)):
                      	img = PhotoImage(file=images[k][0])
                      	can.create_image(images[k][2][0],images[k][2][1],anchor = NW, image=img)
                      


                      On voit bien que les 2 dernières lignes sont décalées, donc à l'intérieur de la boucle

                      Et toi, tu écris:

                      for i in range (len(images)):
                      img = PhotoImage(file=images[i][0])
                      can.create_image(images[i][2][0],images[i][2][1],anchor = NW, image=img)
                      


                      Tout est aligné, donc la 1ere ligne, c'est une boucle qui tourne 20 fois et ne fait rien, et à la fin, le compteur i=19

                      Ensuite, on créé une image images[i][0], donc images[19][0] et on l'affiche
                      On n'affiche donc que la 19eme et dernière image ...
                      0
                      1. Merci c'est juste une erreur de copier coller sinon ça je l'avais bien compris et appris avant. Bon bah je crois que j'ai enfin réussis :) Merci beaucoup pour toutes les aides apportées, c'était pas gagné :')
                        Petite dernière question, peut-on incorporer ce programme à de l'HTML ? Incruster ce programme dans une page WEB ?
                        0
                    2. Bonjour MrLemon,

                      Je vais te tirer les oreilles :-) :-)
                      tu n'as pas fait ce que j'ai expliqué dans mes réponses !

                      Il est bien trop long ton programme : pourquoi créer le dictionnaire images avec les 20 images, si c'est pour ensuite écrier 20 fois can.create_image ….

                      Si ta boucle ne marche pas, c'est parce que les 2 lignes pour créer l'image ne sont pas indentées : donc elles ne sont pas dans la boucle, donc la boucle tourne à vide et ensuite on créé une seule image : la dernière car i est le dernier indice de la boucle qui vient de finir !

                      Regarde ce code, fais en un copié/collé et essaie: ca marche parfaitement bien avec la boucle qui balaye le dictionnaire images et il est 3 fois plus court que le tien:
                      (OK, moi je n'ai que 2 images, mais ca ne change rien au principe)

                      # -*- coding:Latin-1 -*-
                      # Affichage d'images	19/04/2020 16:12:36
                      
                      from tkinter import *
                      
                      def clic_souris(event):
                      	''' Si clic de souris sur une image existante
                      	    ouverture d'une autre fenetre et affichage d'une autre image '''
                      
                      	global image, fenetre_secondaire
                      
                      	for k in range(len(images)):
                      		x1 = images[k][2][0]
                      		y1 = images[k][2][1]
                      		x2 = x1 + images[k][2][2]
                      		y2 = y1 + images[k][2][3]
                      		image_remplacante = images[k][1]
                      
                      		if(event.x >=x1 and event.x <=x2 and event.y >=y1 and event.y <=y2):
                      			#Detruire la fenetre secondaire précédente si elle existe
                      			if('fenetre_secondaire' in globals()): fenetre_secondaire.destroy()
                      
                      			fenetre_secondaire = Toplevel(fenetre_princ)
                      			fenetre_secondaire.geometry('420x350+350+200')
                      	
                      			zone_graphique_secondaire = Canvas(fenetre_secondaire,bg='ivory',height=w_height-15,width=w_width-15)
                      			zone_graphique_secondaire.place(x = 5,y = 5)
                      	
                      			image = PhotoImage(file=image_remplacante)
                      			zone_graphique_secondaire.create_image(10,10,anchor = NW,image=image)
                      
                      w_width=760
                      w_height = 350
                      
                      fenetre_princ = Tk()
                      fenetre_princ.title('Test')
                      fenetre_princ.geometry(str(w_width)+'x'+str(w_height)+'+250+100')
                      
                      zone_graphique = Canvas(fenetre_princ,bg='ivory',height=w_height-15,width=w_width-15)
                      zone_graphique.place(x = 5,y = 5)
                      zone_graphique.bind("<Button-1>", clic_souris)
                      
                      #Image initiales
                      images = {0:('Fresque_01.png','Fresque_02.png',(10,10,365,212)), 1:('Fresque_03.png','Fresque_04.png',(380,10,365,212))}
                      img = {}
                      for k in range(len(images)):
                      	img[k] = PhotoImage(file=images[k][0])
                      	zone_graphique.create_image(images[k][2][0], images[k][2][1], anchor = NW, image=img[k])
                      
                      fenetre_princ.mainloop()
                      
                      
                      1
                      1. Merci, je fais avec mes connaissances et je fais de mon mieux pour comprendre car on n'avait jamais vu ça auparavant :)
                        La fenêtre quand on clique dessus n'a pas la même taille qu'avant, pourtant je n'ai pas changé ses dimensions ... Merci encore
                        0
                    3. Bonjour, j'ai réussis à terminer mon programme sans faire de boucle pour afficher les images.
                      J'ai essayé une boucle
                      for i in range (len(images)):
                      img = PhotoImage(file=images[i][0])
                      can.create_image(images[i][2][0],images[i][2][1],anchor = NW, image=img)
                      

                      mais elle affiche que la dernière image.
                      Sinon mon programme fonctionne sans boucle :
                      from tkinter import *
                      
                      def pick_souris(event):
                       global img_1
                      
                       for k in range(len(images)):
                        x1 = images[k][2][0]
                        y1 = images[k][2][1]
                        x2 = images[k][2][2] + x1
                        y2 = images[k][2][3] + y1
                        image_2 = images[k][1]
                      
                      
                        if(event.x >=x1 and event.x <=x2 and event.y >=y1 and event.y <=y2):
                         fenetre_2 = Toplevel(fenetre_princ)
                         fenetre_2.geometry('1600x1200')
                      
                         can2 = Canvas(fenetre_2,bg='white',height=w_height-10,width=w_width-10)
                         can2.place(x = 0,y = 0)
                      
                         img_1 = PhotoImage(file=image_2)
                         can2.create_image(50,0,anchor = NW, image=img_1)
                      
                      
                      w_width=1600
                      w_height = 1200
                      
                      fenetre_princ = Tk()
                      fenetre_princ.title("I Les conséquences de nos actes")
                      fenetre_princ.geometry(str(w_width)+'x'+str(w_height))
                      
                      
                      can = Canvas(fenetre_princ,bg='#a1ffa3',height=w_height-10,width=w_width-10)
                      can.place(x = 0,y = 0)
                      can.bind("<Button-1>", pick_souris)
                      
                      #Image initiale: taille = 250x150
                      images = {0:('Fresque_01.png','Fresque_02.png',(50,0,250,150)),1:('Fresque_03.png','Fresque_04.png',(580,0,250,150)),
                      2:('Fresque_05.png','Fresque_06.png',(0,160,250,150)),3:('Fresque_07.png','Fresque_08.png',(50,320,250,150)),
                      4:('Fresque_09.png','Fresque_10.png',(50,650,250,150)),5:('Fresque_11.png','Fresque_12.png',(315,0,250,150)),
                      6:('Fresque_13.png','Fresque_14.png',(840,0,250,150)),7:('Fresque_15.png','Fresque_16.png',(400,320,250,150)),
                      8:('Fresque_17.png','Fresque_18.png',(0,480,250,150)),9:('Fresque_19.png','Fresque_20.png',(360,160,250,150)),
                      10:('Fresque_21.png','Fresque_22.png',(400,650,250,150)),11:('Fresque_23.png','Fresque_24.png',(1100,0,250,150)),
                      12:('Fresque_25.png','Fresque_26.png',(1100,320,250,150)),13:('Fresque_27.png','Fresque_28.png',(360,480,250,150)),
                      14:('Fresque_29.png','Fresque_30.png',(710,480,250,150)),15:('Fresque_31.png','Fresque_32.png',(1100,650,250,150)),
                      16:('Fresque_33.png','Fresque_34.png',(1050,160,250,150)),17:('Fresque_35.png','Fresque_36.png',(750,320,250,150)),
                      18:('Fresque_37.png','Fresque_38.png',(710,160,250,150)),19:('Fresque_39.png','Fresque_40.png',(1050,480,250,150)),
                      20:('Fresque_41.png','Fresque_42.png',(750,650,250,150))}
                      
                      #for i in range (len(images)):
                      
                      img = PhotoImage(file=images[0][0])
                      can.create_image(images[0][2][0],images[0][2][1],anchor = NW, image=img)
                      
                      img1 = PhotoImage(file=images[1][0])
                      can.create_image(images[1][2][0],images[1][2][1],anchor = NW, image=img1)
                      
                      img2 = PhotoImage(file=images[2][0])
                      can.create_image(images[2][2][0],images[2][2][1],anchor = NW, image=img2)
                      
                      img3 = PhotoImage(file=images[3][0])
                      can.create_image(images[3][2][0],images[3][2][1],anchor = NW, image=img3)
                      
                      img4 = PhotoImage(file=images[4][0])
                      can.create_image(images[4][2][0],images[4][2][1],anchor = NW, image=img4)
                      
                      img5 = PhotoImage(file=images[5][0])
                      can.create_image(images[5][2][0],images[5][2][1],anchor = NW, image=img5)
                      
                      img6 = PhotoImage(file=images[6][0])
                      can.create_image(images[6][2][0],images[6][2][1],anchor = NW, image=img6)
                      
                      img7 = PhotoImage(file=images[7][0])
                      can.create_image(images[7][2][0],images[7][2][1],anchor = NW, image=img7)
                      
                      img8 = PhotoImage(file=images[8][0])
                      can.create_image(images[8][2][0],images[8][2][1],anchor = NW, image=img8)
                      
                      img9 = PhotoImage(file=images[9][0])
                      can.create_image(images[9][2][0],images[9][2][1],anchor = NW, image=img9)
                      
                      img10 = PhotoImage(file=images[10][0])
                      can.create_image(images[10][2][0],images[10][2][1],anchor = NW, image=img10)
                      
                      img11= PhotoImage(file=images[11][0])
                      can.create_image(images[11][2][0],images[11][2][1],anchor = NW, image=img11)
                      
                      img12 = PhotoImage(file=images[12][0])
                      can.create_image(images[12][2][0],images[12][2][1],anchor = NW, image=img12)
                      
                      img13 = PhotoImage(file=images[13][0])
                      can.create_image(images[13][2][0],images[13][2][1],anchor = NW, image=img13)
                      
                      img14 = PhotoImage(file=images[14][0])
                      can.create_image(images[14][2][0],images[14][2][1],anchor = NW, image=img14)
                      
                      img15 = PhotoImage(file=images[15][0])
                      can.create_image(images[15][2][0],images[15][2][1],anchor = NW, image=img15)
                      
                      img16 = PhotoImage(file=images[16][0])
                      can.create_image(images[16][2][0],images[16][2][1],anchor = NW, image=img16)
                      
                      img17 = PhotoImage(file=images[17][0])
                      can.create_image(images[17][2][0],images[17][2][1],anchor = NW, image=img17)
                      
                      img18 = PhotoImage(file=images[18][0])
                      can.create_image(images[18][2][0],images[18][2][1],anchor = NW, image=img18)
                      
                      img19 = PhotoImage(file=images[19][0])
                      can.create_image(images[19][2][0],images[19][2][1],anchor = NW, image=img19)
                      
                      img20 = PhotoImage(file=images[20][0])
                      can.create_image(images[20][2][0],images[20][2][1],anchor = NW, image=img20)
                      
                      fenetre_princ.mainloop()
                      
                      0
                      1. J'essaie de bien tout comprendre mais c'est compliqué surtout que Python et moi ça fais 2 :?
                        Je vais voir ce que je peux faire tout seul en prenant plus le temps. Merci encore pour votre aide, seul ça serait treeeees compliqué :roll:
                        Bonne soirée à vous
                        0
                        1. Tu n'as pas beaucoup analysé mon code, et tu n'as pas beaucoup regardé la doc python !
                          Si je te fais tout le boulot, ca ne va pas beaucoup t'aider !

                          Pour ces trucs de +350+200, regarde la doc sur la création d'une fenêtre et de sa taille avec la méthode .geometry() et ses paramètres

                          can2 = Canvas(fenetre_2,bg='ivory',height=w_height-70,width=w_width-30), chez moi c'est sur la ligne 19, pas la 17
                          Tu sais bien ce qu'est un Canvas puisque tu en a fait toi-même, pour ce qui est de w_width et de w_height, je t'ai dit tout à l'heure:
                          "Déjà, lignes 25 et 26, 2 variables pour définir la taille de la fenêtre principale …"
                          donc je me sers de ces 2 variables pour régler aussi la taille de can2

                          Ensuite tu me dis :
                          "si j'ai bien compris, il faut ajouter image_3 = images [k][2] en dessous de
                          image_2 = images[k][1]"
                          Tu n'as pas suivi mes explications : je te dis qu'on fait une boucle pour parcourir tout le tableau, et éviter d'écrire 50 fois les affichages, il n'y a donc rien a ajouter !!!
                          A chaque tour de boucle, le nom de l'image et les coordonnées changent puisqu'on parcourt le tableau images qui est justement fait pour ça!

                          Evidemment, il faut aussi modifier le code comme je te le montrait pour faire une boucle à la place de la ligne 40 (affichage de toutes les images initiales)

                          Tu n'as jamais utilisé de boucles en Python ?
                          Fais toi un petit programme de test en mode console et essaie, et met des print pour voir ce qui se passe et ce qui sort, et essayer de comprendre

                          Pour ce qui est de compléter le dictionnaire images je te l'ai montré ici avec 2 éléments numérotés 0 et 1:
                          "Donc, le dictionnaire un peu plus complet commencerait comme ceci: ......."

                          Moi je serais toi je ferais aussi des tests sur les dictionnaires avec des print pour voir la logique pour en extraire les éléments:
                          images[k][0]
                          images[k][1]
                          images[k][2][0]
                          images[k][2][0]

                          Bref, relis bien toutes mes explications, essaie de comprendre, analyse le code, insère des print si il le faut pour mieux voir ce qui se passe
                          0
                          1. Super merci beaucoup ! J'ai déjà modifier les tailles ect .. Manque plus qu'à le refaire pour chaque images ! :) Encore une petite question sur les lignes 15, 17 et 28 :
                            Pourquoi rajoutons nous +350+200 ? (ligne 15)
                            Pareil pour la ligne 28 (+250+100)
                            Et qu'est ce que représente ligne 17 :
                                can2 = Canvas(fenetre_2,bg='ivory',height=w_height-70,width=w_width-30)
                            

                            Le "height=w_height-70,width=w_width-30)"
                            Merci encore
                            0
                            1. Déjà, lignes 25 et 26, 2 variables pour définir la taille de la fenêtre principale, comme ça, il suffit de changer ces valeurs pour ajuster selon ce que l'on veut

                              Ensuite, on crée la fenêtre principale et son Canvas que l'on place à x15, y15

                              Ligne 37: définition d'un dictionnaire "images", si tu ne sais pas ce que c'est qu'on dictionnaire Python, regarde la doc dont je t'ai donné le lien le 8 avril, tu dois comprendre exactement ce que c'est

                              Ca permet d'avoir un tableau avec les images et leurs coordonnées et donc, en balayant tous ses éléments avec une boucle sur le nombre d'éléments, on évite d'écrire 50 fois
                              img = PhotoImage(…………
                              can.create_image(……………
                              pour chaque photo, comme tu l'a fait au début

                              J'aurais donc pu écrire la ligne 40 comme ceci:
                              for k in range(len(images)):
                              	img = PhotoImage(file=images[k][0])
                              	can.create_image(images[k][2][0],images[k][2][1],anchor = NW, image=img)
                              


                              Et dans la fonction "pick_souris", on fait aussi une boucle pour tester sur quelle image on a cliqué, c'est quand même plus pratique et plus court que de faire çà autant de fois qu'il y a d'images

                              Donc, le dictionnaire un peu plus complet commencerait comme ceci:
                              images = {0:('Fresque_01.png','Fresque_02.png',(10,10,365,212)), 1:('Fresque_03.png','Fresque_04.png',(375,10,360,210)), 2:  etc .................}
                              


                              Chaque élément est séparé par une virgule, et composé comme ça:
                              clé : liste contenant 2 chaines de caractères et une liste
                              La clé est un peu le numéro d'ordre, ca commence à 0
                              Les 2 chaines sont la 1ere image, puis celle qui doit la remplacer
                              La liste contient les coordonnées pour placer la 1ere image, puis sa longueur et largeur

                              Il faut donc compléter ce dictionnaire avec toutes tes images, leur vrai nom, et leurs vraies coordonnées et tailles, moi, j'ai mis des noms au hasard et les tailles de mes images pour tester
                              1
                              1. Et si j'ai bien compris, pour rajouter chaque images, il faut rajouter par exemple avec l'image 3 et 4 :
                                image_3 = images [k][2]
                                en dessous de
                                 image_2 = images[k][1]

                                Puis
                                img3= PhotoImage(file=image_3)
                                   can2.create_image(580,0,anchor = NW, image=img3)
                                
                                en dessous de
                                img2 = PhotoImage(file=image_2)
                                   can2.create_image(50,0,anchor = NW, image=img2)
                                


                                Et
                                1:('Fresque_03.png','Fresque_04.png',(580,0,250,150))


                                Si ce n'est pas ça pouvez me le faire pour l'image 3 et 4 pour que je vois et comprenne ? Merci et excuse moi de vous prendre autant de temps.
                                0
                            2. Merci ! C'est exactement ce que je cherchais ! Il me reste plus qu'à modifier pour que ce programme intervienne sur toutes les images . Si jamais je n'y arrive pas je me redirigerai vers vous. Pouvez m'expliquer à quoi sert les principales lignes ? J'aimerais comprendre pour pouvoir l'expliquer plus tard, si cela ne vous dérange pas. Merci infiniment et bonne journée à vous :)
                              0
                              • 1
                              • 2