Problème affichage image TKINTER

Fermé
spots_727 - Modifié le 25 mai 2021 à 12:10
 Spirali - 27 mai 2021 à 22:15
Bonjour,

Mon but étant de refaire Netflix en python, je devais commencer par le menu de sélection de profile.
Mais premièrement : je n'ai pas trouvé de moyen efficace pour stocker mes profiles avec plusieurs valeurs.
Et de deux : Lorsque j'affiches mes boutons avec l'image de chaque profile, les images par défauts fonctionnent mais celles des profiles : seul la dernière est affichée.
Une image d'illustration : https://ibb.co/wg8ycD8

Je serais ravi si vous pouviez m'aider, merci d'avance. PS : j'ai la dernière version de python, je suis sous Window 10, et les chemins d'accès pour chaque fichier sont bien spécifier.

mon code :

# On importe le module Tkinter
from sys import builtin_module_names
from tkinter import *
from typing import Any
import pyautogui
import json
import tkinter.font as tkfont
import ctypes

def profile_load(img, command):
global x
button = Button(canvas, height=150, width=150, image=img, bg="white", activebackground="grey", border=0, command=command)
x += 0.2
height_profile = height / 2 * x
canvas.create_window(height_profile, width / 2, window=button)

def add_new_profile():
window = Toplevel()
window.mainloop()

def hugo():
ctypes.windll.user32.MessageBoxW(0, "Vous pouvez à présent fermer cette fenêtre !", "API", 1)

height, width = pyautogui.size()
display_height = str(height)
display_width = str(width)
fichier = (open("ressources/tampon/display_size.txt", "r"))
size = fichier.read()
window = Tk()
window.title("NETFLIX")
window.geometry(size)
fichier.close()
window.maxsize(height, width)
window.minsize(height, width)
window.state('zoomed')
window.iconbitmap("ressources/icon/foxyvati.ico")
canvas = Canvas(window, width=height, height=width, bg="black")
canvas.create_image(height / 2, width / 2)
canvas.pack()

class Profile:
def __init__(self):
self.id = 0
self.name = "Add"
self.icon = PhotoImage(file="plus_profile.png")
self.command = add_new_profile

x = 0.4
nb_profile = 0

profiles_data = open("ressources/tampon/profiles.json", "r")
dict = json.load(profiles_data)

default_profiles = Profile()

nb_of_profile = len(dict)

# Fonctionne mais n'affiche que la dernière images des profiles, sinon le default_img fonctionne
for i in range(5):
if nb_profile < nb_of_profile:
nb_profile += 1
hey = Profile()
hey.icon = PhotoImage(file=dict[str(nb_profile)])
hey.command = hugo
profile_load(hey.icon, hey.command)
else:
profile_load(default_profiles.icon, default_profiles.command)

window.bind("<Escape>", COMMAND)

window.mainloop()

Et le contenu de profiles.json :

{"1":"hugo.png", "2":"squirrel.png"}




Configuration: Windows / Chrome 90.0.4430.212
A voir également:

6 réponses

Bonjour.

>>># Fonctionne mais n'affiche que la dernière images des profiles, sinon le default_img fonctionne

Ce ne serait pas plutôt parce que tu empiles tes boutons les uns sur les autres ?
Pourquoi d'ailleurs utiliser create_windows que simplement les méthodes de positionnement comme pack ou encore grid ?
0
J'utilise create_window car j'ai réutilisé un bout de code qui venait d'un programme où j'avais une image en arrière plan. Pour répondre à ta question sur le positionnement des boutons, voici une vidéo car c'est plus simple pour expliquer : https://www.youtube.com/watch?v=rXPMiOVVfDE
0
Non mais une vidéo pour expliquer un problème XD

Difficile de lire ton code sans indentation...
À part dire que ton image hugo.png est transparente, je ne vois pas, désolé...

Sinon, dict est un mot réservé de python, c'est essentiel de ne pas utiliser les mots clefs de python comme noms de variables au risque d'avoir des problèmes.
0
Sans indentations ? J'ai jamais compris ce que ça voulez dire mdr ! Et j'utilise dict justement pour récupérer ce qu'il y a dans le dictionnaire contenu dans profiles.json
Indenté, ce n'est pas avec des tabs ? Et pour spécifier, si je retire la 2e photo de profiles.json, cela fonctionne comme ci-dessous : https://ibb.co/D7Wk5Cd
0
dict est une classe native de python, c'est comme list, tuple, str, int, etc.
Si tu les écrases avec autre chose, ça va boguer, en fait je suis même sûr que c'est ça qui fait que ça bogue...

Un code pas indenté et peu lisible :

for i in range(5):
if nb_profile < nb_of_profile:
nb_profile += 1
hey = Profile()
hey.icon = PhotoImage(file=dict[str(nb_profile)])
hey.command = hugo
profile_load(hey.icon, hey.command)
else:
profile_load(default_profiles.icon, default_profiles.command)


Un code indenté et lisible à l'aide du bouton de mise en forme du forum :

for i in range(5):
    if nb_profile < nb_of_profile:
        nb_profile += 1
        hey = Profile()
        hey.icon = PhotoImage(file=dict[str(nb_profile)])
        hey.command = hugo
        profile_load(hey.icon, hey.command)
    else:
        profile_load(default_profiles.icon, default_profiles.command)
0
Quel bouton ?
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Mon code plus lisible :
# On importe le module Tkinter
from sys import builtin_module_names
from tkinter import *
from typing import Any
import pyautogui
import json
import tkinter.font as tkfont
import ctypes

def profile_load(img, command):
   global x
   button = Button(canvas, height=150, width=150, image=img, 
   bg="white", activebackground="grey", border=0, 
   command=command)
   x += 0.2
   height_profile = height / 2 * x
   canvas.create_window(height_profile, width / 2, window=button)

def add_new_profile():
   window = Toplevel()
   window.mainloop()

