Python3 : tkinter image doesnt exists Le sujet est résolu

Tout ce qui concerne la programmation.
Répondre
Avatar du membre
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Enregistré le : 23 avr. 2016, 23:37
Localisation : 47/FR
Diaspora* : https://framasphere.org/u/hucste
Contact :
Status : Hors ligne

Bonsoir,

J'ai un problème de génération d'image avec tkinter en python3.

Mon projet est organisé ainsi :

Code : Tout sélectionner

yup.tk.py
/img/Logo.png
/img/Logo.wbm
/modules/__init__.py (empty)
/modules/windo_about.py
yup.tk.py
window_about.py

L'erreur est la suivante :

Code : Tout sélectionner

[color=#FF0000]Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/tkinter/__init__.py", line 1699, in __call__
    return self.func(*args)
  File "~/YUP.py/yup.tk.py", line 431, in about
    about = gui(None, init)
  File "~/YUP.py/modules/window_about.py", line 33, in __init__
    self.initialize()
  File "~/YUP.py/modules/window_about.py", line 40, in initialize
    self.ui()
  File "~/YUP.py/modules/window_about.py", line 64, in ui
    img_service = ttk.Label(frm_service, image=self.img_logo)
  File "/usr/local/lib/python3.6/tkinter/ttk.py", line 761, in __init__
    Widget.__init__(self, master, "ttk::label", kw)
  File "/usr/local/lib/python3.6/tkinter/ttk.py", line 559, in __init__
    tkinter.Widget.__init__(self, master, widgetname, kw=kw)
  File "/usr/local/lib/python3.6/tkinter/__init__.py", line 2293, in __init__
    (widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage2" doesn't exist[/color]
OK, donc l'image soit disant n'existe pas!
En fait, c'est plus compliqué que cela.

J'explique :

Dans le script 'yup.tk.py', j'ai en gros, cela :

Code : Tout sélectionner

import tkinter as tk
import tkinter.ttk as ttk
 
import PIL.Image as pimg
import PIL.ImageTk as pimgtk
 
NAME = "MyAPP"
 
class Gui(tk.Tk): 
    '''Gui tkinter'''
    def __init__(self, parent):
        tk.Tk.__init__(self, parent)
        self.parent = parent
 
        self.dir = os.path.dirname(os.path.abspath(sys.argv[0]))
        self.icon = os.path.join(self.dir, 'img', 'Logo.xbm')
        self.img_logo = None
        self.logo = os.path.join(self.dir, 'img', 'Logo.png')
         
        self.initialize()
 
    def about(self):
        '''Displaying a window about'''
        from modules.window_about import gui
 
        init = {
            'DESCR': DESCR, 
            'dir': self.dir,
            'icon': self.icon,
            'img_logo': self.img_logo,
            'logo': self.logo,
            'NAME': NAME,
            }
 
        about = gui(None, init)
        about.title(NAME)
        about.mainloop()
 
    def initialize(self):
        '''Initialize window'''
        self.grid()
        (...)
        self.menu()
        self.ui()
 
    def menu(self):
        "Displaying menubar"
        menubar = tk.Menu(self)
 
        menuFile = tk.Menu(menubar, tearoff=0)
        menuFile.add_command(label="Créer", command=self.alert)
        menuFile.add_separator()
        menuFile.add_command(label="Quitter", underline=0,
                             command=self.byebye,
                             accelerator="Ctrl+Q")
 
        menubar.add_cascade(label="Fichier", underline=0, menu=menuFile)
 
        menuHelp = tk.Menu(menubar, tearoff=0)
        menuHelp.add_command(label="À-propos", underline=0,
                             command=self.about)
 
        menubar.add_cascade(label="Aide", underline=0, menu=menuHelp)
 
        self.config(menu=menubar)
 
    def ui(self):
        '''Displaying UI'''
        # Frame for service informations
        self.frm_service = ttk.Frame(self)
        self.frm_service.grid(row=7, column=3)
 
        ## Add an image logo
        logo_open = pimg.open(self.logo)
        self.img_logo = pimgtk.PhotoImage(logo_open)
        print(f'{self.img_logo}')
        img_service = ttk.Label(self.frm_service, image=self.img_logo)
        img_service.grid(row=0, column=0, rowspan=2)
        (...)
Ce script appelle le module 'window_about.py', lorsqu'on clique sur le menu [à-propos] ( Aide > à-propos ).
Celui qui a l'oeil avertit remarque que je génère dans l'interface, cf la def ui(), une image Logo, qui au niveau de cette interface s'affiche bel et bien - je n'ai pas de soucis avec la génération de la fenêtre principale !!!

Quand le script 'yup.tk.py' appelle le module 'window_about', il lui transmet certaines variables, dont 'self.logo', 'self.icon', voire 'self.img_logo' qui est l'image générée après être passée à la moulinette des outils PIL.

Dans 'windows_about', j'utilise ce code :

Code : Tout sélectionner

import tkinter as tk
import tkinter.ttk as ttk
 
import PIL.Image as pimg
import PIL.ImageTk as pimgtk
 
class gui(tk.Tk):
    ''' Display a GUI for window about'''
 
    def __init__(self, parent, init):
        tk.Tk.__init__(self, parent)
        self.parent = parent
 
        # initialise self
        for i in init:
            setattr(self, i, init[i])
            print(f'self.{i}: {init[i]}')
 
        self.initialize()
    (...)
 
    def initialize(self):
        '''Initialize window'''
        self.grid()
 
        (...)
        self.ui()
        (...)
 
    def ui(self):
        '''Displaying UI'''
        # Frame for service informations
        frm_service = ttk.Frame(self)
        frm_service.grid(row=7, column=1)
 
        ## Add an image logo
        img_service = ttk.Label(frm_service, image=self.img_logo)
        img_service.grid(row=0, column=0, rowspan=2)
        (...)
L'oeil avertit remarquera que j'ai intégré la fonction 'print' pour être sûr que la class gui() du module 'window_about' "reçoit" bien et réécris les variables 'self.logo', 'self.icon', voire 'self.img_logo'.
Ce qui restitue bel et bien cela, lors de l'appel du module 'window_about' :
pyimage2
self.DESCR: Yet Uploader Pixxie.py
self.dir: ~/YUP.py
self.icon: ~/YUP.py/img/Logo.xbm
self.img_logo: pyimage2
self.logo: ~/YUP.py/img/Logo.png
self.NAME: YUPixxie
Et, c'est dans l'interface de la fenêtre "About" que c'est le drame... il ne trouve pas l'image !!!

J'ai remplace le code de la variable 'imag_service' par le suivant, mais j'obtiens le même message d'erreur :

Code : Tout sélectionner

logo_open = pimg.open(self.logo)
img_logo = pimgtk.PhotoImage(logo_open)
print(f'{img_logo}')
img_service = ttk.Label(frm_service, image=img_logo)
img_service.grid(row=0, column=0, rowspan=2)
(...)
Une idée à me soumettre ?
PengouinPdt { le seul, le vrai } ~ " Libre as a Pengouin "
- DIY - Debian Sid | Devuan Ceres
----
Ne réponds pas aux PM d'assistance
Avatar du membre
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Enregistré le : 23 avr. 2016, 23:37
Localisation : 47/FR
Diaspora* : https://framasphere.org/u/hucste
Contact :
Status : Hors ligne

Bon, personne pour m'aider à comprendre pourquoi un même code s'exécute correctement dans la fenêtre principale mais pas dans le module appelé ?!

Perso, j'en perds mon latin !
PengouinPdt { le seul, le vrai } ~ " Libre as a Pengouin "
- DIY - Debian Sid | Devuan Ceres
----
Ne réponds pas aux PM d'assistance
Avatar du membre
Arnaud
Membre
Membre
Messages : 162
Enregistré le : 23 avr. 2016, 14:31
Localisation : Allemagne
Status : Hors ligne

Il y a peut-être un conflit d'objets entre les deux instances tk.
Au lieu d'utiliser un objet Tk pour le menu About, essaye plutôt un Toplevel.
Avatar du membre
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Enregistré le : 23 avr. 2016, 23:37
Localisation : 47/FR
Diaspora* : https://framasphere.org/u/hucste
Contact :
Status : Hors ligne

cad ?
déclarer ainsi :

Code : Tout sélectionner

class gui(object):
mais après ce pose le problème de déclarations des objets tk.Tk...
PengouinPdt { le seul, le vrai } ~ " Libre as a Pengouin "
- DIY - Debian Sid | Devuan Ceres
----
Ne réponds pas aux PM d'assistance
Avatar du membre
Arnaud
Membre
Membre
Messages : 162
Enregistré le : 23 avr. 2016, 14:31
Localisation : Allemagne
Status : Hors ligne

Non, dans window_about.py :

Code : Tout sélectionner

class gui(tk.Tk):
    ''' Display a GUI for window about'''

    def __init__(self, parent, init):
        tk.Toplevel.__init__(self, parent)
        self.parent = parent
Avatar du membre
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Enregistré le : 23 avr. 2016, 23:37
Localisation : 47/FR
Diaspora* : https://framasphere.org/u/hucste
Contact :
Status : Hors ligne

oui, j'avais compris que tu parlais de ce script...
mais comment tu fais... parce qu'après tous les appels tk ne répondent plus, dont le premier concernant le grid...
PengouinPdt { le seul, le vrai } ~ " Libre as a Pengouin "
- DIY - Debian Sid | Devuan Ceres
----
Ne réponds pas aux PM d'assistance
Avatar du membre
Arnaud
Membre
Membre
Messages : 162
Enregistré le : 23 avr. 2016, 14:31
Localisation : Allemagne
Status : Hors ligne

Le programme se lance correctement chez moi, je n'ai pas eu le temps de tester en détail.
Qu'est-ce que tu entends par "la méthode grid ne répond plus" ?
Tu peux préciser ?
Avatar du membre
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Enregistré le : 23 avr. 2016, 23:37
Localisation : 47/FR
Diaspora* : https://framasphere.org/u/hucste
Contact :
Status : Hors ligne

Je ne comprends pas ce que tu me demandes de faire : "remplacer par TopLevel", et ensuite ?!

Oui, la fenêtre "window_about" s'affiche mais pas l'image dedans.
PengouinPdt { le seul, le vrai } ~ " Libre as a Pengouin "
- DIY - Debian Sid | Devuan Ceres
----
Ne réponds pas aux PM d'assistance
Avatar du membre
Arnaud
Membre
Membre
Messages : 162
Enregistré le : 23 avr. 2016, 14:31
Localisation : Allemagne
Status : Hors ligne

Oui, tu as raison, j'ai oublié de dire que j'avais ajouté un objet PIL dans window_about.py :

Code : Tout sélectionner

    def ui(self):
        '''Displaying UI'''
        # Frame for service informations
        frm_service = ttk.Frame(self)
        frm_service.grid(row=7, column=1)

        ## Add an image logo
        logo_open = pimg.open(self.logo)
        self.img2_logo = pimgtk.PhotoImage(logo_open)
        
        img_service = ttk.Label(frm_service, image=self.img2_logo)
        img_service.grid(row=0, column=0, rowspan=2)
        
Avatar du membre
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Enregistré le : 23 avr. 2016, 23:37
Localisation : 47/FR
Diaspora* : https://framasphere.org/u/hucste
Contact :
Status : Hors ligne

Eh, bien, tu as bien de la chance... car moi, ça ne fonctionne pas !

Code : Tout sélectionner

class gui(tk.Tk):
    ''' Display a GUI for window about'''

    def __init__(self, parent, init):
        tk.Tk.__init__(self, parent)
        self.parent = parent

        # initialise self
        if isinstance(init, dict):
            for i in init:
                setattr(self, i, init[i])
                print(f'self.{i}: {init[i]}')

        self.initialize()
    
    def initialize(self):
        '''Initialize window'''
        self.grid()

        self.display_icon()
        self.ui()

        self.update()
        self.geometry(self.geometry())

    def display_icon(self):
        '''Manage icon'''
        self.wm_iconbitmap(r'@'+self.icon)
        #logo = pimg.open(self.logo)
        #icon = pimgtk.PhotoImage(logo)
        #self.call('wm', 'iconphoto', self, icon)

    def on_btn_close_clicked(self):
        '''  '''
        self.quit()
        self.destroy()

    def ui(self):
        '''Displaying UI'''
        # Frame for service informations
        frm_service = ttk.Frame(self)
        frm_service.grid(row=7, column=1)

        ## Add an image logo
        #print(f'{self.logo}')
        img = pimg.open(self.logo)
        icon = pimgtk.PhotoImage(img)
        #logo = tk.PhotoImage(file=self.logo)
        img_service = ttk.Label(frm_service, image=icon)
        img_service.grid(row=0, column=0, rowspan=2)
Encore et toujours le même message d'erreur :

Code : Tout sélectionner

Exception in Tkinter callback
Traceback (most recent call last):
  File "/usr/local/lib/python3.6/tkinter/__init__.py", line 1699, in __call__
    return self.func(*args)
  File "~/YUP.py/modules/gui.py", line 89, in about
    about = gui(None, init)
  File "~/YUP.py/modules/about.py", line 34, in __init__
    self.initialize()
  File "~/YUP.py/modules/about.py", line 41, in initialize
    self.ui()
  File "~/YUP.py/modules/about.py", line 69, in ui
    img_service = ttk.Label(frm_service, image=icon)
  File "/usr/local/lib/python3.6/tkinter/ttk.py", line 761, in __init__
    Widget.__init__(self, master, "ttk::label", kw)
  File "/usr/local/lib/python3.6/tkinter/ttk.py", line 559, in __init__
    tkinter.Widget.__init__(self, master, widgetname, kw=kw)
  File "/usr/local/lib/python3.6/tkinter/__init__.py", line 2293, in __init__
    (widgetName, self._w) + extra + self._options(cnf))
_tkinter.TclError: image "pyimage3" doesn't exist
PengouinPdt { le seul, le vrai } ~ " Libre as a Pengouin "
- DIY - Debian Sid | Devuan Ceres
----
Ne réponds pas aux PM d'assistance
Avatar du membre
Arnaud
Membre
Membre
Messages : 162
Enregistré le : 23 avr. 2016, 14:31
Localisation : Allemagne
Status : Hors ligne

Dans ton init, tu n'as pas remplacé l'objet Tk par un Toplevel :

Code : Tout sélectionner

    def __init__(self, parent, init):
        tk.Toplevel.__init__(self, parent)
        self.parent = parent
Dans ce cas, l'image s'affiche, pas testé le reste du programme, mais cela semble répondre normalement.
Avatar du membre
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Enregistré le : 23 avr. 2016, 23:37
Localisation : 47/FR
Diaspora* : https://framasphere.org/u/hucste
Contact :
Status : Hors ligne

Non, seulement, avec le TopLevel, je n'ai plus de message d'erreur, mais en appelant directement l'objet 'self.img_logo', ainsi - sans avoir à redéclarer un objet PIL - cela fonctionne enfin !

Code : Tout sélectionner

 ## Add an image logo
        img_service = ttk.Label(frm_service, image=self.img_logo)
        img_service.grid(row=0, column=0, rowspan=2)
Merci à toi
:041:
PengouinPdt { le seul, le vrai } ~ " Libre as a Pengouin "
- DIY - Debian Sid | Devuan Ceres
----
Ne réponds pas aux PM d'assistance
Répondre