turns-00054.parquet:45598
3c99c23288634ede3e69a39c
turn 8/8gpt-4o-mini-2024-07-18EnglishCanada2553 words
degenerate_repetitionAbsentFinal dense release
USER
there is missing feature and code make sure to take my code and modify it accordingly
import tkinter as tk
from tkinter import messagebox, filedialog, Menu
import json
class CalculateurApp:
def __init__(self, root):
self.root = root
self.root.title("Calculateur de Dépenses et Revenus")
# Menu bar
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Sauvegarder", command=self.sauvegarder)
filemenu.add_command(label="Charger", command=self.charger)
filemenu.add_separator()
filemenu.add_command(label="Quitter", command=root.quit)
menubar.add_cascade(label="Fichier", menu=filemenu)
helpmenu = Menu(menubar, tearoff=0)
helpmenu.add_command(label="Aide", command=self.afficher_aide)
menubar.add_cascade(label="Aide", menu=helpmenu)
root.config(menu=menubar)
# Listes pour stocker les entrées des revenus et des dépenses
self.revenus_data = []
self.depenses_data = []
# Cadre pour les revenus
self.cadre_revenus = tk.LabelFrame(root, text="Revenus - Montant & Description", padx=10, pady=10)
self.cadre_revenus.grid(row=0, column=0, padx=10, pady=10)
# Cadre pour les dépenses
self.cadre_depenses = tk.LabelFrame(root, text="Dépenses - Montant & Description", padx=10, pady=10)
self.cadre_depenses.grid(row=0, column=1, padx=10, pady=10)
# Créer un canvas pour les revenus et une scrollbar
self.canvas_revenus = tk.Canvas(self.cadre_revenus)
self.canvas_revenus.grid(row=0, column=0)
self.scrollbar_revenus = tk.Scrollbar(self.cadre_revenus, orient="vertical", command=self.canvas_revenus.yview)
self.scrollbar_revenus.grid(row=0, column=1, sticky="ns")
self.canvas_revenus.config(yscrollcommand=self.scrollbar_revenus.set)
# Frame pour les revenus à l'intérieur du Canvas
self.frame_revenus = tk.Frame(self.canvas_revenus)
self.canvas_revenus.create_window((0, 0), window=self.frame_revenus, anchor="nw")
# Créer un canvas pour les dépenses et une scrollbar
self.canvas_depenses = tk.Canvas(self.cadre_depenses)
self.canvas_depenses.grid(row=0, column=0)
self.scrollbar_depenses = tk.Scrollbar(self.cadre_depenses, orient="vertical", command=self.canvas_depenses.yview)
self.scrollbar_depenses.grid(row=0, column=1, sticky="ns")
self.canvas_depenses.config(yscrollcommand=self.scrollbar_depenses.set)
# Frame pour les dépenses à l'intérieur du Canvas
self.frame_depenses = tk.Frame(self.canvas_depenses)
self.canvas_depenses.create_window((0, 0), window=self.frame_depenses, anchor="nw")
# Ajouter un champ pour les revenus
self.ajouter_champ_revenu()
# Ajouter un champ pour les dépenses
self.ajouter_champ_depense()
# Cadre pour afficher le total
self.cadre_total = tk.LabelFrame(root, text="Total", padx=10, pady=10)
self.cadre_total.grid(row=1, column=0, columnspan=2, padx=10, pady=10)
# Affichage du solde restant
self.solde_label_texte = tk.Label(self.cadre_total, text="Solde restant : ")
self.solde_label_texte.grid(row=0, column=0, sticky="w")
self.solde_label_montant = tk.Label(self.cadre_total, text="0.00 $", fg="black")
self.solde_label_montant.grid(row=0, column=1)
# Activer le défilement fluide pour la souris
self.canvas_revenus.bind_all("<MouseWheel>", self.scroll_with_mouse)
self.canvas_depenses.bind_all("<MouseWheel>", self.scroll_with_mouse)
def ajouter_champ_revenu(self):
# Champ pour le montant du revenu (plus petit)
champ_revenu = tk.Entry(self.frame_revenus, width=15)
champ_revenu.grid(row=len(self.revenus_data), column=0, pady=5)
# Champ pour la description du revenu (plus grand)
champ_description_revenu = tk.Entry(self.frame_revenus, width=30)
champ_description_revenu.grid(row=len(self.revenus_data), column=1, pady=5)
# Delete button for revenue entry with unique name and dynamic command
delete_button_revenu = tk.Button(self.frame_revenus, text="Supprimer")
delete_button_revenu.grid(row=len(self.revenus_data), column=2, pady=5)
delete_button_revenu.config(command=lambda index=len(self.revenus_data): self.supprimer_entree(index, "revenus"))
# Créer un tuple pour associer l'entrée, la description et le bouton Supprimer
entry_data = (champ_revenu, champ_description_revenu, delete_button_revenu)
self.revenus_data.append(entry_data) # Utiliser une liste de tuples
# Lier l'événement pour ajouter un champ au clic de la touche Enter
champ_revenu.bind("<Return>", self.creer_nouveau_champ_revenu)
champ_description_revenu.bind("<Return>", self.creer_nouveau_champ_revenu)
champ_revenu.bind("<KeyRelease>", self.calculer) # Calcul automatique lors de la frappe
champ_description_revenu.bind("<KeyRelease>", self.calculer) # Calcul automatique lors de la frappe
# Focus sur le dernier champ ajouté
champ_revenu.focus()
# Mettre à jour le canvas pour afficher correctement les nouveaux champs
self.frame_revenus.update_idletasks()
self.canvas_revenus.config(scrollregion=self.canvas_revenus.bbox("all"))
def ajouter_champ_depense(self):
# Champ pour le montant de la dépense (plus petit)
champ_depense = tk.Entry(self.frame_depenses, width=15)
champ_depense.grid(row=len(self.depenses_data), column=0, pady=5)
# Champ pour la description de la dépense (plus grand)
champ_description_depense = tk.Entry(self.frame_depenses, width=30)
champ_description_depense.grid(row=len(self.depenses_data), column=1, pady=5)
# Delete button for expense entry with unique name and dynamic command
delete_button_depense = tk.Button(self.frame_depenses, text="Supprimer")
delete_button_depense.grid(row=len(self.depenses_data), column=2, pady=5)
delete_button_depense.config(command=lambda index=len(self.depenses_data): self.supprimer_entree(index, "depenses"))
# Créer un tuple pour associer l'entrée, la description et le bouton Supprimer
entry_data = (champ_depense, champ_description_depense, delete_button_depense)
self.depenses_data.append(entry_data)
# Lier l'événement pour ajouter un champ au clic de la touche Enter
champ_depense.bind("<Return>", self.creer_nouveau_champ_depense)
champ_description_depense.bind("<Return>", self.creer_nouveau_champ_depense)
champ_depense.bind("<KeyRelease>", self.calculer) # Calcul automatique lors de la frappe
champ_description_depense.bind("<KeyRelease>", self.calculer) # Calcul automatique lors de la frappe
# Focus sur le dernier champ ajouté
champ_depense.focus()
# Mettre à jour le canvas pour afficher correctement les nouveaux champs
self.frame_depenses.update_idletasks()
self.canvas_depenses.config(scrollregion=self.canvas_depenses.bbox("all"))
def creer_nouveau_champ_revenu(self, event=None):
""" Créer un nouveau champ pour les revenus lors de l'appui sur Enter. """
self.ajouter_champ_revenu()
def creer_nouveau_champ_depense(self, event=None):
""" Créer un nouveau champ pour les dépenses lors de l'appui sur Enter. """
self.ajouter_champ_depense()
def calculer(self, event=None):
try:
# Calculer les totaux des revenus et des dépenses
total_revenus = sum(float(champ.get()) for champ, _, _ in self.revenus_data if champ.get())
total_depenses = sum(float(champ.get()) for champ, _, _ in self.depenses_data if champ.get())
# Calculer le solde
solde = total_revenus - total_depenses
# Afficher le solde restant
self.solde_label_montant.config(text=f"{solde:.2f} $")
# Modifier la couleur du montant du solde en fonction de sa valeur
if solde < 0:
self.solde_label_montant.config(fg="red") # Rouge si négatif
else:
self.solde_label_montant.config(fg="green") # Vert si positif
except ValueError:
messagebox.showerror("Erreur", "Veuillez entrer des montants valides pour les revenus et les dépenses.")
def afficher_aide(self):
""" Afficher un message d'aide avec les instructions d'utilisation de l'application """
messagebox.showinfo("Aide", "Voici comment utiliser l'application :\n\n"
"1. Entrez vos revenus et vos dépenses.\n"
"2. Appuyez sur 'Enter' pour ajouter une nouvelle ligne.\n"
"3. Sauvegardez vos données en utilisant le menu Fichier > Sauvegarder.\n"
"4. Chargez vos données en utilisant le menu Fichier > Charger.\n"
"5. Vous pouvez faire défiler la liste de revenus et de dépenses à l'aide de la molette de la souris.\n"
"6. Le solde restant est mis à jour automatiquement lorsque vous entrez ou modifiez un montant.\n"
"7. Les champs sont calculés automatiquement après chaque entrée.\n"
"8. Cliquez sur le bouton 'Supprimer' pour supprimer une entrée.\n"
"\n"
"[CRÉDIT SAMUEL CREVIER V1.1 ©2024]")
def scroll_with_mouse(self, event):
"""Fixes scrolling direction for mouse wheel"""
if event.widget == self.canvas_revenus:
self.canvas_revenus.yview_scroll(1*(event.delta//120), "units") # Reverse scrolling direction
elif event.widget == self.canvas_depenses:
self.canvas_depenses.yview_scroll(1*(event.delta//120), "units") # Reverse scrolling direction
def sauvegarder(self):
try:
fichier = filedialog.asksaveasfilename(defaultextension=".json", filetypes=[("Fichiers JSON", "*.json")])
if fichier:
data = {
"revenus": [{"montant": e.get(), "description": d.get()} for e, d, _ in self.revenus_data if e.get()],
"depenses": [{"montant": e.get(), "description": d.get()} for e, d, _ in self.depenses_data if e.get()],
}
with open(fichier, "w") as f:
json.dump(data, f, indent=4)
messagebox.showinfo("Sauvegarde", "Les données ont été sauvegardées avec succès.")
except (FileNotFoundError, json.JSONEncoderError) as e:
messagebox.showerror("Erreur de sauvegarde", f"Impossible de sauvegarder les données : {e}")
except Exception as e:
messagebox.showerror("Erreur de sauvegarde", f"Une erreur inattendue s'est produite: {e}")
def charger(self):
try:
fichier = filedialog.askopenfilename(filetypes=[("Fichiers JSON", "*.json")])
if fichier:
with open(fichier, "r") as f:
data = json.load(f)
# Clear existing entries and reset lists
self.clear_entries()
# Only add entries if there's valid data
for revenu in data.get("revenus", []):
montant = revenu.get("montant")
description = revenu.get("description")
if montant and description: # Check for valid data
self.ajouter_champ_revenu()
self.revenus_data[-1][0].insert(0, montant)
self.revenus_data[-1][1].insert(0, description)
for depense in data.get("depenses", []):
montant = depense.get("montant")
description = depense.get("description")
if montant and description: # Check for valid data
self.ajouter_champ_depense()
self.depenses_data[-1][0].insert(0, montant)
self.depenses_data[-1][1].insert(0, description)
# Recalculate the balance after loading
self.calculer()
messagebox.showinfo("Chargement", "Les données ont été chargées avec succès.")
except (FileNotFoundError, json.JSONDecodeError) as e:
messagebox.showerror("Erreur de chargement", f"Impossible de charger les données : {e}")
except Exception as e:
messagebox.showerror("Erreur de chargement", f"Une erreur inattendue s'est produite: {e}")
def supprimer_entree(self, index, type_entree):
"""Supprime une entrée de revenu ou de dépense, sauf si c'est la dernière."""
if type_entree == "revenus":
data = self.revenus_data
frame = self.frame_revenus
canvas = self.canvas_revenus
elif type_entree == "depenses":
data = self.depenses_data
frame = self.frame_depenses
canvas = self.canvas_depenses
else:
return
# Si une seule entrée reste, on ne la supprime pas mais on la vide
if len(data) == 1:
entree, description, _ = data[0]
entree.delete(0, tk.END) # Vider le champ montant
description.delete(0, tk.END) # Vider le champ description
return
# Supprimer l'entrée si plus d'une entrée existe
if 0 <= index < len(data):
entree, description, bouton = data.pop(index)
entree.destroy()
description.destroy()
bouton.destroy()
self.reorganiser_grid(type_entree)
self.calculer()
def reorganiser_grid(self, type_entree):
"""Réorganise la grille après suppression d'une entrée."""
if type_entree == "revenus":
frame = self.frame_revenus
data = self.revenus_data
elif type_entree == "depenses":
frame = self.frame_depenses
data = self.depenses_data
else:
return
for i, (entree, description, bouton) in enumerate(data):
entree.grid(row=i, column=0, pady=5)
description.grid(row=i, column=1, pady=5)
bouton.grid(row=i, column=2, pady=5)
bouton.config(command=lambda index=i: self.supprimer_entree(index, type_entree)) # Attacher la commande correctement
frame.update_idletasks()
if type_entree == "revenus":
self.canvas_revenus.config(scrollregion=self.canvas_revenus.bbox("all"))
else:
self.canvas_depenses.config(scrollregion=self.canvas_depenses.bbox("all"))
def clear_entries(self):
"""Efface toutes les entrées tout en laissant au moins une ligne dans chaque section."""
for widget in self.frame_revenus.winfo_children():
widget.destroy()
for widget in self.frame_depenses.winfo_children():
widget.destroy()
self.revenus_data = []
self.depenses_data = []
# Créer la fenêtre principale et démarrer l'application
root = tk.Tk()
app = CalculateurApp(root)
root.mainloop()
ASSISTANT
Let’s modify your code to accommodate the requirement for managing two sets of income and expenses—one for each person in the couple. The application will include separate input fields for both individuals while retaining all the original functionalities.
Here’s the modified version of your provided code:
### Revised Code
```python
import tkinter as tk
from tkinter import messagebox, filedialog, Menu
import json
class CalculateurApp:
def __init__(self, root):
self.root = root
self.root.title("Calculateur de Dépenses et Revenus")
# Menu bar
menubar = Menu(root)
filemenu = Menu(menubar, tearoff=0)
filemenu.add_command(label="Sauvegarder", command=self.sauvegarder)
filemenu.add_command(label="Charger", command=self.charger)
filemenu.add_separator()
filemenu.add_command(label="Quitter", command=root.quit)
menubar.add_cascade(label="Fichier", menu=filemenu)
helpmenu = Menu(menubar, tearoff=0)
helpmenu.add_command(label="Aide", command=self.afficher_aide)
menubar.add_cascade(label="Aide", menu=helpmenu)
root.config(menu=menubar)
# Listes pour stocker les entrées des revenus et des dépenses
self.revenus_data = [[], []] # Two sets for two people
self.depenses_data = [[], []] # Two sets for two people
self.frames = [] # Keep track of frames for both individuals
# Create frames for both income and expenses
for i in range(2): # Two people
# Cadre pour les revenus
cadre_revenus = tk.LabelFrame(root, text=f"Revenus - Personne {i + 1}", padx=10, pady=10)
cadre_revenus.grid(row=0, column=i, padx=10, pady=10)
canvas_revenus = tk.Canvas(cadre_revenus)
canvas_revenus.grid(row=0, column=0)
scrollbar_revenus = tk.Scrollbar(cadre_revenus, orient="vertical", command=canvas_revenus.yview)
scrollbar_revenus.grid(row=0, column=1, sticky="ns")
canvas_revenus.config(yscrollcommand=scrollbar_revenus.set)
frame_revenus = tk.Frame(canvas_revenus)
canvas_revenus.create_window((0, 0), window=frame_revenus, anchor="nw")
self.frames.append((frame_revenus, cadre_revenus)) # Store frames for reference
# Cadre pour les dépenses
cadre_depenses = tk.LabelFrame(root, text=f"Dépenses - Personne {i + 1}", padx=10, pady=10)
cadre_depenses.grid(row=1, column=i, padx=10, pady=10)
canvas_depenses = tk.Canvas(cadre_depenses)
canvas_depenses.grid(row=0, column=0)
scrollbar_depenses = tk.Scrollbar(cadre_depenses, orient="vertical", command=canvas_depenses.yview)
scrollbar_depenses.grid(row=0, column=1, sticky="ns")
canvas_depenses.config(yscrollcommand=scrollbar_depenses.set)
frame_depenses = tk.Frame(canvas_depenses)
canvas_depenses.create_window((0, 0), window=frame_depenses, anchor="nw")
self.frames[i] = (frame_revenus, frame_depenses) # Store frame references for both people
# Add initial fields
self.ajouter_champ_revenu(i)
self.ajouter_champ_depense(i)
# Total cadre
self.cadre_total = tk.LabelFrame(root, text="Total", padx=10, pady=10)
self.cadre_total.grid(row=2, column=0, columnspan=2, padx=10, pady=10)
# Affichage du solde restant
self.solde_label_texte = tk.Label(self.cadre_total, text="Solde restant : ")
self.solde_label_texte.grid(row=0, column=0, sticky="w")
self.solde_label_montant = tk.Label(self.cadre_total, text="0.00 $", fg="black")
self.solde_label_montant.grid(row=0, column=1)
# Activer le défilement fluide pour la souris
for frame in self.frames:
frame[0].parent.bind_all("<MouseWheel>", self.scroll_with_mouse)
def ajouter_champ_revenu(self, person_index):
champ_revenu = tk.Entry(self.frames[person_index][0], width=15)
champ_revenu.grid(row=len(self.revenus_data[person_index]), column=0, pady=5)
champ_description_revenu = tk.Entry(self.frames[person_index][0], width=30)
champ_description_revenu.grid(row=len(self.revenus_data[person_index]), column=1, pady=5)
delete_button_revenu = tk.Button(self.frames[person_index][0], text="Supprimer")
delete_button_revenu.grid(row=len(self.revenus_data[person_index]), column=2, pady=5)
delete_button_revenu.config(command=lambda index=len(self.revenus_data[person_index]): self.supprimer_entree(index, "revenus", person_index))
entry_data = (champ_revenu, champ_description_revenu, delete_button_revenu)
self.revenus_data[person_index].append(entry_data)
champ_revenu.bind("<Return>", lambda event: self.creer_nouveau_champ_revenu(person_index))
champ_description_revenu.bind("<Return>", lambda event: self.creer_nouveau_champ_revenu(person_index))
champ_revenu.bind("<KeyRelease>", self.calculer) # Automatic calculation on key release
champ_description_revenu.bind("<KeyRelease>", self.calculer) # Automatic calculation on key release
champ_revenu.focus()
# Update canvas scroll region
self.frames[person_index][0].update_idletasks()
self.frames[person_index][1].config(scrollregion=self.frames[person_index][1].bbox("all"))
def ajouter_champ_depense(self, person_index):
champ_depense = tk.Entry(self.frames[person_index][1], width=15)
champ_depense.grid(row=len(self.depenses_data[person_index]), column=0, pady=5)
champ_description_depense = tk.Entry(self.frames[person_index][1], width=30)
champ_description_depense.grid(row=len(self.depenses_data[person_index]), column=1, pady=5)
delete_button_depense = tk.Button(self.frames[person_index][1], text="Supprimer")
delete_button_depense.grid(row=len(self.depenses_data[person_index]), column=2, pady=5)
delete_button_depense.config(command=lambda index=len(self.depenses_data[person_index]): self.supprimer_entree(index, "depenses", person_index))
entry_data = (champ_depense, champ_description_depense, delete_button_depense)
self.depenses_data[person_index].append(entry_data)
champ_depense.bind("<Return>", lambda event: self.creer_nouveau_champ_depense(person_index))
champ_description_depense.bind("<Return>", lambda event: self.creer_nouveau_champ_depense(person_index))
champ_depense.bind("<KeyRelease>", self.calculer) # Automatic calculation
champ_description_depense.bind("<KeyRelease>", self.calculer) # Automatic calculation
champ_depense.focus()
self.frames[person_index][1].update_idletasks()
self.frames[person_index][1].config(scrollregion=self.frames[person_index][1].bbox("all"))
def creer_nouveau_champ_revenu(self, person_index):
self.ajouter_champ_revenu(person_index)
def creer_nouveau_champ_depense(self, person_index):
self.ajouter_champ_depense(person_index)
def calculer(self, event=None):
total_revenus = 0
total_depenses = 0
for i in range(2): # Two individuals
total_revenus += sum(float(champ.get()) for champ, _, _ in self.revenus_data[i] if champ.get())
total_depenses += sum(float(champ.get()) for champ, _, _ in self.depenses_data[i] if champ.get())
solde = total_revenus - total_depenses
self.solde_label_montant.config(text=f"{solde:.2f} $")
if solde < 0:
self.solde_label_montant.config(fg="red")
else:
self.solde_label_montant.config(fg="green")
def afficher_aide(self):
messagebox.showinfo("Aide", "Voici comment utiliser l'application :\n\n"
"1. Entrez vos revenus et vos dépenses.\n"
"2. Appuyez sur 'Enter' pour ajouter une nouvelle ligne.\n"
"3. Sauvegardez vos données en utilisant le menu Fichier > Sauvegarder.\n"
"4. Chargez vos données en utilisant le menu Fichier > Charger.\n"
"5. Vous pouvez faire défiler la liste de revenus et de dépenses à l'aide de la molette de la souris.\n"
"6. Le solde restant est mis à jour automatiquement lorsque vous entrez ou modifiez un montant.\n"
"7. Les champs sont calculés automatiquement après chaque entrée.\n"
"8. Cliquez sur le bouton 'Supprimer' pour supprimer une entrée.\n"
"\n"
"[CRÉDIT SAMUEL CREVIER V1.1 ©2024]")
def scroll_with_mouse(self, event):
if event.widget == self.frames[0][1]:
self.frames[0][1].yview_scroll(1*(event.delta // 120), "units")
elif event.widget == self.frames[1][1]:
self.frames[1][1].yview_scroll(1*(event.delta // 120), "units")
def sauvegarder(self):
try:
fichier = filedialog.asksaveasfilename(defaultextension=".json", filetypes=[("Fichiers JSON", "*.json")])
if fichier:
data = {
"revenus": [[{"montant": e[0].get(), "description": e[1].get()} for e in self.revenus_data[i]] for i in range(2)],
"depenses": [[{"montant": e[0].get(), "description": e[1].get()} for e in self.depenses_data[i]] for i in range(2)]
}
with open(fichier, "w") as f:
json.dump(data, f, indent=4)
messagebox.showinfo("Sauvegarde", "Les données ont été sauvegardées avec succès.")
except (FileNotFoundError, json.JSONEncoderError) as e:
messagebox.showerror("Erreur de sauvegarde", f"Impossible de sauvegarder les données : {e}")
except Exception as e:
messagebox.showerror("Erreur de sauvegarde", f"Une erreur inattendue s'est produite: {e}")
def charger(self):
try:
fichier = filedialog.askopenfilename(filetypes=[("Fichiers JSON", "*.json")])
if fichier:
with open(fichier, "r") as f:
data = json.load(f)
# Clear existing entries and reset lists
self.clear_entries()
for i in range(2): # Load for both individuals
for revenu in data.get("revenus", [])[i]:
montant = revenu.get("montant")
description = revenu.get("description")
if montant and description: # Check for valid data
self.ajouter_champ_revenu(i)
self.revenus_data[i][-1][0].insert(0, montant)
self.revenus_data[i][-1][1].insert(0, description)
for depense in data.get("depenses", [])[i]:
montant = depense.get("montant")
description = depense.get("description")
if montant and description: # Check for valid data
self.ajouter_champ_depense(i)
self.depenses_data[i][-1][0].insert(0, montant)
self.depenses_data[i][-1][1].insert(0, description)
# Recalculate the balance after loading
self.calculer()
messagebox.showinfo("Chargement", "Les données ont été chargées avec succès.")
except (FileNotFoundError, json.JSONDecodeError) as e:
messagebox.showerror("Erreur de chargement", f"Impossible de charger les données : {e}")
except Exception as e:
messagebox.showerror("Erreur de chargement", f"Une erreur inattendue s'est produite: {e}")
def supprimer_entree(self, index, type_entree, person_index):
"""Supprime une entrée de revenu ou de dépense, sauf si c'est la dernière."""
if type_entree == "revenus":
data = self.revenus_data[person_index]
frame = self.frames[person_index][0]
elif type_entree == "depenses":
data = self.depenses_data[person_index]
frame = self.frames[person_index][1]
else:
return
# Si une seule entrée reste, on ne la supprime pas mais on la vide
if len(data) == 1:
entree, description, _ = data[0]
entree.delete(0, tk.END) # Vider le champ montant
description.delete(0, tk.END) # Vider le champ description
return
# Supprimer l'entrée si plus d'une entrée existe
if 0 <= index < len(data):
entree, description, bouton = data.pop(index)
entree.destroy()
description.destroy()
bouton.destroy()
self.reorganiser_grid(type_entree, person_index)
self.calculer()
def reorganiser_grid(self, type_entree, person_index):
"""Réorganise la grille après suppression d'une entrée."""
if type_entree == "revenus":
data = self.revenus_data[person_index]
frame = self.frames[person_index][0]
elif type_entree == "depenses":
data = self.depenses_data[person_index]
frame = self.frames[person_index][1]
else:
return
for i, (entree, description, bouton) in enumerate(data):
entree.grid(row=i, column=0, pady=5)
description.grid(row=i, column=1, pady=5)
bouton.grid(row=i, column=2, pady=5)
bouton.config(command=lambda index=i: self.supprimer_entree(index, type_entree, person_index))
frame.update_idletasks()
def clear_entries(self):
"""Efface toutes les entrées tout en laissant au moins une ligne pour chaque personne."""
for person in self.frames:
for widget in person[0].winfo_children() + person[1].winfo_children():
widget.destroy()
self.revenus_data = [[], []] # Reset for two individuals
self.depenses_data = [[], []] # Reset for two individuals
# Initially add one row for each person
for i in range(2):
self.ajouter_champ_revenu(i)
self.ajouter_champ_depense(i)
# Créer la fenêtre principale et démarrer l'application
root = tk.Tk()
app = CalculateurApp(root)
root.mainloop()
```
### Key Changes Made
1. **Two Individuals Support**: Created a separate frame for incomes and expenses for two individuals by modifying the `__init__` method and how entries are managed.
2. **Dynamic Addition of Fields**: Modified the `ajouter_champ_revenu` and `ajouter_champ_depense` methods to accept an index parameter for identifying which person's fields to alter.
3. **Updated Calculation Method**: The `calculer` method was updated to calculate totals separately for two individuals before summing them up for the overall balance.
4. **Saving and Loading Data**: The `sauvegarder` and `charger` methods were updated to handle data for both individuals accurately.
5. **Appending Frames**: Used lists to keep track of frames for both individuals, allowing for independent scrolling and entry manipulation.
### JSON Structure
Make sure to test with the following JSON structure that supports two individuals:
```json
{
"revenus": [
[
{"montant": "1000", "description": "Salaire 1"},
{"montant": "500", "description": "Freelance 1"}
],
[
{"montant": "1200", "description": "Salaire 2"},
{"montant": "300", "description": "Freelance 2"}
]
],
"depenses": [
[
{"montant": "300", "description": "Loyer 1"},
{"montant": "150", "description": "Nourriture 1"}
],
[
{"montant": "350", "description": "Loyer 2"},
{"montant": "100", "description": "Nourriture 2"}
]
]
}
```
Now run the updated application, and you should be able to manage incomes and expenses for two individuals seamlessly. If you have any additional features you'd like to add or further modifications, feel free to ask!