Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ##imports
- from tkinter import Tk, Toplevel, Listbox, Canvas, IntVar, CENTER, END, LEFT, RIGHT, BOTH, W, E, N, S, ACTIVE, Y, ALL # GUI
- from tkinter import messagebox
- from tkinter.ttk import Frame, Combobox, Button, Label, Entry, Checkbutton, Scrollbar # Widgets avec thèmes
- import csv
- from datetime import *
- from os.path import join, exists
- from os import makedirs
- ##liste_de_var
- #L'ensemble des variables de chaque fichier est représenté par une liste, dont chaque élément est une variable dudit fichier.
- #Cette variable est elle-même une liste, de la forme suivante :
- #["nom de la variable", "type de la variable", **paramètres supplémentaires, suivant le type de la variable**, "booleen:variable importante"]
- #Les différents types sont les suivants :
- #"d" : date ; on précisera en paramètre supplémentaire si la date est une date de début ("dd"),
- #si c'est une date de fin ("df"), ou si c'est une simple date ("d")
- #"int" : entier
- #"str" : chaîne de caractères
- #"ld" : liste déroulante
- #Par exemple, la variable "Situation de la demande" sera codée de la façon suivante :
- #["Situation de la demande", "ld", ["", "Active", "Annulée", "Fermée", "Pourvue"]]
- #Ici, le troisième élément de la liste représente donc les modalités de la variable.
- #En revanche, la variable "Nom du stagiaire" sera codée de la façon suivante :
- #["Nom du stagiaire", "str"]
- #Ici, il n'y a pas de paramètre supplémentaire à ajouter, la liste ne comprend donc que 2 éléments et non 3.
- Var_stages=[["Situation de la demande","ld",["","Active","Annulée","Fermée","Pourvue"],True],
- ["Nombre stagiaire","int",True],
- ["Nom du stagiaire","str",True],
- ["Prénom du stagiaire","str",True],
- ["Rémunération","ld",["","Oui","Non"],True],
- ["Site","ld",["","Paris","Arcueil","Angers"],True],
- ["Structure","str",True],
- ["Unité","str",True],
- ["Niveau études","ld",["","Collège","Lycée","Bac +1","Bac +2","Licence","Master 1","Master 2","Master Spécialisé"],True],
- ["Domaine études","ld", ["", "Actuariat", "Comptabilité", "Contrôle de gestion", "Audit/Contrôle interne", "Assurance", "Juridique", "Finance de marché/Risques", "RH", "Communication/Digital", "Informatique/MOA", "Achats", "Secrétariat", "Statistiques", "Immeuble/Logistique", "Commercial/marketing", "Autre"],True],
- ["Durée","int",True],
- ["Date de début","d","dd",True],
- ["Date de fin","d","df",True],
- ["CHR","str",False],
- ["Indemnités de stage (brut)","int",False],
- ["N°TS","str",False],
- ["Nom responsable hierarchique","str",False],
- ["Nom tuteur","str",False],
- ["Demande validée","str",False],
- ["Transmission Dossier Paie/GA","str",False],
- ["Convention","str",False],
- ["Centre de formation","str",False],
- ["Adresse","str",False],
- ["Demande de badge","str",False],
- ["Commentaires","str",False]]
- Var_CDD=[["N° Demande", "str", True],
- ["Situation", "ld", ["", "Active", "Annulée", "Fermée", "Pourvue"], True],
- ["CRH", "str", True],
- ["Intitulé du poste", "str", True],
- ["Zone géographique", "ld", ["", "Paris", "Arcueil", "Angers"], True],
- ["Nombre de CDD", "int", True],
- ["Famille","ld", ["", "EC","AS","IL","FC","GC","JU","CM","RH","CO","SA","MO"], True],
- ["Fonction", "str", True],
- ["Classe","ld",["","1","2","3","4","5","6","7"], True],
- ["Origine", "ld", ["", "Remplacement", "Surcroît", "Autre", "CDD Senior"], True],
- ["Personne remplacée", "str", True],
- ["Entité", "str", True],
- ["Structure","str", True],
- ["Hiérarchique", "str", True],
- ["C/NC", "ld", ["", "C", "NC"], True],
- ["Demande hiérarchique", "str", False],
- ["Réception RH12", "str", False],
- ["Présentation 1er candidat", "str", False],
- ["Présentation du candidat retenu", "str", False],
- ["Clôture de mission", "d", False],
- ["Date annulation", "d", False],
- ["Date arrivée prise de fonction", "d", False],
- ["Indicateur budget", "ld", ["","0","1"], False],
- ["Mat. candidat ou N° recrut.", "str", False],
- ["Date arrivée CNP ou date début contrat", "d", "dd", False],
- ["Date départ CNP ou date fin contrat", "d", "df", False],
- ["Candidat retenu", "str", False],
- ["Âge", "int", False],
- ["Sexe", "ld", ["", "H", "F"], False],
- ["Niveau études", "ld", ["", "Bac Professionnel", "Bac + 1", "Bac + 2", "DUT", "BTS", "DCG", "Licence", "DSCG", "Master 1", "Master 2", "Master Spécialisé"], False],
- ["Diplôme", "str", False],
- ["Origine candidature", "str", False],
- ["Date RDV manager", "d", False],
- ["Délai", "str", False],
- ["Durée du CDD (en mois)", "int", False],
- ["Prolongation (en mois)", "int", False],
- ["Actions", "str", False],
- ["Commentaires FH11", "str", False],
- ["Nbre candidat presente H", "str", False],
- ["Nbre candidat presente F", "str", False]]
- Var_alternants=[["Situation de la demande", "ld", ["", "Active", "Annulée", "Fermée", "Pourvue"], True],
- ["CHR", "str", True],
- ["N° RH", "str", True],
- ["Matricule", "str", True],
- ["NOM", "str", True],
- ["Prénom", "str", True],
- ["BU", "str", True],
- ["UNITE", "str", True],
- ["Site", "ld", ["", "Paris", "Arcueil", "Angers"], True],
- ["Date début de contrat", "d", "dd", True],
- ["Date fin de contrat", "d", "df", True],
- ["Type de contrat", "str", True],
- ["Diplôme préparé", "ld", ["", "Bac Professionnel", "Bac + 1", "Bac + 2", "DUT", "BTS", "DCG", "Licence", "DSCG", "Master 1", "Master 2", "Master Spécialisé"], True],
- ["Domaine métier", "str", True],
- ["Genre", "ld", ["", "H", "F"], False],
- ["Âge", "int", False],
- ["Tuteur", "str", False],
- ["Responsable hiérarchique", "str", False],
- ["Organisme de formation", "str", False],
- ["Adresse", "str", False],
- ["Date validation demande", "d", False],
- ["Commentaire", "str", False],
- ["Date d'envoi à la Gestion Administrative", "d", False],
- ["Date d'envoi à la CCI ou l'OPCA", "d", False],
- ["Date d'envoi fiche période d'essai", "d", False]]
- Var_interim=[["Agence", "ld", ["", "ADECCO", "HAYS", "KELLY", "MANPOWER", "RANDSTAD"], True],
- ["NOM", "str", True],
- ["Prénom", "str", True],
- ["Sexe", "ld", ["", "H", "F"], True],
- ["Date de début", "d", "dd", True],
- ["Date de fin", "d", "df", True],
- ["Nature", "str", True],
- ["Mois", "ld", [str(i) for i in range(13)], True],
- ["Jours travaillés", "int", True],
- ["Jours payés", "int", True],
- ["Motif", "str", True],
- ["Description du motif", "str", True],
- ["Fonction", "str", True],
- ["Famille professionnelle", "str", True],
- ["Statut", "ld", ["", "C", "NC"], True],
- ["Nouvelle entité", "str", True],
- ["BU/Direction Groupe", "str", True],
- ["Site", "ld", ["", "Paris", "Arcueil", "Angers"], True],
- ["Observations", "str", True],
- ["Nbre d'interim", "int", True],
- ["Montant facturé", "float", True],
- ["Avoir", "float", True],
- ["N° Facture", "str", True],
- ["N° Engagement", "str", True],
- ["Centre budgétaire", "str", True],
- ["N° Contrat", "str", True],
- ["Taux horaire", "float", True],
- ["Coeff", "float", True],
- ["Taux facturé", "float", True]]
- ##Définition des classes
- class Menu_principal(Tk):
- dic_var = {"CDD":Var_CDD, "Alternants":Var_alternants, "Stages":Var_stages, "Intérim":Var_interim }
- dic_code_fichier = {"CDD":"CDD_", "Alternants":"alternants_", "Stages":"stages_", "Intérim":"Int_"}
- annees = [str(i) for i in range(2016, 2051)]
- """Affiche le menu principal"""
- dev = False
- def __init__(self, dev = False):
- self.dev = dev
- self.root = Tk()
- self.root.title("Menu principal")
- self.root.geometry("260x150")
- #Widgets
- self.canvas = Canvas(self.root, width = 260, height = 150, highlightthickness = 0)
- self.canvas.place(relx = 0.5, rely = 0.5, anchor = CENTER)
- self.frame = Frame(self.canvas)
- self.frame.pack()
- self.choix_fichier = Combobox(self.frame, exportselection=0, state="readonly", width = 10)
- self.choix_fichier["values"] = list(self.dic_var.keys())
- self.choix_fichier.set("Stages")
- self.choix_fichier.grid(row = 0, column = 0, padx=5, pady=4, sticky = E)
- self.choix_annee = Combobox(self.frame, exportselection = 0, state = "readonly", width = 10)
- self.choix_annee["values"] = self.annees
- self.choix_annee.set(2017)
- self.choix_annee.grid(row = 0, column = 1, padx=5, pady=4, sticky = W)
- Button(self.canvas, text="Ajouter un individu", width = 27, command = lambda : self.bouton_ig_ajout()).pack(padx=5, pady=4)
- Button(self.canvas, text="Modifier un individu", width = 27, command = lambda : self.bouton_ig_rech()).pack(padx=5, pady=4)
- self.canvas.update()
- self.root.mainloop()
- def init_var(self):
- """charge les variables sous la forme d'une liste"""
- self.liste_de_var = self.dic_var[self.choix_fichier.get()]
- self.filename = self.file_name()
- self.filepath = self.file_path()
- def code_fichier(self):
- """renvoie le code fichier en fonction du choix de l'utilisateur ; exemple : CDD_"""
- return self.dic_code_fichier[self.choix_fichier.get()]
- def file_path(self):
- """renvoie le path du fichier associé à la saisie"""
- debut_path = self.choix_annee.get() + "\CSV"
- if not exists(debut_path):
- makedirs(debut_path)
- return join(debut_path, self.filename)
- def file_name(self):
- """renvoie le nom du fichier associé à la saisie"""
- annee = self.choix_annee.get()
- return (self.code_fichier() + annee + ".csv")
- def bouton_ig_ajout(self):
- self.init_var()
- utilisateur_veut_nouveau_fichier = self.pop_up_fichier_inexistant()
- if utilisateur_veut_nouveau_fichier == None:
- self.root.withdraw() #fait disparaître self.root (et tous ses widgets) ; pour le faire réapparaître, utiliser self.deiconify() ; le pb : quand utiliser self.deiconify() ??
- Interface_graphique(parent = self, which = "a")
- elif utilisateur_veut_nouveau_fichier:
- self.nouveau_fichier()
- self.root.withdraw() #fait disparaître self.root
- Interface_graphique(parent = self, which = "a")
- def bouton_ig_rech(self):
- self.init_var()
- utilisateur_veut_nouveau_fichier = self.pop_up_fichier_inexistant()
- if utilisateur_veut_nouveau_fichier == None:
- self.root.withdraw() #fait disparaître self.root
- Interface_graphique(parent = self, which = "r")
- elif utilisateur_veut_nouveau_fichier:
- self.nouveau_fichier()
- def fichier_existe(self):
- try:
- with open(self.filepath):
- return True
- except IOError:
- return False
- def pop_up_fichier_inexistant(self):
- if self.fichier_existe():
- return None
- elif not(self.fichier_existe()):
- return messagebox.askyesnocancel("Information", "Le fichier sélectionné n'existe pas. Voulez-vous en initialiser un nouveau ?")
- def nouveau_fichier(self):
- """crée fichier csv vide (avec variables en 1e ligne)"""
- with open(self.filepath,'w') as file:
- writer = csv.writer(file, delimiter=";",lineterminator='\n')
- writer.writerow([self.liste_de_var[i][0] for i in range(len(self.liste_de_var))])
- return messagebox.showinfo("Information", "Fichier créé.")
- class Interface_graphique(Tk): #dans la suite : ig correspondra à interface graphique
- dic_texte_infobulle = {"int":"Saisissez un entier.", "d":"Saisissez une date au format jj/mm/aaaa.", "float":"Saisissez un nombre décimal.", "duree_stage":"Saisissez un entier (unité : jour).", "indicateurbudget_cdd":"0 = à ne pas prendre dans le budget ; 1 = à prendre en compte."}
- """Affiche une interface graphique"""
- dev = False
- def __init__(self, parent, which, line_id_a_modif = None, index_liste = None):
- """Interface de recherche ou interface de modification"""
- self.type = which
- self.parent = parent #permet d'appeler le Tk "master"
- self.dev = self.parent.dev
- self.root = Toplevel(self.parent.root)
- self.root.grab_set() #empêche de modifer les fenêtres parentes
- self.root.focus_set() #passe le focus (1e action du clavier par ex)
- self.liste_de_var = self.parent.liste_de_var
- self.filename = self.parent.filename
- self.filepath = self.parent.filepath
- self.afficher_scrollbar = (self.filename[:-9] == "CDD")
- if which == "r" : #charge ig de recherche
- self.ig_rech()
- elif which == "a" : #charge ig d'ajout
- self.ig_ajout()
- elif which == "m" : #charge ig de modification
- self.ig_modif(line_id_a_modif, index_liste)
- for i in range(len(self.liste_de_var)): #on a déjà grid les labels avec self.creer_Tkobjets()
- self.Tkobjets[i].grid(row=i,column=1, pady=3, padx=5)
- if not(self.afficher_scrollbar):
- self.frame.pack()
- else:
- self.frame.update()
- self.canvas.create_window(0, 0, window=self.frame, anchor = N + W)
- self.canvas.configure(scrollregion=self.canvas.bbox(ALL))
- self.root.bind('<Return>', lambda e: self.raccourci_entree())
- self.root.mainloop()
- def creer_Tkobjets(self):
- """Retourne les différents objets de saisie + grid les labels associes"""
- if not(self.afficher_scrollbar):
- self.canvas = Canvas(self.root, highlightthickness = 0)
- self.canvas.pack(side=LEFT, fill = BOTH)
- else:
- self.scrollbar = Scrollbar(self.root, orient = "vertical")
- self.scrollbar.grid(row = 0, column = 1, sticky = N + S)
- self.canvas = Canvas(self.root, yscrollcommand=self.scrollbar.set, width = 550, height = 750, highlightthickness = 0)
- self.canvas.grid(row = 0, column = 0, sticky=W+E+N+S)
- self.scrollbar.config(command=self.canvas.yview)
- self.frame = Frame(self.canvas)
- L = []
- for i in range(len(self.liste_de_var)):
- #intitules des variables
- label = Label(self.frame,text=self.liste_de_var[i][0])
- label.grid(row=i,column=0,sticky=W, padx = 5)
- #saisie texte ou listes deroulantes
- if self.liste_de_var[i][1]=="ld":
- L.append(Combobox(self.frame,exportselection=0, width = 17 ,state="readonly"))
- L[i]["values"] = self.liste_de_var[i][2]
- L[i].set(self.liste_de_var[i][2][0])
- else:
- L.append(Entry(self.frame, width = 20))
- #infobulles
- if (self.filename[:-9] == "stages" and self.liste_de_var[i][0] == "Durée"): #"en mois"
- infoBulle(label, self.dic_texte_infobulle["duree_stage"])
- infoBulle(L[i], self.dic_texte_infobulle["duree_stage"])
- elif (self.filename[:-9] == "CDD" and self.liste_de_var[i][0] == "Indicateur budget"):
- infoBulle(label, self.dic_texte_infobulle["indicateurbudget_cdd"])
- infoBulle(L[i], self.dic_texte_infobulle["indicateurbudget_cdd"])
- elif est_dans(self.liste_de_var[i][1], ["int","float","d"]):
- infoBulle(label, self.dic_texte_infobulle[self.liste_de_var[i][1]])
- infoBulle(L[i], self.dic_texte_infobulle[self.liste_de_var[i][1]])
- return L
- def saisie(self): #fusion de criteres et saisie_modif
- """Renvoie valeurs saisies par l'utilisateur sous le format [val1, ...]"""
- return [objet.get() for objet in self.Tkobjets]
- def afficher_erreur(self,erreur):
- """Affiche message d'erreur si saisie incohérente ; retourne True si erreur, False sinon"""
- msg = ""
- if erreur == "type":
- Erreurs, dates_inversees = controle_type(self.saisie(), self.liste_de_var)
- if dates_inversees: #on remet dans le bon sens
- messagebox.showerror("Erreur","La date de fin est antérieure à la date de début.")
- return True
- elif erreur =="rempli":
- Erreurs = controle_est_vide(self.saisie(),self.liste_de_var)
- n_erreurs = sum(Erreurs) #Erreurs = [True/False, ... , True/False] avec : True = 1, False = 0
- if n_erreurs == 0:
- return False
- elif n_erreurs == 1:
- msg = "La variable " + self.liste_de_var[Erreurs.index(True)][0] + " est mal renseignée."
- elif n_erreurs > 1:
- msg_var = "" #stocke les noms des variables présentant des valeurs incohérentes
- for i in range(len(self.liste_de_var)):
- if Erreurs[i]:
- if n_erreurs > 1:
- msg_var = msg_var + " " + self.liste_de_var[i][0] + ","
- n_erreurs -= 1 #après cette ligne, il reste encore n_erreurs variables à ajouter à msg_var
- elif n_erreurs == 1: # il reste une seule variable
- msg_var = msg_var + " et " + self.liste_de_var[i][0]
- msg = "Les variables" + msg_var + " sont mal renseignées."
- if erreur == "rempli":
- n_erreurs = sum(Erreurs)
- if n_erreurs == 1:
- msg = msg + " (Cette variable ne peut être laissée vide.)"
- elif n_erreurs > 1:
- msg = msg + " (Ces variables ne peuvent être laissées vides.)"
- messagebox.showerror('Erreur',msg)
- return True
- def raccourci_entree(self):
- """Doit déterminer s'il faut lancer bouton_modif ou bouton_rech ou bouton_ajout lorsque l'utilisateur appuie sur la touche entree"""
- if self.root.title() == "Saisie de recherche":
- self.bouton_rech()
- elif self.root.title() == "Saisie de modification":
- self.bouton_modif()
- elif self.root.title() == "Saisie d'ajout":
- self.bouton_ajout()
- def fermer_ig(self):
- self.parent.root.deiconify()
- self.root.destroy()
- ##interface de recherche
- def ig_rech(self):
- self.root.title("Saisie de recherche")
- self.root.protocol("WM_DELETE_WINDOW",lambda : self.fermer_ig()) #s'exécute quand on appuie sur la croix de fermeture
- self.root.bind('<Escape>', lambda e: self.fermer_ig()) #s'execute lorsqu'on appuie sur Echap
- #Widgets
- self.Tkobjets = self.creer_Tkobjets()
- Button(self.frame, text="Rechercher",command = lambda : self.bouton_rech()).grid(row=0,column=3, padx = 5, pady = 5)
- def bouton_rech(self):
- erreur_types = self.afficher_erreur(erreur = "type")
- if not(erreur_types):
- self.root.withdraw() #fait disparaître self.root
- Resultats_recherche(saisie_recherche = self)
- def elem_list(self):
- """Retourne iterable pour remplir la listbox de Resultats_recherche, recalcule resultats recherche"""
- a_afficher = reponse_recherche(self.saisie(), self.filepath,self.liste_de_var) #est une liste dont les éléments sont de la forme [[val1, ... , val n], nligne]
- elem_list=[]
- for i in range(len(a_afficher)):
- elem="| "
- for j in range(len(self.liste_de_var)):
- if a_afficher[i][0][j] != "" and self.liste_de_var[j][-1]:
- elem=elem+a_afficher[i][0][j]+" | " # a_afficher[i][0][j] = val(j+1)
- elem_list.append(elem)
- return elem_list
- ##interface d'ajout
- def ig_ajout(self):
- self.root.title("Saisie d'ajout")
- self.root.bind('<Escape>', lambda e: self.fermer_ig())
- self.root.protocol("WM_DELETE_WINDOW",lambda : self.fermer_ig()) #s'exécute quand on appuie sur la croix de fermeture
- self.vider_champs_apres_saisie = IntVar() #création de "variable-retour" pour Checkbutton
- #Widgets
- self.Tkobjets = self.creer_Tkobjets()
- Checkbutton(self.frame, variable = self.vider_champs_apres_saisie, text = "Vider les champs après la saisie").grid(row = 1, column = 3, padx = 5)
- Button(self.frame, text="Ajouter",command = lambda : self.bouton_ajout()).grid(row=0,column=3, padx = 5, pady = 5)
- def bouton_ajout(self):
- """Si confirmation, rend effectif la saisie de l'utilisateur"""
- erreur_rempli = self.afficher_erreur(erreur = "rempli")
- if not(erreur_rempli):
- erreur_types = self.afficher_erreur(erreur = "type")
- if not(erreur_types):
- if pop_up_confirmer():
- add_line(self.saisie(), self.filepath)
- if self.vider_champs_apres_saisie.get():
- self.vider_formulaire()
- messagebox.showinfo("Information", "L'individu a bien été ajouté à la base de données.")
- def vider_formulaire(self):
- """Vide le formulaire"""
- for i in range(len(self.liste_de_var)):
- if self.liste_de_var[i][1]=="ld":
- self.Tkobjets[i].set("")
- else:
- self.Tkobjets[i].delete(0,END)
- ##interface de modification
- def ig_modif(self, line_id_a_modif, index_liste):
- #ces valeurs sont constantes dans interface de modif
- self.line_id_a_modif = line_id_a_modif
- self.index_liste = index_liste
- self.root.title("Saisie de modification")
- self.root.bind('<Escape>', lambda e: self.root.confirmer_sortie_saisie_modifiee())
- self.root.protocol("WM_DELETE_WINDOW",lambda : self.confirmer_sortie_saisie_modifiee())
- #Widgets
- self.Tkobjets = self.creer_Tkobjets()
- self.preremplir_formulaire() #charge les données du csv quant à l'individu ciblé
- Button(self.frame, text="Modifier",command = lambda : self.bouton_modif()).grid(row=0,column=3, padx = 5, pady = 5)
- self.hardcore = IntVar() #création de "variable-retour" pour Checkbutton
- Checkbutton(self.frame, variable = self.hardcore, text = "Ne pas demander de confirmation").grid(row = 1, column = 3, padx = 5)
- def bouton_modif(self):
- """Si confirmation, rend effectif la saisie de l'utilisateur"""
- erreur_rempli = self.afficher_erreur(erreur = "rempli")
- if not(erreur_rempli):
- erreur_types = self.afficher_erreur(erreur = "type")
- if not(erreur_types):
- if self.hardcore.get() or pop_up_confirmer():
- mod_line(self.line_id_a_modif, self.saisie(), self.filepath)
- self.parent.update_liste()
- self.parent.liste.selection_set(self.index_liste)
- def preremplir_formulaire(self):
- """Preremplit avec valeurs du csv"""
- if self.type == "m":
- ligne_select = read_line(self.line_id_a_modif, self.filepath)
- elif self.type == "a" and self.dev == True:
- ligne_select = creer_exemples(1, self.liste_de_var, self.parent.choix_annee.get())[0]
- for i in range(len(self.liste_de_var)):
- if self.liste_de_var[i][1]=="ld":
- for item in self.liste_de_var[i][2]:
- if est_dans(ligne_select[i],self.liste_de_var[i][2]): #pour éviter bug (sur Listbox) si données mal renseignées dans le csv
- self.Tkobjets[i].set(ligne_select[i]) #on fixe à la valeur du csv
- else:
- self.Tkobjets[i].insert(0,ligne_select[i]) #idem
- def confirmer_sortie_saisie_modifiee(self):
- if self.saisie() != read_line(self.line_id_a_modif, self.filepath):
- if messagebox.askokcancel("Confirmation", "Êtes-vous sûr de vouloir quitter sans enregistrer les modifications ?"):
- self.root.destroy()
- else:
- self.root.destroy()
- class Resultats_recherche(Tk):
- """Affiche les resultats de la recherche dans une Listbox"""
- dev = False
- def __init__(self, saisie_recherche, dev = False):
- "Listbox + 2 boutons si resultats, messagebox sinon"
- self.parent = saisie_recherche
- self.dev = self.parent.dev
- if self.parent.elem_list() == []:
- messagebox.showinfo("Résultats de la recherche","Aucun individu ne répond à la requête.")
- self.parent.root.deiconify()
- else: #ne se lance que si des individus correspondent à la requête
- self.root = Toplevel(self.parent.root)
- self.root.title("Résultats de la recherche")
- self.root.grab_set() #empêche de modifer les fenêtres parentes
- self.root.focus_set() #passe le focus (1e action du clavier par ex)
- self.liste_de_var = self.parent.liste_de_var
- self.filename = self.parent.filename
- self.filepath = self.parent.filepath
- #creation de la Listbox
- self.liste = self.remplir_listbox()
- self.liste.pack()
- #Autres widgets
- Button(self.root, text="Modifier",command=lambda:self.bouton_ig_modif()).pack()
- Button(self.root, text="Supprimer",command=lambda:self.bouton_suppr()).pack()
- self.root.protocol("WM_DELETE_WINDOW",lambda : self.fermer_fenetre())
- self.root.bind('<Escape>', lambda e: self.fermer_fenetre())
- self.root.mainloop()
- def remplir_listbox(self):
- """Cree la Listbox"""
- elem_list = self.parent.elem_list()
- listbox = Listbox(self.root, height=len(elem_list), width = max(len(ligne) for ligne in elem_list), exportselection=0, activestyle = 'none')
- for item in elem_list:
- listbox.insert(END,item)
- return listbox
- def line_id(self):
- """Renvoie line_id dans csv de la selection"""
- choisi = self.liste.get(ACTIVE)
- n0 = self.parent.elem_list().index(choisi) #indice dans la listbox de la sélection
- line_id = reponse_recherche(self.parent.saisie(), self.filepath, self.liste_de_var)[n0][1] #indice dans le csv
- return line_id
- def index_liste(self):
- """Renvoie index dans la liste de la selection"""
- return self.liste.curselection()
- def bouton_ig_modif(self):
- """Ouvre interface graphique pour modifier individu selectionne et renvoie line_id, index_liste"""
- Interface_graphique(parent = self, which = "m", line_id_a_modif = self.line_id(), index_liste = self.index_liste())
- def bouton_suppr(self):
- """Si confirmation, supprime la selection de la Listbox"""
- if pop_up_confirmer():
- del_line(self.line_id(),self.filepath)
- self.update_liste()
- def update_liste(self):
- """Actualise la Listbox"""
- elem_list = self.parent.elem_list()
- self.liste.delete(0,END)
- for item in elem_list:
- self.liste.insert(END,item)
- def fermer_fenetre(self):
- self.root.destroy()
- self.parent.root.destroy()
- self.parent.parent.root.deiconify()
- class infoBulle(Toplevel):
- def __init__(self,parent=None,texte='', temps=500):
- Toplevel.__init__(self,parent,bd=1,bg='black')
- self.tps=temps
- self.parent=parent
- self.withdraw()
- self.overrideredirect(1)
- self.transient()
- l=Label(self,text=texte,background="white",justify='left')
- l.update_idletasks()
- l.pack()
- l.update_idletasks()
- self.tipwidth = l.winfo_width()
- self.tipheight = l.winfo_height()
- self.parent.bind('<Enter>',self.delai)
- self.parent.bind('<Button-1>',self.efface)
- self.parent.bind('<Leave>',self.efface)
- def delai(self,event):
- self.action=self.parent.after(self.tps,self.affiche)
- def affiche(self):
- self.update_idletasks()
- posX = self.parent.winfo_rootx()+self.parent.winfo_width()
- posY = self.parent.winfo_rooty()+self.parent.winfo_height()
- if posX + self.tipwidth > self.winfo_screenwidth():
- posX = posX-self.winfo_width()-self.tipwidth
- if posY + self.tipheight > self.winfo_screenheight():
- posY = posY-self.winfo_height()-self.tipheight
- #~ print posX,print posY
- self.geometry('+%d+%d'%(posX,posY))
- self.deiconify()
- def efface(self,event):
- self.withdraw()
- self.parent.after_cancel(self.action)
- ##outils csv
- def read_line(line_id,file_name):
- with open(file_name,'r') as myfile:
- r = csv.reader(myfile, delimiter=';', quotechar='"', lineterminator='\n')
- lines=[l for l in r]
- return lines[line_id]
- def add_line(new_line, file_name):
- """ajoute ligne à la fin du csv"""
- #on lit le fichier en mode "append"
- with open(file_name,'a') as myfile:
- w = csv.writer(myfile, delimiter=';', quotechar='"', lineterminator='\n')
- w.writerow(new_line)
- def mod_line(line_id, new_line,file_name):
- """remplace la ligne d'indice line_id par new_line"""
- #on lit le fichier en mémoire
- with open(file_name,'r') as myfile:
- r = csv.reader(myfile, delimiter=';', quotechar='"', lineterminator='\n')
- lines=[l for l in r]
- lines[line_id]=new_line
- # puis on le modifie (toujours en mémoire), avant d'en réécrire toutes les lignes.
- with open(file_name,'w') as myfile:
- w = csv.writer(myfile, delimiter=';', quotechar='"', lineterminator='\n')
- w.writerows(lines)
- def del_line(line_id,file_name):
- """supprime la ligne d'indice line_id"""
- # on lit le fichier en mémoire
- with open(file_name,'r') as myfile:
- r = csv.reader(myfile, delimiter=';', quotechar='"', lineterminator='\n')
- lines=[l for l in r]
- lines.pop(line_id)
- # puis on le modifie (toujours en mémoire), avant d'en réécrire toutes les lignes.
- with open(file_name,'w') as myfile:
- w = csv.writer(myfile, delimiter=';', quotechar='"', lineterminator='\n')
- w.writerows(lines)
- ##fonctions
- def est_inclus(str1, str2):
- """True si str1 est inclus dans str2, False sinon"""
- diff = len(str2) - len(str1)
- if diff < 0:
- return False
- elif diff == 0:
- return (str1 == str2)
- elif diff > 0:
- return(est_inclus(str1,str2[1:]) or est_inclus(str1,str2[:-1]))
- def est_dans(elem_candidat,list):
- """True si elem_candidat est dans list, False sinon"""
- reponse = False
- for elem in list:
- if elem == elem_candidat:
- reponse = True
- break
- return reponse
- def reponse_recherche(criteres, file_name, liste_de_var):
- """Renvoie les résultats de la recherche"""
- "Liste dont les éléments sont de la forme [[val1, ... , val25], line_id]"
- Lindiv_et_nligne = []
- with open(file_name,'r') as myfile:
- reader = csv.reader(myfile, delimiter=';', quotechar='"', lineterminator='\n')
- lines=[l for l in reader]
- for i in range(1,len(lines)): #on commence à 1 pour écarter la ligne des intitulés de variables
- for j in range(len(liste_de_var)): #j comptera presque le nombre de critères remplis
- if not(est_inclus(criteres[j],lines[i][j])) and (criteres[j] != ""): #(match critère ou critère inactif)
- j = 0
- break
- if j == len(liste_de_var) - 1:
- Lindiv_et_nligne.append([lines[i],i])
- return Lindiv_et_nligne
- def pop_up_confirmer():
- """renvoie True si l'utilisateur clique sur 'OK', False sinon"""
- return messagebox.askokcancel("Demande de confirmation", "Êtes-vous sûr de vouloir continuer ?")
- def est_float(s):
- """Verifier qu'un string est un float ou est vide"""
- if s == "":
- return True
- else:
- try:
- float(s)
- return True
- except Exception:
- return False
- def est_entier(s):
- """Verifier qu'un string est un entier ou est vide"""
- if s == "":
- return True
- else:
- try:
- int(s)
- return True
- except Exception:
- return False
- def est_date(d):
- """Verifier qu'un string est soit vide soit un date sous la forme jour/mois/annee"""
- if d == "":
- return True
- else:
- try:
- datetime.strptime(d, '%d/%m/%Y')
- return True
- except Exception:
- return False
- def controle_type(indiv, liste_de_var):
- """vérifie la cohérence des valeurs de l'individu 'indiv' conformément à la liste de variables 'liste_var'"""
- Erreurs=[] #liste de booléens : Erreurs[i] vaut True s'il y a une erreur de saisie sur indiv[i], False sinon.
- dates_inversees = False #vaut True si la date de fin est antérieure à la date de début
- #on teste toutes les variables suivant leur type :
- for i in range(len(liste_de_var)):
- if est_dans(liste_de_var[i][1], ["str", "ld"]):
- Erreurs.append(False)
- elif liste_de_var[i][1]=="int":
- Erreurs.append(not(est_entier(indiv[i])))
- elif liste_de_var[i][2] == "float":
- Erreurs.append(not(est_float(indiv[i])))
- elif liste_de_var[i][1]=="d":
- Erreurs.append(not(est_date(indiv[i])))
- if liste_de_var[i][2]=="dd":
- date_debut=indiv[i]
- elif liste_de_var[i][2]=="df":
- date_fin=indiv[i]
- #on teste ensuite si la date de début est bien antérieure à la date de fin
- try:
- dates_inversees = datetime.strptime(date_debut, "%d/%m/%Y") > datetime.strptime(date_fin, "%d/%m/%Y")
- except ValueError:
- pass
- return (Erreurs,dates_inversees)
- def controle_est_vide(indiv, liste_de_var):
- """vérifie que les variables importantes ne sont pas vides"""
- est_vide = [] #est_vide[i] = True si indiv[i] = "" (champ laissé vide)
- for i in range(len(liste_de_var)):
- if liste_de_var[i][-1]:
- est_vide.append(indiv[i] == "")
- elif not(liste_de_var[i][-1]):
- est_vide.append(False) #on considère que pour les variables non importantes, laisser vide leurs champs respectifs n'est pas une erreur
- return est_vide
- ##exécution
- f = Menu_principal()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement