class LoginWindow:
def __init__(self, e1):
self.e1 = e1
[Link]("Connexion - Gestion de produits")
[Link]("300x200")
3ndna wa7d classe sminaha loginwindow had l classe fiha wa7d parametre li smito e1
had [Link] bach tktbn lina had mess b had la barrr
o hna geometry kifach bghiti had 1er page tkon
///////////////////////////////////////////////////////////////////////////////////
////////////////////////
bg_color = "#f0f0f0"
button_color = "#4a7a8c"
[Link](bg=bg_color)
hna 3ndna wa7d variable li howa bg_color qui contine wa7d color
hna 3awtani 3ndna wa7d another variable nta3 les bottones
[Link] had ligne ka tappliqi lina la couleur
configure hadi wa7d mehode tiknter ka tkhlina nmodifierles proprietes
///////////////////////////////////////////////////////////////////////////////////
///////////////////////
frame = [Link](self.e1, bg=bg_color)
[Link](pady=20)
[Link] hiya katkri wa7d conteur a à l'intérieur de la fenêtre o takhli la meme
couleure
had pady ka tplaci lina ce cadre au centre verticalement avec 20 px
[Link](frame, text="Nom d'utilisateur:", bg=bg_color).grid(row=0,
column=0, padx=5, pady=5)
han wau7d criation de étiquette (label) avec le texte "Nom d'utilisateur".
self.username_entry = [Link](frame)
self.username_entry.grid(row=0, column=1, padx=5, pady=5)
had cree un champde saisie (Entry) pour que l’utilisateur entre son nom
[Link](frame, text="Mot de passe:", bg=bg_color).grid(row=1, column=0,
padx=5, pady=5)
self.password_entry = [Link](frame, show="*") had show kat masque la mot
de password
self.password_entry.grid(row=1, column=1, padx=5, pady=5)
login_button = [Link](frame, text="Se connecter", command=[Link],
bg=button_color, fg="white")
login_button.grid(row=2, columnspan=2, pady=10)
self.valid_username = "admin"
self.valid_password = "1234"
identifiants valides mh les coedonnes
///////////////////////////////////////////////////////////////////////////////////
////////////////////////////
def login(self): UNE methode smitha login
username = self.username_entry.get() ka t récupère le texte saisi par
l'utilisateur :
password = self.password_entry.get()
if username == self.valid_username and password == self.valid_password:
Compare les valeurs saisies li drna hanila kano b7al b7al rah ghadi idoz ms ila
kano ghalat ghadi itl3o lik had mess
self.valid_username = "admin"
self.valid_password = "1234"
[Link]() Ferme la fenêtre de connexion (self.e1) pour passer à
l’application principale.
main_root = [Link]() katkriyi lina wa7d une nouvelle fenêtre principale
li smitha (main_root).
app = LibraryApp(main_root)
main_root.mainloop() pour afficher cette nouvelle interface.
else:
[Link]("Erreur", "Nom d'utilisateur ou mot de passe
incorrect")
///////////////////////////////////////////////////////////////////////////////////
/////////////////////
class LibraryApp:
def __init__(self, e1):
self.e1 = e1
[Link]("Gestion de produits")
[Link]("800x600")
self.bg_color = "#f0f0f0"
self.button_color = "#4a7a8c"
[Link](bg=self.bg_color)
self.csv_file = "[Link]" hna wa7d file csv smina produites
self.create_csv_if_not_exists() crée ce fichier s’il n’existe pas deja
[Link](self.e1, text="Bienvenue dans la gestion des produits",
font=("Arial", 18), bg=self.bg_color).pack(pady=20) hna affichage nta3 tite f lfoo9
nta3 fenetre
self.input_frame = [Link](self.e1, bg=self.bg_color)
self.input_frame.pack(pady=20)
self.button_frame = [Link](self.e1, bg=self.bg_color)
self.button_frame.pack(pady=10)
self.list_frame = [Link](self.e1)
self.list_frame.pack(fill=[Link], expand=True, padx=20, pady=10) had
fill=[Link] list katb9a mmdoda hta kat3mr tout l’espace disponible.
han wa7d Appelle nat3 trois méthodes
self.create_input_widgets() crée lowla nat3 les produits.
self.create_buttons() tanya nta3 les bottnos ajouter suprimer
self.create_list_widget() un widget d’affichage pour montrer la liste des
produits.
///////////////////////////////////////////////////////////////////////////////////
//////////////////////
def create_csv_if_not_exists(self): Déclaration de la méthode et qui crée le
fichier CSV ila ma kanch.
if not [Link](self.csv_file): verification de le fichier nexiste
pas os hiya li declarinaha f lowl
with open(self.csv_file, mode='w', newline='', encoding='utf-8') as
file: hna kan7lo had file b mode w li kaymkn lina nkto newline pour eviterles
lignes vides utf nktbo les caracters corerctement 7al accents
writer = [Link](file)
[Link](["ID", "Nom", "Categorie", "Prix"]) ecrire lentet
de fichier csv
///////////////////////////////////////////////////////////////////////////////////
//////////////////////////
def create_input_widgets(self):
[Link](self.input_frame, text="ID:", bg=self.bg_color).grid(row=0,
column=0, padx=5, pady=5, sticky="e") CREATION NTA3 chap li homa id nom categoeie
prix
self.title_entry = [Link](self.input_frame, width=40) le gestionnaire de
placement aligné à droite kaynin bzafff b7al sticky="w" → aligné à gauche
self.title_entry.grid(row=0, column=1, padx=5, pady=5)
[Link](self.input_frame, text="Nom:", bg=self.bg_color).grid(row=1,
column=0, padx=5, pady=5, sticky="e")
self.author_entry = [Link](self.input_frame, width=40)
self.author_entry.grid(row=1, column=1, padx=5, pady=5)
[Link](self.input_frame, text="Categorie:", bg=self.bg_color).grid(row=2,
column=0, padx=5, pady=5, sticky="e")
self.year_entry = [Link](self.input_frame, width=40)
self.year_entry.grid(row=2, column=1, padx=5, pady=5)
[Link](self.input_frame, text="Prix:", bg=self.bg_color).grid(row=3,
column=0, padx=5, pady=5, sticky="e")
self.isbn_entry = [Link](self.input_frame, width=40)
self.isbn_entry.grid(row=3, column=1, padx=5, pady=5)
///////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////
def create_buttons(self):
add_button = [Link](self.button_frame, text="Ajouter",
command=self.add_book,
bg=self.button_color, fg="white", width=15) appelle
la méthode self.add_book pour ajouter un produit)
add_button.grid(row=0, column=0, padx=5, pady=5)
show_button = [Link](self.button_frame, text="Afficher tout",
command=self.display_books,
bg=self.button_color, fg="white", width=15)
show_button.grid(row=0, column=1, padx=5, pady=5) Appelle
self.display_books pour afficher tous les produits dans la liste.
delete_button = [Link](self.button_frame, text="Supprimer",
command=self.delete_book,
bg="#8c4a4a", fg="white", width=15) Appelle
self.delete_book pour supprimer un produit sélectionné.
delete_button.grid(row=0, column=2, padx=5, pady=5)
clear_button = [Link](self.button_frame, text="Effacer",
command=self.clear_fields,
bg="#4a8c5e", fg="white", width=15)Appelle
self.clear_fields pour vider les champs de saisie.
clear_button.grid(row=0, column=3, padx=5, pady=5)
search_button = [Link](self.button_frame, text="Rechercher",
command=self.search_book,
bg=self.button_color, fg="white",
width=15)Appelle self.search_book pour chercher un produit selon les champs
search_button.grid(row=0, column=4, padx=5, pady=5)
///////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
def create_list_widget(self):
[Link] = [Link](self.list_frame, columns=("ID", "Nom",
"Categorie", "Prix"), show="headings")
Crée un widget Treeview (de ttk, la version moderne de Tkinter) dans le cadre
self.list_frame show="headings" indique de n’afficher que les entêtes
[Link]("ID", text="ID") DEFINIR LES TITRES
[Link]("Nom", text="Nom")
[Link]("Categorie", text="Categorie")
[Link]("Prix", text="Prix")
[Link]("ID", width=200)
[Link]("Nom", width=150)
[Link]("Categorie", width=100)
[Link]("Prix", width=100)
scrollbar = [Link](self.list_frame, orient="vertical",
command=[Link]) Barre de défilement verticale
[Link](yscrollcommand=[Link])
[Link](side="left", fill="both", expand=True)
[Link](side="right", fill="y")
Le Treeview prend tout l’espace disponible (fill="both", expand=True) sur la
gauche.
La scrollbar est placée à droite et prend toute la hauteur (fill="y").
///////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////
def add_book(self):
title = self.title_entry.get()
author = self.author_entry.get()
year = self.year_entry.get()
isbn = self.isbn_entry.get()
if not title or not author or not year or not isbn:
[Link]("Erreur", "Tous les champs doivent être remplis")
return
HNA wa7d condition vérifie si un des champs est vide.
Si oui : une fenêtre d’erreur s'affiche, et la fonction s'arrête ici (avec return).
with open(self.csv_file, mode='a', newline='', encoding='utf-8') as file:
writer = [Link](file) [Link]() permet d’écrire dans ce fichier
ligne par ligne.
[Link]([title, author, year, isbn])
[Link]("Succès", "Produit ajouté avec succès")
self.clear_fields() Appelle une méthode (que tu dois créer) pour vider les
champs de saisie après l’ajout
self.display_books() Appelle une méthode (à créer aussi) pour actualiser
la liste des produits affichée dans le tableau (Treeview).
///////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
def display_books(self):
for item in [Link].get_children():
[Link](item)
Efface toutes les lignes déjà affichées dans le tableau, pour éviter les doublons
lors du rechargement.
try:
with open(self.csv_file, mode='r', newline='', encoding='utf-8') as
file:
reader = [Link](file)
next(reader)
for row in reader:
[Link]("", "end", values=row)
Pour chaque ligne du fichier, ajoute une nouvelle entrée dans le tableau.
except FileNotFoundError:
[Link]("Erreur", "Fichier de données introuvable")
Si le fichier n’existe pas, affiche une fenêtre d’erreur.
def delete_book(self):
selected_item = [Link]()
if not selected_item:
[Link]("Erreur", "Veuillez sélectionner un produit à
supprimer")
return
Vérifie qu’un produit est sélectionné. Sinon, affiche une erreur.
if not [Link]("Confirmation", "Êtes-vous sûr de vouloir
supprimer ce produit ?"):
return
Affiche une confirmation avant suppression.
item_data = [Link](selected_item[0])['values']
Récupère les données de la ligne sélectionnée (ID, Nom, etc.).
books = []
with open(self.csv_file, mode='r', newline='', encoding='utf-8') as file:
reader = [Link](file)
header = next(reader)
for row in reader:
if row != [str(val) for val in item_data]:
[Link](row)
Stocke les autres produits dans la liste books.
with open(self.csv_file, mode='w', newline='', encoding='utf-8') as file:
writer = [Link](file)
[Link](header)
[Link](books)
Réécrit tout le fichier en supprimant le produit sélectionné.
self.display_books()
[Link]("Succès", "Produit supprimé avec succès")
Recharge la liste, puis affiche une confirmation.
def clear_fields(self):
self.title_entry.delete(0, [Link])
self.author_entry.delete(0, [Link])
self.year_entry.delete(0, [Link])
self.isbn_entry.delete(0, [Link])
ffacer le contenu des champs de saisie.
///////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////
def search_book(self):
search_window = [Link](self.e1)
search_window.title("Rechercher un produit")
search_window.geometry("400x200")
frame = [Link](search_window, bg=self.bg_color)
[Link](pady=20) Ajoute un cadre (Frame) pour organiser les éléments
de la fenêtre.
[Link](frame, text="Rechercher par:", bg=self.bg_color).grid(row=0,
column=0, padx=5, pady=5)
self.search_var = [Link](value="ID")
search_options = ["ID", "Nom", "Prix"] Affiche un menu déroulant
(OptionMenu) pour choisir le critère de recherche.
search_menu = [Link](frame, self.search_var, *search_options)
search_menu.grid(row=0, column=1, padx=5, pady=5)
[Link](frame, text="Terme de recherche:", bg=self.bg_color).grid(row=1,
column=0, padx=5, pady=5)
self.search_entry = [Link](frame, width=30) Affiche un champ pour que
l’utilisateur saisisse ce qu’il recherche (le mot-clé)
self.search_entry.grid(row=1, column=1, padx=5, pady=5)
search_button = [Link](frame, text="Rechercher",
command=self.perform_search,
bg=self.button_color, fg="white")
search_button.grid(row=2, columnspan=2, pady=10)
def perform_search(self):
search_term = self.search_entry.get().lower()
search_by = self.search_var.get() Récupère le critère choisi (ID, Nom, ou
Prix).
if not search_term:
[Link]("Erreur", "Veuillez entrer un terme de recherche")
return Vérifie que l’utilisateur a bien tapé quelque chose.
for item in [Link].get_children():
[Link](item) Vide la table Treeview pour afficher
uniquement les résultats de la recherche.
try:
with open(self.csv_file, mode='r', newline='', encoding='utf-8') as
file:
reader = [Link](file)
next(reader)
found = False
for row in reader:
if (search_by == "ID" and search_term in row[0].lower()) or \
(search_by == "Nom" and search_term in row[1].lower()) or \
(search_by == "Prix" and search_term in row[3].lower()):
Compare le terme recherché à la colonne appropriée selon le critère sélectionné,
puis affiche la ligne si elle correspond.
[Link]("", "end", values=row)
found = True
if not found:
[Link]("Information", "Aucun produit trouvé")
except FileNotFoundError:
[Link]("Erreur", "Fichier de données introuvable")
/////////////////////////////////////////////////////////////
if __name__ == "__main__":
e1 = [Link]()
login_app = LoginWindow(e1)
[Link]()