Casse-tête Python : lecture d'1 fichier txt bug mais débug avec un problème tkin

Résolu/Fermé
Lecodeurhtmlcss Messages postés 76 Date d'inscription lundi 20 avril 2020 Statut Membre Dernière intervention 24 août 2022 - Modifié le 23 juil. 2021 à 11:54
yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 - 24 juil. 2021 à 20:01
Bonjour, et merci beaucoup de vous pencher sur ce problème. C'est un casse-tête j'ai l'impression !

Circonstances :
- Je crée un moteur 3D avec python Tkinter depuis pas mal de temps, avec enregistrement de fichiers
- J'ai un niveau assez moyen en python (mais pas débutant)

Problème en gros : la lecture d'un fichier ne fonctionne pas du premier coup, mais fonctionne avec la suite du script, dès qu'on ferme la fenêtre


Explication du script :

1) On crée une fenetre Tkinter, et on lance une fonction ("Activation")

2) Cette fonction "Activation" essaie de voir si il y a déjà un monde ouvert sauvegardé :
..............->Si oui : juste définir le chemin ("pathmonde")

..............->Si non : On regarde si quelqu'un a créé un monde temporaire, non sauvegardé :

.........................-> Si non : on le crée (en attendant de sauvegarder...), et on met les options(contenues dans un fichier txt)

.........................-> Si oui : on demande si on continue ou on supprime ce pauvre fichier
........................................-(on ne s'intéresse pas au cas continuer pour l'instant ;)
........................................-Si on supprime, ça appelle une fonction "ecraserfichiertemporaire"
Puis elle appelle la fonction "suiteActivation"

fonction "ecraser..." :
- On supprime l'ancien fichier
- on en crée un nouveau avec les options
- on continue l'activation ("suiteactivation")

fonction "suiteactivation" :
- On retrouve le chemin des options
- on les lis et on les print.



Et là est le problème !
Dès qu'on utilise la fonction "écraser...." les options ne s'impriment pas (elles sont bien écrites dans le fichier txt).
2e problème : La suite de la fonction activation ne se fait que quand on ferme la fenetre principale... Je suppose qu'elle attend la fin du "mainloop" de la fenetre popup, alors qu'on la détruite !
Et, surprise, dès qu'on ferme la fenêtre principale... "Suiteactivation" fonctionne et imprimme les options !

A mon avis, c'est une histoire de fonction et de fenêtre à la fois...

Code : (assez long)
from tkinter import *
from tkinter import ttk
import os as o
import shutil

DirectoryPath=(o.path.abspath(__file__))[0:-27]   # On regarde où seront les fichiers...






def SuiteActivation():    #Suite
    lienoptions=o.path.normpath(o.path.join(pathmonde,"options.txt"))
    print("lien option normalisé : ",lienoptions)
    options=open(lienoptions,"r")
    pos=(options.readlines())
    print("position : ",pos)   #Et là ça marche une fois sur deux ! 
    
    #Normalement,  c'est activé le première fois quand on clique sur le bouton et la 2e fois après (fin de def activation)
    


def ecraserfichiertemporaire():           #Si on détruit le fichier temporaire (pour plus de clarté voir ci-après)
    print("fichier temporaire supprimé")
    asupprimer=o.path.join(DirectoryPath, "fichier_temporaire")
    shutil.rmtree(asupprimer) #supprimer tout le fichier
    global textelabelfichiertemporairesupprime
    textelabelfichiertemporairesupprime="Le fichier " + asupprimer + " a été supprimé"
    fenetrefichiertrouve.destroy()  # Je détruis l'ancienne fenetre

    o.mkdir("fichier_temporaire")       #On crée à nouveau un fichier temporaire
    print("fichier temporaire créé")
    global pathmonde
    pathmonde=o.path.join(DirectoryPath,"fichier_temporaire")    #On ajoute les options à ce fichier
    pathmonde=o.path.normpath(pathmonde)
    options=open(o.path.join(pathmonde,"options.txt"),"w+") #écrire les options
    options.write("pos=1,1,1\nRgd=2,356\nRhb=-0,7854")
    options.close
    
    suite=SuiteActivation()    #passer à la suite






def Activation():
    fichiermondecourant=open("mondeactuel.txt","r")
    mondecourant=fichiermondecourant.read()
    print(mondecourant)
    if mondecourant=='':
        print("pas de monde courant sauvegardé")
        fileexist=0
        try:                                            #On essaie de créer un fichier temporaire en attendant de sauvegarder
            o.mkdir("fichier_temporaire")
        except FileExistsError:             #Il y a déjà un fichier temporaire de la dernière fois !
            fileexist=1
            global fenetrefichiertrouve
            fenetrefichiertrouve = Toplevel()                     #On veut une fenetre popup
            fenetrefichiertrouve.attributes("-topmost", True)
            
            textefichiertrouve = Text(fenetrefichiertrouve, height=4, width=40)
            textefichiertrouve.pack()
            textefichiertrouve.insert(END, "Fichier non-sauvegardé trouvé.")
            boutonsupprimerfichiertrouve = Button(fenetrefichiertrouve, text="supprimer", command=lambda : ecraserfichiertemporaire())
            boutonsupprimerfichiertrouve.pack()
            boutoncontinuerfichiertrouve = Button(fenetrefichiertrouve, text="le continuer") # ce n'est pas ce qui nous intéresse
            boutoncontinuerfichiertrouve.pack()
            fenetrefichiertrouve.title("Fichier non sauvergardé trouvé")
            
            fenetrefichiertrouve.mainloop()
        
        if fileexist==0:
                print("Aucun fichier temporaire n'a existé")    #Pour la première fois qu'on utilise ou quand on supprime le fichier manuelement
                global pathmonde
                pathmonde=o.path.join(DirectoryPath,"fichier_temporaire")    #Je crée un nouveau monde avec les options
                pathmonde=o.path.normpath(pathmonde)
                options=open(o.path.join(pathmonde,"options.txt"),"w+")
                options.write("pos=1,1,1\nRgd=2,356\nRhb=-0,7854")
                options.close
        
        
        
    else:
        print("il y a un monde courant ! son nom est : ",mondecourant)
        pathmonde=o.path.join(DirectoryPath,mondecourant)
        
    suite=SuiteActivation()   #On passe à la suite !
##################################
#     /\         C'est ici que ça se joue !
#    /||\    En gros, la première fois en supprimant le fichier, SuiteActivation ne fonctionne pas
#   / '' \         Mais dès que on le fait ici (au dessus) la position marche !
#  /______\
###################################






################################### Juste du tkinter... 
fenetre = Tk()
fenetre.geometry("600x600")
label=Label(fenetre,text="Cette fenetre a été grandement simplifiée...")
label.pack()

Lancement=Activation()  ################## On lance avant le mainloop...
fenetre.mainloop()


Quel est le poblème ? Et comment régler ça (pourquoi pas une fonction avant le mainloop de la fenetre popup ?)?

Merci beaucoup pour votre attention !!!
Cordialement,
N. B.

A voir également:

6 réponses

yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 Ambassadeur 1 550
23 juil. 2021 à 12:22
bonjour,
il serait préférable que tu simplifies ton programme pour n'y garder que le minimum qui pose problème.
tu n'expliques pas comment utiliser le programme (en partant de rien) afin d'obtenir le comportement inattendu.
1
Lecodeurhtmlcss Messages postés 76 Date d'inscription lundi 20 avril 2020 Statut Membre Dernière intervention 24 août 2022 1
Modifié le 23 juil. 2021 à 12:45
En fait tout est lié, c'est le minimum que je puisse faire (de fait un truc simple marche (juste lire), mais on ne peut pas complexifier au fur et à mesure car les fonctions sont liées. ????




from tkinter import *
from tkinter import ttk
import os as o

DirectoryPath=(o.path.abspath(__file__))[0:-27]   # On regarde où seront les fichiers...




def SuiteActivation():    #Suite
    lienoptions=o.path.normpath(o.path.join(pathmonde,"options.txt"))
    print("lien option normalisé : ",lienoptions)
    options=open(lienoptions,"r")
    pos=(options.readlines())
    print("position : ",pos)   #Et là ça marche une fois sur deux ! 
    
    


def ecraserfichiertemporaire():
    #ici je détruis le fichier           
    fenetrefichiertrouve.destroy()  # Je détruis l'ancienne fenetre
    print("fichier temporaire supprimé puis créé")
    global pathmonde
    pathmonde=o.path.normpath(o.path.join(DirectoryPath,"fichier_temporaire"))
    options=open(o.path.join(pathmonde,"options.txt"),"w+") #écrire les options dans un txt
    options.write("pos=1,1,1\nRgd=2,356\nRhb=-0,7854")
    suite=SuiteActivation()    #passer à la suite




def Activation():           # ne suit plus le schéma initial car simplifié
        print("pas de monde courant sauvegardé")
        fileexist=0
        try:                                            #On essaie de créer un fichier temporaire en attendant de sauvegarder
            o.mkdir("fichier_temporaire")
        except FileExistsError:             #Il y a déjà un fichier temporaire de la dernière fois !
            fileexist=1
            global fenetrefichiertrouve
            fenetrefichiertrouve = Toplevel()                     #On veut une fenetre popup
            
            textefichiertrouve = Text(fenetrefichiertrouve, height=4, width=40)
            textefichiertrouve.pack()
            textefichiertrouve.insert(END, "Fichier non-sauvegardé trouvé.")
            boutonsupprimerfichiertrouve = Button(fenetrefichiertrouve, text="supprimer", command=lambda : ecraserfichiertemporaire())
            boutonsupprimerfichiertrouve.pack()
            fenetrefichiertrouve.title("Fichier non sauvergardé trouvé")
            
            fenetrefichiertrouve.mainloop()
        
        if fileexist==0:
            print("Aucun fichier temporaire n'a existé")    #Pour la première fois qu'on utilise ou quand on supprime le fichier manuelement
            global pathmonde
            pathmonde=o.path.normpath(o.path.join(DirectoryPath,"fichier_temporaire"))
            options=open(o.path.join(pathmonde,"options.txt"),"w+")
            options.write("pos=1,1,1\nRgd=2,356\nRhb=-0,7854")
            options.close
        
        suite=SuiteActivation()  


################################### Juste du tkinter...
fenetre = Tk()
label=Label(fenetre,text="Fenetre principale")
label.pack()
Lancement=Activation()  ################## On lance avant le mainloop...
fenetre.mainloop()





Désolé pour la non-explication ! Oui il faut juste lancer le programme 2 fois. La première il n'y aura aucun monde temporaire et normalement il ne se passera rien. C'est une fois qu'il y en a un que ça marche.
0
yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 1 550 > Lecodeurhtmlcss Messages postés 76 Date d'inscription lundi 20 avril 2020 Statut Membre Dernière intervention 24 août 2022
23 juil. 2021 à 12:48
tu n'expliques pas comment utiliser le programme (en partant de rien) afin d'obtenir le comportement inattendu.

ton programme est visiblement prévu pour un scenario bien précis, et se termine en erreur si on ne suit pas ce scenario.

n'hésite pas non plus à expliquer ce que le programme affiche dans ce scénario.
0
yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 1 550 > Lecodeurhtmlcss Messages postés 76 Date d'inscription lundi 20 avril 2020 Statut Membre Dernière intervention 24 août 2022
23 juil. 2021 à 13:07
la ligne 5 est une source d'erreur, pourquoi pas plutôt
DirectoryPath=""
?
0
yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 1 550 > yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024
23 juil. 2021 à 13:13
que faut-il faire après avoir lancé le programme?
0
Lecodeurhtmlcss Messages postés 76 Date d'inscription lundi 20 avril 2020 Statut Membre Dernière intervention 24 août 2022 1 > yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024
Modifié le 23 juil. 2021 à 22:25
(Désolé, oui forcément je sais ce que je cherche donc ça me paraît naturel... )

J'eplicite mal mon but : j'essaie de supprimer les infos pour en remettre de nouvelles, et ensuite réussir à lire ces infos depuis le fichier texte "options.txt"
Ce processus se traduit par cliquer sur "supprimer" sur la fenêtre popup - mais on voit que dans la console on n'arrive pas à récupérer les informations (juste une liste vide). En fait ce n'est que supprimer la fenêtre principale qui fait fonctionner le script après ces différentes manips.
Et j'essaie de comprendre pourquoi (et surtout de trouver un moyen de récupérer les options du fichier texte correctement sans fermer la fenetre principale.
0
Ton problème vient de l'incompréhension du déroulement de ton code, le code qui suit l'ouverture de ta toplevel ne va pas attendre que celle-ci soit fermée pour être exécuté, il le sera directement.

Il y a tellement de choses à rectifier dans ton code.
Déjà la 1ère ligne, comme dit par le voisin du dessus.

DirectoryPath=(o.path.abspath(__file__))[0:-27]
est erroné et soumis à de futurs bugs.

