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

Tout ce qui concerne la programmation.
Répondre
Avatar de l’utilisateur
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Inscription : 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 de l’utilisateur
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Inscription : 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 de l’utilisateur
Arnaud
Membre
Membre
Messages : 162
Inscription : 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 de l’utilisateur
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Inscription : 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 de l’utilisateur
Arnaud
Membre
Membre
Messages : 162
Inscription : 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 de l’utilisateur
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Inscription : 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 de l’utilisateur
Arnaud
Membre
Membre
Messages : 162
Inscription : 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 de l’utilisateur
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Inscription : 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 de l’utilisateur
Arnaud
Membre
Membre
Messages : 162
Inscription : 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 de l’utilisateur
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Inscription : 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 de l’utilisateur
Arnaud
Membre
Membre
Messages : 162
Inscription : 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 de l’utilisateur
PengouinPdt
Contributeur
Contributeur
Messages : 1343
Inscription : 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