Problème de sauvegarde.

Résolu/Fermé
Lapwace Messages postés 5 Date d'inscription jeudi 19 janvier 2023 Statut Membre Dernière intervention 19 janvier 2023 - 19 janv. 2023 à 13:41
Lapwace Messages postés 5 Date d'inscription jeudi 19 janvier 2023 Statut Membre Dernière intervention 19 janvier 2023 - 19 janv. 2023 à 23:22

Bonjour, je suis débutant en python et pour m'entrainer j'essaye de faire un r/place like pour mes amis et moi.

Il est encore très archaïque mais je rencontre déjà 2 problèmes assez similaire que je voudrais résoudre avant de faire la suite.

Le premier survient quand je met un pixel d'une certaine couleur puis que je le change de couleur , si j'enregistre le canvas le pixel s'enregistre sous le nom "x,y, ".

Pour vous donner un exemple si je met la couleur rouge sur le pixel en coordonné (10,10) et que je sauvegarde, dans le fichier csv la cellule est bien "10,10,red". Mais si je rechange le pixel en bleu et que je resauvegarde dans le csv il est inscrit "10,10," au lieu de "10,10,blue".

Et pour le deuxième problème c'est un peu pareil mais au niveau du chargement du csv, si je charge un csv les pixels prennent bien la couleur qu'ils doivent avoir sur le canvas mais si je sauvegarde, dans le csv la cellule redeviens "x,y,"

Voici le code:
 

import tkinter as tk
import csv
 
root = tk.Tk()
root.title("App Pixel")
root.state('zoomed')
 
def draw_pixel():
    x = int(x_coordinate.get())
    y = int(y_coordinate.get())
    pixel_color = color.get()
    canvas.create_rectangle(x, y, x, y, fill=pixel_color,width=0,tags=(f"pixel_{x}_{y}"))
 
def save_to_csv():
    with open("canvas_content.csv", "w", newline="") as f:
        writer = csv.writer(f)
        for x in range(1000):
            for y in range(1000):
                color = canvas.itemcget(canvas.find_withtag(f"pixel_{x}_{y}"), "fill")
                writer.writerow([x, y, color])
 
def load_from_csv():
    with open("canvas_content.csv", "r") as f:
        reader = csv.reader(f)
        for row in reader:
            x, y, color = row
            if color != "":
                canvas.create_rectangle(int(x), int(y), int(x), int(y), fill=color,width=0)
 
 
x_coordinate = tk.StringVar()
y_coordinate = tk.StringVar()
color = tk.StringVar()
 
frame=tk.Frame(root)
frame.pack(expand=True, fill='both')
 
frame_Menu=tk.Frame(frame)
frame_Menu.grid(row=0, column=0, sticky="N")
 
frame_Canvas=tk.Frame(frame)
frame_Canvas.grid(row=0, column=2, sticky="W")
 
x_entry = tk.Entry(frame_Menu, textvariable=x_coordinate)
x_entry.grid(row=0, column=0, pady=1, sticky="N")
x_entry.config(bd=1, relief="solid")
 
y_entry = tk.Entry(frame_Menu, textvariable=y_coordinate)
y_entry.grid(row=1, column=0, sticky="N")
y_entry.config(bd=1, relief="solid")
 
color_entry = tk.Entry(frame_Menu, textvariable=color)
color_entry.grid(row=2, column=0, pady=1, sticky="N")
color_entry.config(bd=1, relief="solid")
 
draw_button = tk.Button(frame_Menu, text="Dessiner", command=draw_pixel)
draw_button.grid(row=3, column=0, sticky="N")
 
save_button = tk.Button(frame_Menu, text="Sauvegarder", command=save_to_csv)
save_button.grid(row=4, column=0, sticky="N")
 
load_button = tk.Button(frame_Menu, text="Charger", command=load_from_csv)
load_button.grid(row=5, column=0, sticky="N")
 
close_button = tk.Button(frame_Menu, text="Fermer", command=root.destroy)
close_button.grid(row=6, column=0, sticky="N")
 
canvas = tk.Canvas(frame_Canvas, width=1000, height=1000)
canvas.grid(row=0, column=0, rowspan=1, sticky="NSEW")
canvas.config(bd=1, relief="solid")
 
root.mainloop()
A voir également:

3 réponses

Salut, cela vient du fait que tu affectes autant de fois le tag de ton rectangle que tu n'en crées.

.

Donc vérifier, que le tag n'existe pas avant de créer ton rectangle, sinon, modifier sa couleur.

De plus quel intérêt d'enregistrer une liste de points ? Enregistre seulement s'il y a une couleur.

.

import tkinter as tk
import csv

WIDTH = 100
HEIGHT = 100

root = tk.Tk()
root.title("App Pixel")
# root.state('zoomed') # fonctionne pas sur Linux


def draw_pixel():
    x = int(x_coordinate.get())
    y = int(y_coordinate.get())
    pixel_color = color.get()
    rects = canvas.find_withtag(f"pixel_{x}_{y}")
    if rects:
        canvas.itemconfig(rects[0], fill=pixel_color)
    else:
        canvas.create_rectangle(
            x, y, x, y, fill=pixel_color, width=0, tags=(f"pixel_{x}_{y}")
        )


def save_to_csv():
    with open("canvas_content.csv", "w", newline="") as f:
        writer = csv.writer(f)
        for x in range(WIDTH):
            for y in range(HEIGHT):
                color = canvas.itemcget(canvas.find_withtag(f"pixel_{x}_{y}"), "fill")
                if color:
                    writer.writerow([x, y, color])


def load_from_csv():
    with open("canvas_content.csv", "r") as f:
        reader = csv.reader(f)
        for row in reader:
            x, y, color = row
            canvas.create_rectangle(int(x), int(y), int(x), int(y), fill=color, width=0)


x_coordinate = tk.StringVar()
y_coordinate = tk.StringVar()
color = tk.StringVar()

frame = tk.Frame(root)
frame.pack(expand=True, fill='both')

frame_Menu = tk.Frame(frame)
frame_Menu.grid(row=0, column=0, sticky="N")

frame_Canvas = tk.Frame(frame)
frame_Canvas.grid(row=0, column=2, sticky="W")

x_entry = tk.Entry(frame_Menu, textvariable=x_coordinate)
x_entry.grid(row=0, column=0, pady=1, sticky="N")
x_entry.config(bd=1, relief="solid")

y_entry = tk.Entry(frame_Menu, textvariable=y_coordinate)
y_entry.grid(row=1, column=0, sticky="N")
y_entry.config(bd=1, relief="solid")

color_entry = tk.Entry(frame_Menu, textvariable=color)
color_entry.grid(row=2, column=0, pady=1, sticky="N")
color_entry.config(bd=1, relief="solid")

draw_button = tk.Button(frame_Menu, text="Dessiner", command=draw_pixel)
draw_button.grid(row=3, column=0, sticky="N")

save_button = tk.Button(frame_Menu, text="Sauvegarder", command=save_to_csv)
save_button.grid(row=4, column=0, sticky="N")

load_button = tk.Button(frame_Menu, text="Charger", command=load_from_csv)
load_button.grid(row=5, column=0, sticky="N")

close_button = tk.Button(frame_Menu, text="Fermer", command=root.destroy)
close_button.grid(row=6, column=0, sticky="N")

canvas = tk.Canvas(frame_Canvas, width=WIDTH, height=HEIGHT, bg='yellow')
canvas.grid(row=0, column=0, rowspan=1, sticky="NSEW")
canvas.config(bd=1, relief="solid")

root.mainloop()
1
Lapwace Messages postés 5 Date d'inscription jeudi 19 janvier 2023 Statut Membre Dernière intervention 19 janvier 2023 1
19 janv. 2023 à 20:45

Merci beaucoup, d'accord donc si je comprend bien mon erreur c'est un peu comme si je superposais deux pixels et que ça sélectionnait tout le temps le premier qui n'avait plus de couleur.

0
jouflu > Lapwace Messages postés 5 Date d'inscription jeudi 19 janvier 2023 Statut Membre Dernière intervention 19 janvier 2023
19 janv. 2023 à 22:31

Il suffit de tester pour comprendre ce qu'il se passe ^^

import tkinter


can = tkinter.Canvas(width=50, height=50, bg='yellow')

can.create_rectangle(10, 10, 10, 10, fill='red', tag='r')
print(1, can.itemcget('r', 'fill'))

can.create_rectangle(10, 10, 10, 10, fill='blue', tag='r')
print(2, can.itemcget('r', 'fill'))
print(3, can.itemcget(can.find_withtag('r'), 'fill'))
print(4, can.itemcget(can.find_withtag('r')[-1], 'fill'))

Là, on comprend pourquoi tu avais ce souci.

On peut mettre n'importe quel type d'objet en tags, donc tkinter accepte sans broncher ce que retourne find_withtag (un tuple des identifiants items ayant ce tag, 'r' ici), on pourrait tout de même reprocher qu'il ne jette pas une erreur au cas où on demande la valeur de l'option d'un item inexistant.

0

La meilleure solution serait de ne pas utiliser de tag qui sert principalement à faire des groupes d'items, et d'user de la méthode find_enclosed du canvas.

Préfère aussi utiliser les constantes tkinter plutôt que des strings.

import tkinter as tk
import csv

WIDTH = 100
HEIGHT = 100
CSV_NAME = "canvas_content.csv"

root = tk.Tk()
root.title("App Pixel")
# root.state('zoomed') # fonctionne pas sur Linux


def draw_pixel():
    pixel_color = color.get()
    try:
        assert pixel_color
        x = int(x_coordinate.get())
        y = int(y_coordinate.get())
        assert WIDTH > x >= 0
        assert HEIGHT > y >= 0
    except (ValueError, AssertionError):
        return
    rects = canvas.find_enclosed(x - 1, y - 1, x + 1, y + 1)
    if rects:
        canvas.itemconfig(rects[0], fill=pixel_color)
    else:
        canvas.create_rectangle(x, y, x, y, fill=pixel_color, width=0)


def save_to_csv():
    pixels = canvas.find_all()
    if pixels:
        with open(CSV_NAME, "w", newline="") as f:
            writer = csv.writer(f)
            for pixel in pixels:
                row = canvas.coords(pixel)[:2]
                row.append(canvas.itemcget(pixel, "fill"))
                writer.writerow(row)


def load_from_csv():
    with open(CSV_NAME, "r") as f:
        reader = csv.reader(f)
        for row in reader:
            x, y = (float(v) for v in row[0:2])
            color = row[2]
            rects = canvas.find_enclosed(x - 1, y - 1, x + 1, y + 1)
            if rects:
                canvas.itemconfig(rects[0], fill=color)
            else:
                canvas.create_rectangle(x, y, x, y, fill=color, width=0)


x_coordinate = tk.StringVar()
y_coordinate = tk.StringVar()
color = tk.StringVar()

frame = tk.Frame(root)
frame.pack(expand=True, fill=tk.BOTH)

frame_Menu = tk.Frame(frame)
frame_Menu.grid(row=0, column=0, sticky=tk.N)

frame_Canvas = tk.Frame(frame)
frame_Canvas.grid(row=0, column=2, sticky=tk.W)

x_entry = tk.Entry(frame_Menu, textvariable=x_coordinate)
x_entry.grid(row=0, column=0, pady=1, sticky=tk.N)
x_entry.config(bd=1, relief=tk.SOLID)

y_entry = tk.Entry(frame_Menu, textvariable=y_coordinate)
y_entry.grid(row=1, column=0, sticky=tk.N)
y_entry.config(bd=1, relief=tk.SOLID)

color_entry = tk.Entry(frame_Menu, textvariable=color)
color_entry.grid(row=2, column=0, pady=1, sticky=tk.N)
color_entry.config(bd=1, relief=tk.SOLID)

draw_button = tk.Button(frame_Menu, text="Dessiner", command=draw_pixel)
draw_button.grid(row=3, column=0, sticky=tk.N)

save_button = tk.Button(frame_Menu, text="Sauvegarder", command=save_to_csv)
save_button.grid(row=4, column=0, sticky=tk.N)

load_button = tk.Button(frame_Menu, text="Charger", command=load_from_csv)
load_button.grid(row=5, column=0, sticky=tk.N)

close_button = tk.Button(frame_Menu, text="Fermer", command=root.destroy)
close_button.grid(row=6, column=0, sticky=tk.N)

canvas = tk.Canvas(
    frame_Canvas, width=WIDTH, height=HEIGHT, bg='white', bd=1, relief=tk.SOLID
)
canvas.grid(row=0, column=0, rowspan=1, sticky=tk.NSEW)

root.mainloop()

Tu pourrais aussi utiliser des IntVar plutôt que des StringVar pour les coordonnées des Entry, mais il faudrait pour cela utiliser la méthode d'autorisation de saisie.

1
Lapwace Messages postés 5 Date d'inscription jeudi 19 janvier 2023 Statut Membre Dernière intervention 19 janvier 2023 1
19 janv. 2023 à 21:18

Je vais probablement modifier le code pour utiliser la méthode find_enclosed qui a l'air plus efficace.

Pour les entrées en IntVar, ce sera un bot Discord qui les fera, donc elles seront toujours des entiers ou le bot refusera la commande. J'ai pensé que c'était plus simple de faire comme je le connaissais déjà, ça me fait moins de choses à rechercher sur le moment. Cependant, je prends note de cette méthode pour mon apprentissage.

En ce qui concerne les constantes tkinter, je les ignorais également, merci pour le conseil. Pouvez-vous m'expliquer pourquoi il est préférable de les utiliser par rapport à des chaînes de caractères ?

1
jouflu > Lapwace Messages postés 5 Date d'inscription jeudi 19 janvier 2023 Statut Membre Dernière intervention 19 janvier 2023
19 janv. 2023 à 22:36

Il est préférable d'utiliser les constantes d'un modules plutôt que la valeur de ces constantes, pour la simple raison qu'il peut prendre au développeur/mainteneur de ce module de changer la valeur des constantes pour x raison.

En utilisant les constantes on ne sera pas exposé à des bugs de nos programmes, bon, tkinter, ça n'a pas trop bougé et ne bougera sans doute jamais, mais ça reste tout de même une bonne habitude à adopter.

0
Lapwace Messages postés 5 Date d'inscription jeudi 19 janvier 2023 Statut Membre Dernière intervention 19 janvier 2023 1 > jouflu
19 janv. 2023 à 23:22

Ok je vois , merci pour ses précisions.

0
Lapwace Messages postés 5 Date d'inscription jeudi 19 janvier 2023 Statut Membre Dernière intervention 19 janvier 2023 1
19 janv. 2023 à 14:00

Pour le deuxième problème j'ai réussi à comprendre mon erreur en rajoutant le tag au create_rectangle ligne 28.
 

canvas.create_rectangle(int(x), int(y), int(x), int(y), fill=color,width=0,tags=(f"pixel_{x}_{y}"))

mais je n'arrive toujours pas à trouver mon erreur pour le premier problème.

0