Déjà pourquoi mettre un alias à une lettre d'un module ayant un nom de 2 lettres ?
De plus DirectoryPath étant une constante, on l'écrit en majuscule.

Soit quelque chose comme
DIRECTORY_PATH = os.path.abspath(os.path.dirname(__file__))
qui est déjà plus limpide, ne trouves-tu pas ?
1
Lecodeurhtmlcss Messages postés 76 Date d'inscription lundi 20 avril 2020 Statut Membre Dernière intervention 24 août 2022 1
23 juil. 2021 à 22:19
Merci beaucoup, c'est vraiment mieux en effet !
0
yg_be Messages postés 23342 Date d'inscription lundi 9 juin 2008 Statut Contributeur Dernière intervention 21 novembre 2024 Ambassadeur 1 550
23 juil. 2021 à 15:51
Le soucis principal, c'est ton approche: construire un truc simple et ensuite le complexifier au fur et à mesure.
Comme si tu construisais un abri de jardin pour ensuite le transformer en immeuble à appartement. Al lieu de commencer par les fondations et la structure.
Avant de commencer, tu dois déterminer où tu veux arriver, et commencer en conséquence.
Quel que soit la source de ton soucis, il faudra immanquablement réécrire ton code en le structurant différemment.

Une des preuves de cela, c'est que, au lieu d'expliquer ce que tu attends de ton code (que nous ne pouvons pas deviner), tu nous expliques la logique de ton script, alors que nous pouvons lire le programme, malgré qu'il soit mal commenté.
1
Allez, d'autres petites choses.

Utiliser des exceptions, c'est très bien, mais il y a aussi un else et finally dans la gestion des exceptions en python, donc plutôt que faire

fileexist=0
try:
    o.mkdir("fichier_temporaire")
except FileExistsError:
    fileexist=1

if fileexist==0:
    # code


Fais simplement

try:
    o.mkdir("fichier_temporaire")
except FileExistsError:
    # code
else:
    # code



Faire
command=lambda : ecraserfichiertemporaire())
est inutile, puisque ta fonction anonyme fait exactement la même chose que la fonction d'origine, donc autant passer la référence à la fonction
ecraserfichiertemporaire
(sans parenthèses donc).

Essaie aussi de respecter les conventions en python (et bien souvent en programmation), soit le snake_case, soit le camelCase, car écrire des noms comme
textelabelfichiertemporairesupprime
n'aide pas à la lecture du code, c'est vraiment très bien de donner des noms de variables, fonctions descriptives, mais là c'est un peu trop ^^

Comme tu ne fermes pas tes fichiers, utilise à bon escient le context manager with

with open('fichier_a_lire') as f:
    content = f.read()


Essaie aussi de dissocier dans des fonctions distinctes ce qui concerne l'interface garphique et les autres choses, logique, etc.
1
Lecodeurhtmlcss Messages postés 76 Date d'inscription lundi 20 avril 2020 Statut Membre Dernière intervention 24 août 2022 1
23 juil. 2021 à 22:23
Je suis sûr que ça va régler pas mal de choses... Je vais en effet restructurer ce code et le rendre plus lisible, merci beaucoup pour ces conseils, ça fait avancer ! Il serait plus judicieux de reconsidérer l'ordre des choses... Merci beaucoup !
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Lecodeurhtmlcss Messages postés 76 Date d'inscription lundi 20 avril 2020 Statut Membre Dernière intervention 24 août 2022 1
23 juil. 2021 à 22:38
A vrai dire, le problème ressort plus si on enlève les lignes 85->89
    else:
        print("il y a un monde courant ! son nom est : ",mondecourant)
        pathmonde=o.path.join(DirectoryPath,mondecourant)
        
    suite=SuiteActivation()   !

De fait là la seule fonction qui appele "Suiteactivation" est bien celle du bouton "supprimer" de la fenetre popup. On clique, mais malheureusement a position est illisible.
0
Lecodeurhtmlcss Messages postés 76 Date d'inscription lundi 20 avril 2020 Statut Membre Dernière intervention 24 août 2022 1
23 juil. 2021 à 22:56
Vidéo explicative ici : https://drive.google.com/file/d/1WnY_2ib-23qzICMeTb1N0-GJRNiT2fO5/view?usp=sharing

C'est mieux ! Et merci de votre aide et implication !
0