Problème affichage image TKINTER

Signaler
-
 Spirali -
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

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 ?
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
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.
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
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)
Quel bouton ?
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()
> spots_727
Bonjour.

Je n'ai rien compris.
Ton application est une simple fenêtre possédant des boutons pour lancer des exécutables, j'imagine que c'est pour faire un simple menu, ce sont des exécutables fenêtrés lancés ?
Ces exécutables agissent sur le json launched ?
Ta fenêtre tkinter doit se fermer si un bouton est pressé et donc une app externe lancée ?
Parce que là, je n'arrive pas à comprendre la logique de cette fonction verif.
Il faudrait un peu décrire la chronologie de ton script et ce qu'il se passe avec ces exe.

Si c'est simplement une histoire de focus de fenêtre, tkinter propose plusieurs méthodes avec les focus_* et grab_*

Mais sinon, ça fonctionne comme tu veux ou y a encore des problèmes ?
> Spirali
Les exécutables sont des scripts pour lancer une fenêtre. Ils agissent sur le json launched, je vais te faire la chronologie :
Je lance script1.py, lorsque je j'appuie sur le bouton cela ferme script1.py et lance script2.py. Jusque là tout va bien mais entre la fermeture de script1.py et le lancement de script2.py, tu seras d'accord pour dire qu'il y a un délai plus ou moins long selon la puissance de l'ordinateur.
Tu seras aussi d'accord pour dire que pendant ce délai, rien n'est affiché (autrement dit on voit le bureau windows ou les autres applications lancées sur l'ordinateur)
Ce bout de code marche comme cela :
Je lance script1.py et je clique sur le bouton, le bouton va lancer script2.py et vérifier si le json launched contient True, si oui il ferme script1.py. Il reste donc en standbye puisque le json launched contient False. Lors du lancement de script2.py, je lui dit de mettre True dans le json launched. script1.py toujours dans sa boucle remarque que le json launched contient True et ferme donc scipt.py. Donc pas de temps "morts" où l'on voit le bureau window, ou autrement dit script1.py atteint que script2.py soit lancé pour se fermer. C'est pour cela que je voudrais un moyen de changer le contenu de la fenêtre de script1.py pour éviter de lancer de nouveaux scripts pour chaque nouvelle fenêtre.
> spots_727
A moins d'avoir une tortue en guise de pc, ou que les applications sont relativement conséquentes, c'est quand même très rapide, et quasi instantané avec 2 fenêtres tkinter python ultras légères.

Changer le contenu d'une fenêtre tkinter ça se résume à jouer avec les pack et pack_forget (ou grid).
> Spirali
Même si le délai est de seulement 1 seconde ou moins, cela est moins esthétique. N'y a t-il pas un moyen de faire comme en Kotlin pour les applications android ? D'avoir Une fenêtre est de venir y incorporé des fragments, et de pouvoir choisir quel fragment insérer à chaque fois que l'on veut ?
> spots_727
Je ne connais pas ce kotlin, à priori langage de prog destiné à développer des applications, quel est donc le rapport ?

On dirait que tu parles de wysiwyg, et pareil, c'est le genre de truc sympa pour faire des choses très très simples, dès lors que l'on souhaite quelque chose de plus complexe et plus spécifique, on est bien obligé de mettre les mains dans le cambouis.

Je ne sais si en python il existe une bibliothèque graphique permettant de faire ça, ou un truc développé par quelqu'un, j'ai comme un gros doute.

Dans les sources du module tkinter, il y a un exemple de fichier drag and drop, il se nomme dnd.py, et c'est pas très facile à faire =)
Mais tu peux toujours regarder comme c'est réalisé.

Donc, t'as pas trop le choix, et puis c'est pas très difficile de gérer les pack, pack_forget.

Exemple minimaliste.

import tkinter as tk

window = tk.Tk()
window.geometry('500x350')

def show_content_1():
    global current_content
    content = tk.Frame(window)
    lbl = tk.Label(content, text="contenu 1")
    lbl.pack()
    bt = tk.Button(content, text="show 2", command=show_content_2)
    bt.pack()
    try:
        current_content.pack_forget()
    except AttributeError:
        pass
    current_content = content
    content.pack()

def show_content_2():
    global current_content
    content = tk.Frame(window)
    lbl = tk.Label(content, text="contenu 2")
    lbl.pack()
    bt = tk.Button(content, text="show 1", command=show_content_1)
    bt.pack()
    try:
        current_content.pack_forget()
    except AttributeError:
        pass
    current_content = content
    content.pack()

C'est pas très sorcier à faire.
current_content = None
show_content_1()

window.mainloop()
Je testerai cela demain, en attendant merci pour ta réponse, bonne soirée.