def hugo():
   ctypes.windll.user32.MessageBoxW(0, "Vous pouvez à présent 
   fermer cette fenêtre !", "API", 1)

height, width = pyautogui.size()
display_height = str(height)
display_width = str(width)
fichier = (open("ressources/tampon/display_size.txt", "r"))
size = fichier.read()
window = Tk()
window.title("NETFLIX")
window.geometry(size)
fichier.close()
window.maxsize(height, width)
window.minsize(height, width)
window.state('zoomed')
window.iconbitmap("ressources/icon/foxyvati.ico")
canvas = Canvas(window, width=height, height=width, bg="black")
canvas.create_image(height / 2, width / 2)
canvas.pack()

class Profile:
   def __init__(self):
      self.id = 0
      self.name = "Add"
      self.icon = PhotoImage(file="plus_profile.png")
      self.command = add_new_profile

x = 0.4
nb_profile = 0

profiles_data = open("ressources/tampon/profiles.json", "r")
dict = json.load(profiles_data)

default_profiles = Profile()

nb_of_profile = len(dict)

# Fonctionne mais n'affiche que la dernière images des profiles, sinon le default_img fonctionne
for i in range(5):
   if nb_profile < nb_of_profile:
   nb_profile += 1
   hey = Profile()
   hey.icon = PhotoImage(file=dict[str(nb_profile)])
   hey.command = hugo
   profile_load(hey.icon, hey.command)
else:
   profile_load(default_profiles.icon, default_profiles.command)

window.bind("<Escape>", COMMAND)

window.mainloop()
0
La référence des images a besoin d'être gardée dans un coin, car sinon python les supprime automatiquement de la mémoire.

Une simple variable de classe suffit.

class Profile:
    images = []
    def __init__(self, image_path):
        self.id = 0
        self.name = "Add"
        self.icon = tk.PhotoImage(file=image_path)
        self.images.append(self.icon)
        self.command = add_new_profile


Ta boucle peu aussi revue simplement :

profiles_data = open("profiles.json", "r")
dico = json.load(profiles_data)

default_profiles = Profile("plus_profile.png")

for i in range(1, 6):
    i = str(i)
    if i in dico:
        hey = Profile(dico[i])
        profile_load(hey.icon, hey.command)
    else:
        profile_load(default_profiles.icon, default_profiles.command)
0
spots_727 > Spirali
Modifié le 26 mai 2021 à 09:07
Je viens de tester le programme, il fonctionne parfaitement. Merci énormément. Connaissais vous un moyen de changer ce qui est dans la fenêtre car je m'embête à exécuter de nouvelle fenêtre alors que peut-être y a t'il un moyen de garder toujours le même script mais qui peut changer ce qu'il y a dedans. Cela me permettrais aussi de récupérer sur quel bouton j'ai cliqué lors de la sélection de profile pour pouvoir afficher la fenêtre qui correspond au bon utilisateur? Connaissez vous aussi un moyen de changer la couleur de la barre window en haut? Un problème majeur que je rencontre aussi est que je suis obligé de stocker avec des nombres les profiles dans le fichier json, ce qui fait que je ne peux pas mettre un nom associer pour chaque profile sur les boutons, n'y a t-il pas un moyen de faire en sorte de stocker avec les noms de le fichier json ?
Merci d'avance
0
Spirali > spots_727
26 mai 2021 à 12:34
Bonjour.

>>>Je viens de tester le programme, il fonctionne parfaitement. Merci énormément.

Je t'en prie, et pas de vouvoiement sur les forums ^^

>>>Connaissez-vous un moyen de changer ce qui est dans la fenêtre car je m'embête à exécuter de nouvelle fenêtre alors que peut-être y-a-t-il un moyen de garder toujours le même script mais qui peut changer ce qu'il y a dedans. Cela me permettrait aussi de récupérer sur quel bouton j'ai cliqué lors de la sélection de profile pour pouvoir afficher la fenêtre qui correspond au bon utilisateur?

Faudrait être un peu plus clair, de quelle fenêtre parles-tu ? La principale ? une Toplevel ?
Mais de toute façon, oui, le contenu d'une fenêtre peut être modifié à loisir.

>>>Connaissez vous aussi un moyen de changer la couleur de la barre window en haut?

Si tu parles de la bordure de fenêtre, non ce n'est pas possible puisque c'est géré par le système d'exploitation en fonction du thème graphique défini par l'utilisateur, sur linux ça s'intègre très bien, en revanche sur windows, pas certain que tkinter s'accorde bien avec et que ce soit aussi facile pour tcl/tkinter.

>>>Un problème majeur que je rencontre aussi est que je suis obligé de stocker avec des nombres les profiles dans le fichier json, ce qui fait que je ne peux pas mettre un nom associer pour chaque profile sur les boutons, n'y a t-il pas un moyen de faire en sorte de stocker avec les noms du fichier json ?

Pareil, j'ai un peu de mal à saisir ce que tu souhaites faire, dans ton fichier json, tu peux y ajouter ce que tu veux comme données, je ne vois donc pas ce qui pose souci, un exemple de ce que tu souhaites obtenir vaut mieux que de longues explications.

Quelques remarques sur ton code.

Inutile de se servir du module pyautogui uniquement pour connaitre la dimension de l'écran, tkinter peut la fournir avec window.winfo_screenwidth() et window.winfo_screenheight()

Pourquoi le geometry est chargé depuis un fichier ?

À quoi sert la fonction hugo et surtout pourquoi utiliser ctype ?

Le window.bind("<Escape>", COMMAND) ne sert à rien, COMMAND n'est pas une fonction mais une constante qui contient, suspens..., "command".

Tes fonctions load_profile et add_new_profile auraient tout bénéfice à être intégrées comme méthodes de la classe Profile.
0
spots_727 > Spirali
26 mai 2021 à 13:04
>>>Faudrait être un peu plus clair, de quelle fenêtre parles-tu ? La principale ? une Toplevel ?
Mais de toute façon, oui, le contenu d'une fenêtre peut être modifié à loisir.

Par exemple passé du menu de sélection de profil à la fenêtre de chargement sans que ce soit 2 scripts différents.

>>>Pareil, j'ai un peu de mal à saisir ce que tu souhaites faire, dans ton fichier json, tu peux y ajouter ce que tu veux comme données, je ne vois donc pas ce qui pose souci, un exemple de ce que tu souhaites obtenir vaut mieux que de longues explications.

Le problème c'est que mon fichier json ressemble à ça :
{"1":"ressources/images/hugo.png", "2":"ressources/images/squirrel.png", "3":"ressources/images/papa.png"}
Cela veut dire que pour aller chercher les infos du fichier dans la boucle :
for i in range(1, 6):
    i = str(i)
    if i in dico:
        hey = Profile(dico[i])
        if i == "1":
            hey.command = hugo
            hey.name = "Hugo"
        elif i == "2":
            hey.command = maman
            hey.name = "Maman"
        elif i== "3":
            hey.command = papa
            hey.name = "Papa"
        profile_load(hey.icon, hey.command, hey.name)
    else:
        profile_load(default_profiles.icon, default_profiles.command, default_profiles.name)

je doit forcément mettre comme key un nombre, sauf que si je veux associer un nom à son image comme par exemple : {"Hugo":"ressources/images/hugo.png", "Maman":"ressources/images/squirrel.png", "Papa":"ressources/images/papa.png"}
La boucle ne fonctionnera plus et les profiles ne s'afficheront pas.

>>>Inutile de se servir du module pyautogui uniquement pour connaitre la dimension de l'écran, tkinter peut la fournir avec window.winfo_screenwidth() et window.winfo_screenheight()

Je pensais que window.winfo_screenwidth() et window.winfo_screenheight() donné seulement la taille de l'application et nom de l'écran "physique comme un 26 pouces par exemple" et je vais le chercher dans un fichier car je ne demande la taille de l'écran qu'une seule fois et j'ai juste à aller pioché dans les autres programmes, cela optimise le script.

>>>À quoi sert la fonction hugo et surtout pourquoi utiliser ctype ?

hugo servait juste à vérifier que mon code fonctionne, ctype car je ne connais pas d'autre moyen.

>>>Le window.bind("<Escape>", COMMAND) ne sert à rien, COMMAND n'est pas une fonction mais une constante qui contient, suspens..., "command".

Je sais, c'était un rappel pour ne pas que j'oublies de le faire.

Voilà mon code mise à jour, ne tient pas compte de la partie où je charge des fichiers et je regarde si c'est True ou False, c'est une partie pour faire en sorte qu'il n'y est pas de retour windows entre chaque lancement de nouvelle fenêtre, c'est plus esthétique et c'est à peu près le résultat de : "Par exemple passé du menu de sélection de profil à la fenêtre de chargement sans que ce soit 2 scripts différents."

# On importe le module Tkinter
from sys import builtin_module_names
from tkinter import *
from typing import Any
import pyautogui
import json
import tkinter.font as tkfont
import ctypes
import subprocess
from playsound import playsound

def profile_load(img, command, name):
    global x
    def go_in(event):
        button['bg']="white"
        label['fg']="white"
    def go_out(event):
        button['bg']="#141414"
        label['fg']="grey"
    helvetica = tkfont.Font(family='Helvetica', size=10, weight='bold')
    button = Button(canvas, height=150, width=150, image=img, bg="#141414", activebackground="grey", command=command)
    label = Label(canvas, text=name, fg="grey", bg="#141414")
    label['font'] = helvetica
    button.bind("<Enter>", go_in)
    button.bind("<Leave>", go_out)
    x += 0.2
    height_profile = height / 2 * x
    canvas.create_window(height_profile, width / 2, window=button)
    canvas.create_window(height_profile, width / 2 + 100, window=label)

def verif():
    launch = open("ressources/tampon/launched.json", "r")
    launch_data = json.load(launch)
    if launch_data["LAUNCHED"] == "False":
        launch.close()
        window.after(500, verif)
    elif launch_data["LAUNCHED"] == "True":
        launch_data = open("ressources/tampon/launched.json", "r")
        launched_dict = json.load(launch_data)
        launched_dict["LAUNCHED"] = "False"
        launched_redict = open("ressources/tampon/launched.json", "w")
        json.dump(launched_dict, launched_redict)
        launch_data.close()
        launched_redict.close()
        window.destroy()
    window.after(500, verif)

def add_new_profile():
    window = Toplevel()
    window.mainloop()

def hugo():
    subprocess.Popen(("loading_screen", "loading_screen.exe"))
    verif()

def maman():
    subprocess.Popen(("loading_screen", "loading_screen.exe"))
    verif()

def papa():
    subprocess.Popen(("loading_screen", "loading_screen.exe"))
    verif()

def refresh():
    subprocess.Popen(("Netflix", "Netflix.exe"))
    window.destroy()

def submit(event):
    hugo()

def go_in(event):
        edit_button['fg']="white"

def go_out(event):
    edit_button['fg']="grey"

def edit_profile():
    subprocess.Popen(("edit_profile_page", "edit_profile_page.exe"))
    verif()

launch_data = open("ressources/tampon/launched.json", "r")
launched_dict = json.load(launch_data)
launched_dict["LAUNCHED"] = "True"
launched_redict = open("ressources/tampon/launched.json", "w")
json.dump(launched_dict, launched_redict)
launch_data.close()
launched_redict.close()

height, width = pyautogui.size()
display_height = str(height)
display_width = str(width)
fichier = (open("ressources/tampon/display_size.txt", "r"))
size = fichier.read()
window = Tk()
window.title("Netflix")
window.geometry(size)
fichier.close()
window.maxsize(height, width)
window.minsize(height, width)
window.state('zoomed')
window.iconbitmap("ressources/icon/netflix.ico")
canvas = Canvas(window, width=height, height=width, bg="#141414")
canvas.create_image(height / 2, width / 2)
canvas.pack()

helvetica = tkfont.Font(family='Helvetica', size=40, weight='bold')
wich_profile_lbl = Label(canvas, text="Qui est-ce ?", fg="white", bg="#141414")
wich_profile_lbl['font'] = helvetica
canvas.create_window(height / 2, 3.75 * (width / 10), window=wich_profile_lbl)

logo_img = PhotoImage(file="ressources/images/netflix_logo.png")
logo = Button(canvas, image=logo_img, bg="#141414", activebackground="#141414", command=refresh, height=50, width=100, border=0)
canvas.create_window(height / 20, width / 20, window=logo)

helvetica = tkfont.Font(family='Helvetica', size=20, weight='bold')
edit_button = Button(canvas, text="GÉRER LES PROFILS", bg="#141414", fg="grey", activebackground="#141414", command=edit_profile)
edit_button['font'] = helvetica
canvas.create_window(height / 2, 7 * (width / 10), window=edit_button)

edit_button.bind("<Enter>", go_in)
edit_button.bind("<Leave>", go_out)

class Profile:
    images = []
    def __init__(self, image_path):
        self.id = 0
        self.name = "Add"
        self.icon = PhotoImage(file=image_path)
        self.images.append(self.icon)
        self.command = add_new_profile

x = 0.4
nb_profile = 0

profiles_data = open("ressources/tampon/profiles.json", "r")
dico = json.load(profiles_data)

default_profiles = Profile("ressources/images/plus_profile.png")

for i in range(1, 6):
    i = str(i)
    if i in dico:
        hey = Profile(dico[i])
        if i == "1":
            hey.command = hugo
            hey.name = "Hugo"
        elif i == "2":
            hey.command = maman
            hey.name = "Maman"
        elif i== "3":
            hey.command = papa
            hey.name = "Papa"
        profile_load(hey.icon, hey.command, hey.name)
    else:
        profile_load(default_profiles.icon, default_profiles.command, default_profiles.name)

window.bind("<Right>", submit)

window.mainloop()
0
Spirali > spots_727
26 mai 2021 à 14:30
Comment peux-tu t'y retrouver dans un tel bazar ?
Ton code est cafouillis, rien qu'au départ déjà tu importes des modules dont tu ne te sers pas.
Franchement, tu n'arriveras à rien sans un minimum de rigueur, enfin, fais comme tu le sens, mais je trouve que tout ça est bien mal parti :/

window.winfo_screenwidth
retourne la largeur de l'écran,
window.winfo_width
donne la taille de la fenêtre, donc je répète que pyautogui n'a pas grand chose à faire dans ton code.

En ce qui concerne ton problème de json, une solution est de le mettre dans un itérable indexable.

data = {
    "Hugo":"ressources/images/hugo.png",
    "Maman":"ressources/images/squirrel.png",
    "Papa":"ressources/images/papa.png"
}

fonctions = dict(
    hugo=lambda: print('fonction hugo'),
    maman=lambda: print('fonction maman'),
    papa=lambda: print('fonction papa'),
)


Puis

data_list = tuple(data)
for i in range(5):
    try:
        key = data_list[i]
        print('key : ', key, ', value : ', data[key])
        fonctions[key.lower()]()
    except IndexError:
        print('default value')


On peut encore faire autrement avec un simple compteur et compléter ce qu'il manque à la suite si les exceptions c'est pas encore ton truc.
Cette solution est de loin la plus simple.

i = 0
for key, value in data.items():
    print(key, value)
    fonctions[key.lower()]()
    i += 1
for _ in range(i, 5):
    print('default value')


Ou encore autrement en utilisant la fonction zip_longest du module itertools.
0
Je testerai cela demain, en attendant merci pour ta réponse, bonne soirée.
0