• Tkinter > Afficher une image dans un canvas

      création d’un labyrinthe en réseau avec interface graphique côté client. j’ai fais pas mal d’essais sur des bouts de code pour comprendre comment se comporte python 3.6.4, Je commence donc une classe qui me permet d’afficher l’interface voulue. Histoire d’agrémenter l’interface et tester en même temps certaines possibilités en vue de la suite, j’ai désiré y intégrer une image, via Canevas. mais ce fameux canevas n’affiche l’image que si je lance un mainloop() directement à la suite de sa création. Je mets le code ci-dessous: Et si quelqu’un a une idée je suis preneur. autrement je ferais ma fenetre hors classe et tant pis pour la beauté des classes.

       

      from tkinter import *
      import os
      class Wclient(Tk):
          def __init__(self, parent):
              Tk.__init__(self, parent)
              self.parent = parent
              self.initialize()
              self.AIDE = ""
              def initialize(self):
                  elfgrid()
                  # canevas pour déterminer l'emplacement du labyrinthe sera construit selon l'arrivée du labyrinthe.
                  self.canvas = Canvas(self)
                  self.canvas.configure(width=300, height=300, bg='red')
                  self.canvas.create_text(150,150, text='Mire')
                  self.canvas.grid(row=1,rowspan=10)
                  # champ de saisie
                  self.entryvariable = StringVar()
                  self.entry = Entry(self, textvariable=self.entryvariable)
                  self.entry.grid(column=1, row=10, sticky='S')
                  self.entry.bind('<Return>', self.OnPressEnter)
                  self.entryvariable.set(u"Enter text here")
                  # C'est la ligne en haut, qui rappelle la dernière frappe
                  self.labelvariable = StringVar()
                  self.label = Label(self, anchor=W, fg="white", bg="blue", textvariable=self.labelvariable)
                  self.label.grid(row=0, columnspan=2,sticky=EW)
                  self.labelvariable.set(u"Hello !")
          ###############################
          # C'est ici que cela se passe: 
          img = PhotoImage(file="rdv.png")
          canvas = Canvas(self)
          canvas.configure(width=img.width(), height=img.height())
          canvas.create_image(img.width()/2,img.height()/2,image=img)
          canvas.grid(row=1,column=1)
          #j'enlève ce mainloop() ci-dessous et l'image disparaît. Si je le laisse, l'image  apparaît mais je ne peux plus
          #changer le titre par  exemple.
          #<br>        self.mainloop()
          #permet le redimentionnement dynamique
          self.grid_columnconfigure(0,weight=1)
          #empèche le redimentionnement
          self.resizable(False, False)
          self.update()
          self.geometry(self.geometry())
          self.entry.focus_set()
          self.entry.selection_range(0, END)
          def OnPressEnter(self,event):
              self.labelvariable.set( self.entryvariable.get())
              self.entry.focus_set()
              self.entry.selection_range(0, END)
      
      def main():
          app = Wclient(None)
          app.title('Fenêtre')
          app.mainloop()
      
      if __name__ == '__main__':
          main()

       

       

      En fait, c’est très simple comme erreur, mais je ne peux pas vraiment l’expliquer.Lorsque l’on créer un canva contenant une image, il faut gérer ce canva comme étant un label. 

      (On le fait pas souvent, parce que normalement, on a plusieurs images dans le même canvas et qu’elles apparaissent tous).

      label = Label(…, image=img)

      label.image = img ## Association de l’image au widget

      label.pack()

      C’est-à-dire qu’il faut lui associé l’image à ce canva.

      img = PhotoImage(file="rdv.png")

      canvas = Canvas(self)

      canvas.configure(width=img.width(), height=img.height())

      canvas.create_image(img.width()/2,img.height()/2,image=img)

      canvas.image = img ## Association de l’image au canva.

      canvas.grid(row=1,column=1)

      Sans classe, il fonctionne très bien sans association, mais avec une classe, il faut l’associé (Je ne sais pas pourquoi).

      C’est comme s’il se rappelait pas qu’il y a une image…

       

      Cool, merci pour la réponse, entre temps j’ai réussi à faire fonctionner ce code de la manière suivante:
      #l’image est dans le répertoire du programme

      img = PhotoImage(file=’rdv.png’)

      wi = img.width()

      hi = img.height()

      C = Canvas(self.myFenetre)

      C['width'] = wi

      C['height'] = hi

      C.create_image(wi/2 ,hi/2 ,image=img)

      C.grid(row=2, column=1)

      En déclarant self.myFenetre dans l’initialisation plutôt en qu’en faisant hériter ma classe de Tk() ça fonctionne:
      def __init__(self):

      self.myFenetre = Tk()

      self.myFenetre['width'] = 500

      self.myFenetre['height'] = 400

      Mais je vais reprendre ta réponse et la tester dans différentes conditions, particulièrement ces histoires de Threads qui rendent chèvre.

      Merci pour la réponse.

       

       

      BitmapImage Class

      The BitmapImage class provides a simple image class, for monochrome (two-color) images.

      When to use the BitmapImage Class

      This class can be used to display bitmap images in labels, buttons, canvases, and text widgets.

      The bitmap loader reads X11 bitmap files. To use other formats, use the PhotoImage class.

      Patterns #

      An X11 bitmap image consists of a C fragment that defines a width, a height, and a data array containing the bitmap. To embed a bitmap in a Python program, you can put it inside a triple-quoted string:

      BITMAP = """
      #define im_width 32
      #define im_height 32
      static char im_bits[] = {
      0xaf,0x6d,0xeb,0xd6,0x55,0xdb,0xb6,0x2f,
      0xaf,0xaa,0x6a,0x6d,0x55,0x7b,0xd7,0x1b,
      0xad,0xd6,0xb5,0xae,0xad,0x55,0x6f,0x05,
      0xad,0xba,0xab,0xd6,0xaa,0xd5,0x5f,0x93,
      0xad,0x76,0x7d,0x67,0x5a,0xd5,0xd7,0xa3,
      0xad,0xbd,0xfe,0xea,0x5a,0xab,0x69,0xb3,
      0xad,0x55,0xde,0xd8,0x2e,0x2b,0xb5,0x6a,
      0x69,0x4b,0x3f,0xb4,0x9e,0x92,0xb5,0xed,
      0xd5,0xca,0x9c,0xb4,0x5a,0xa1,0x2a,0x6d,
      0xad,0x6c,0x5f,0xda,0x2c,0x91,0xbb,0xf6,
      0xad,0xaa,0x96,0xaa,0x5a,0xca,0x9d,0xfe,
      0x2c,0xa5,0x2a,0xd3,0x9a,0x8a,0x4f,0xfd,
      0x2c,0x25,0x4a,0x6b,0x4d,0x45,0x9f,0xba,
      0x1a,0xaa,0x7a,0xb5,0xaa,0x44,0x6b,0x5b,
      0x1a,0x55,0xfd,0x5e,0x4e,0xa2,0x6b,0x59,
      0x9a,0xa4,0xde,0x4a,0x4a,0xd2,0xf5,0xaa
      };
      """

      To create X11 bitmaps, you can use the X11 bitmap editor provided with most Unix systems, or draw your image in some other drawing program and convert it to a bitmap using e.g. the Python Imaging Library.

      The BitmapImage class can read X11 bitmaps from strings or text files:

      bitmap = BitmapImage(data=BITMAP)
      
      bitmap = BitmapImage(file="bitmap.xbm")

      By default, foreground (non-zero) pixels in the bitmap are drawn in black, and background (zero) pixels are made transparent. You can use the foreground and background options to override this behaviour:

      bitmap = BitmapImage(
          data=BITMAP,
          foreground="white", background="black"
          )

      You can draw two-colour transparent bitmaps by associating a mask image to the bitmap. The mask must be an X11 bitmap of the same size as the main bitmap. Background (zero) pixels in the mask are always made transparent, independent of the foreground and background colour settings:

      bitmap = BitmapImage(
          data=BITMAP,
          foreground="black", background="yellow",
          maskdata=MASK_BITMAP
          )

      You can use a BitmapImage instance everywhere Tkinter accepts an image object. An example:

      label = Label(image=bitmap)
      label.pack()

      Note: When a BitmapImage object is garbage-collected by Python (e.g. when you return from a function which stored a bitmap in a local variable), the bitmap is cleared even if it’s displayed by a Tkinter widget.

      To avoid this, the program must keep an extra reference to the bitmap object. One way to do this is to assign the bitmap to a widget attribute, like this:

      label = Label(image=bitmap)
      label.image = bitmap # keep a reference!
      label.pack()

      You can change the bitmap options after you’ve created the object. To modify an option, use the config method, or the [] operator. To get the current value of an option, use the [] operator. The cget method cannot be used for bitmap objects.

      bitmap.config(foreground="blue")
      bitmap["foreground"] = "red"
      print bitmap["foreground"]

       

       

      PhotoImage Class

      The PhotoImage class is used to display images (either grayscale or true color images) in labels, buttons, canvases, and text widgets.

      When to use the PhotoImage Class

      You can use the PhotoImage class whenever you need to display an icon or an image in a Tkinter application.

      Patterns #

      The PhotoImage class can read GIF and PGM/PPM images from files:

      photo = PhotoImage(file="image.gif")
      
      photo = PhotoImage(file="lenna.pgm")

      The PhotoImage can also read base64-encoded GIF files from strings. You can use this to embed images in Python source code (use functions in the base64 module to convert binary data to base64-encoded strings):

      photo = """
      R0lGODdhEAAQAIcAAAAAAAEBAQICAgMDAwQEBAUFBQYGBgcHBwgICAkJCQoKCgsLCwwMDA0NDQ4O
      Dg8PDxAQEBERERISEhMTExQUFBUVFRYWFhcXFxgYGBkZGRoaGhsbGxwcHB0dHR4eHh8fHyAgICEh
      ...
      AfjHtq1bAP/i/gPwry4AAP/yAtj77x+Af4ABAwDwrzAAAP8SA/j3DwCAfwAA/JsM4J/lfwD+/QMA
      4B8AAP9Ci/4HoLTpfwD+qV4NoHVAADs=
      """
      
      photo = PhotoImage(data=photo)

      If you need to work with other file formats, the Python Imaging Library (PIL) contains classes that lets you load images in over 30 formats, and convert them to Tkinter-compatible image objects:

      from PIL import Image, ImageTk
      
      image = Image.open("lenna.jpg")
      photo = ImageTk.PhotoImage(image)

      You can use a PhotoImage instance everywhere Tkinter accepts an image object. An example:

      label = Label(image=photo)
      label.image = photo # keep a reference!
      label.pack()

      You must keep a reference to the image object in your Python program, either by storing it in a global variable, or by attaching it to another object.

      Note: When a PhotoImage object is garbage-collected by Python (e.g. when you return from a function which stored an image in a local variable), the image is cleared even if it’s being displayed by a Tkinter widget.

      To avoid this, the program must keep an extra reference to the image object. A simple way to do this is to assign the image to a widget attribute, like this:

      label = Label(image=photo)
      label.image = photo # keep a reference!
      label.pack()

      x1 et x2 sont des entiers, vous pouvez mettre ce que vous voulez comme valeur,

      dans mon code :

      x1 = tkinter.IntVar()

      x2 = tkinter.IntVar()

      x1.set(2)     (par exemple)

      x2.set(2)  (par exemple)

      img= tkinter.PhotoImage(file="monImage.gif").zoom(x1).subsample(x2)

      là, ça marche, ce qu il faut savoir, c’est que .zoom(2) agrandira l’image de 2x, subsample la réduira, à vous de choisir les bonnes

      valeurs pour obtenir la taille désirée

       

       

      __init__(self, name=None, cnf={}, master=None, **kw)

      Create an image with NAME.

       

      blank(self)

      Display a transparent image.

       

      cget(self, option)

      Return the value of OPTION.

       

      copy(self) Return a new PhotoImage with the same image as this widget.

       

      zoom(self, x, y='’)

      Return a new PhotoImage with the same image as this widget but zoom it with X and Y.

       

      subsample(self, x, y='’)

      Return a new PhotoImage based on the same image as this widget but use only every Xth or Yth pixel.

       

      get(self, x, y)

      Return the color (red, green, blue) of the pixel at X,Y.

       

      put(self, data, to=None)

      Put row formated colors to image starting from position TO, e.g.

       

      write(self, filename, format=None, from_coords=None)

      Write image to file FILENAME in FORMAT starting from position FROM_COORDS.

       

       

       

 

Aucun commentaire

 

Laissez un commentaire