Salut,
Il serait préférable de créer une nouvelle discussion et de montrer un peu ce que vous avez fait car la boucle de "scrutation" de votre programme, sans voir à quoi ça ressemble...
- W
C'est bien simple, j'ai utilisé une boucle while infinie avec un sleep pour lister le contenu du répertoire périodiquement.
Évidemment dès que la boucle tourne je ne peux plus agir sur l'interface...
Bref, je cherche comment surveiller ce qui se passe niveau clic de bouton et autres manips clavier et souris.
Dommage d'utiliser une boucle while infinie alors qu'on peut le faire sans (avec les différentes bibliothèques mentionnées)... mais pour que ça marche sans bloquer l'interface vous avez la possibilité de la pousser dans un thread séparé.
Vous pouvez aussi revoir la séquence: on sélectionne un élève, ça attend que la photo arrive dans le répertoire en remplaçant le while infini par une fonction lancée par le GUI qui regarde le contenu du répertoire et se re-soumet elle même tant qu'il est vide.
A vous de choisir ce qui vous convient le mieux (et ouvrez un tuto. pour apprendre les bases de la programmation de votre GUI car ils sont là pour expliquer comment faire).
- W
Comme dis par Wiz, le threading te permettra de faire ce que tu demandes !
Code:
1
2
3
4
5
6
7
8
9
10 import threading, time def test(): while 1: print('Bye\n') time.sleep(1) threading.Thread(target=test,daemon=True).start() while 1: print('Hello\n') time.sleep(1)
Je vais essayer ça.
J'avais essayé d'utiliser after, mais ça me renvoie une erreur que je ne comprends pas : free variable 'before' referenced before assignment in enclosing scop.
J'appelle la première fonction avec l'appui sur le bouton de démarrage de la surveillance :
C'est la ligne added = [f for f in after if not f in before] qui ne lui plait pas apparemment...Code:
1
2
3
4
5
6
7
8
9
10
11 def surveiller_rep(): before = dict ((f, None) for f in os.listdir (RepertoireASurv)) Photoscol.after(1000,surveiller_rep_boucle) def surveiller_rep_boucle(): after = dict ((f, None) for f in os.listdir (RepertoireASurv)) added = [f for f in after if not f in before] removed = [f for f in before if not f in after] if added: print("Added: ", ", ".join (added)) before = after Photoscol.after(1000,surveiller_rep_boucle)
Je viens de comprendre : il faut redéclarer les variables after et before en global dans les fonctions ?!
Problème, au bout d'un moment ca plante avec cette erreur : maximum recursion depth exceeded while pickling an object...
"pickler" des objets, c'est quelque chose que fait "automatiquement" le multiprocessing et il n'y en a pas de trace dans le code posté.
Après, je ne comprends pas pourquoi vous comparez le contenu du répertoire avant/après plutôt que de le dédier à l'arrivée d'une image qu'on déplace après avoir été traitée. Le code serait plus simple et les éventuels point de reprise aussi.
- W
J'ignore totalement comment détecter l'arrivée d'un fichier, sinon en comparant le contenu du répertoire entre un instant T et un instant T+1...
Si le répertoire est toujours vide sauf lorsqu'il y a une image à traiter, on fera toujours la différence côté contenu (rien vs quelque chose que le traitement supprime).
Mais plus besoin de se trimbaler la liste des fichiers existants d'une itération à l'autre (cette liste étant vide...)
- W
Je ne veux pax déplacer les fichiers, simplement les renommer sur place.
Le répertoire est créé lorsque je lance la session de prise de vue depuis le logiciel photo. Ce dernier n'est pas capable de m'afficher en simultané 2 répertoires d'images différents et ce ne serait pas pratique de toute façon.
Je veux "simplement" choisir ce répertoire dans mon appli avant de lancer la surveillance en appuyant sur un bouton.
Arrêt de la surveillance et du renommage quand je veux par appui d'un autre bouton.
Les renommer sur place ou les renommer ailleurs, c'est un peu la même chose - tant que çà reste sur le même disque physique et que les images arrivent dans un répertoire connu...
L'avantage est que vous n'avez pas à trier un gros tas par nom ou date de création (que ce soit en le faisant vous même ou en le faisant faire par le système): il y a ou pas des fichiers à traiter.
En plus on a une indication, lorsqu'on démarre l'application, que quelque chose s'est mal passé si on y trouve quelque chose (puisqu'il devrait être vide). Et éventuellement la possibilité de traiter intelligemment les collisions de nommage.
Cerises sur le gâteau, moins de code: c'est moins de cas de figures à identifier côté plan de tests et de tests à faire.
- W
Je ne peux pas les déplacer, sinon le logiciel photo ne les verra plus et je ne pourrai pas les visualiser en live. C'est le but premier de la prise de vue connectée : contrôler rapidement sur un grand écran ce qu'on fait ;)
hello,
plutôt que de faire une boucle pour balayer le répertoire pour voir si quelque chose est arrivé il serait plus judicieux d'utiliser les événements. Pour faire ceci sous windows utiliser FindFirstChangeNotification (message #6 de LeNarvalo) . En utilisant PyQt comme GUI il y a une classe qui fait cela QFileSystemWatcher (exemple ici). Pour éviter une boucle on peut aussi utiliser un timer.
Ami calmant, J.P
Il y a quand même une boucle infinie qui bloque le GUI...
Et voilà. On pense être arrivé au bout et on se rend compte qu'on pourrait faire mieux. Et on peut toujours faire mieux...
Déjà qui dit "bouton" dit "ihm". Ca c'est incontournable donc tu ne pourras pas le contourner.
L'avantage de l'IHM c'est qu'elle gère l'évènementiel (elle détecte toute seule l'action sur ses widgets) et toi tu n'as qu'à programmer le "quoi faire quand telle action". Python possède une ihm minimaliste Tkinter donc tu peux t'y lancer. Et ensuite si ça t'intéresse alors PyQt (que j'ai déjà citée et que jurassic pork mentionne aussi) et qui fait partie des musts dans ce domaine.
Un dossier étant avant-tout un fichier, il possède tous les attributs d'un fichier. Notamment un "état" qui est récupérable par os.stat() et qui te donne plein d'infos dont sa taille, la date de dernière modif etc. Si par exemple cette date de dernière modif change entre T et T+1 peut-être que c'est un signe...
Je tourne en rond : j'ai fait une IHM avec Tkinter.
Le problème est simplement que si je veux que l'appui sur un bouton lance un scan périodique d'un répertoire, une boucle avec un sleep fige l'IHM...
Donc en clair : comment faire tourner périodiquement os.stat() que tu cites tout en pouvant toujours agir sur l'IHM pour lui dire simplement "arrêtes de pédaler, je vais changer de répertoire" ?
Parce qu'en parallèle je charge dans une liste le fichier des élèves de la classe en cours de prise de vue et le but est de renommer les fichiers qui arrivent avec le nom sélectionné dans la liste.
J'ai trouvé sur le net une bout de code qui fait ce que je veux avec un thread, mais je n'y comprends rien :oops:
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 from threading import Thread from time import sleep from tkinter import Button, Label, Tk i=1 class App(Tk): def __init__(self): Tk.__init__(self) self.label = Label(self, text="Stopped.") self.label.pack() self.play_button = Button(self, text="Play", command=self.play) self.play_button.pack(side="left", padx=2, pady=2) self.stop_button = Button(self, text="Stop", command=self.stop) self.stop_button.pack(side="left", padx=2, pady=2) self._thread, self._pause, self._stop = None, False, True i=1 def action(self): global i while 1: i=i+1 if self._stop: break while self._pause: self.label["text"] = "Pause... (count: {})".format(i) sleep(0.1) self.label["text"] = "Playing... (count: {})".format(i) sleep(0.1) self.label["text"] = "Stopped." def play(self): if self._thread is None: self._stop = False self._thread = Thread(target=self.action) self._thread.start() self._pause = False self.play_button.configure(text="Pause", command=self.pause) def pause(self): self._pause = True self.play_button.configure(text="Play", command=self.play) def stop(self): if self._thread is not None: self._thread, self._pause, self._stop = None, False, True self.play_button.configure(text="Play", command=self.play) App().mainloop()
En fait, quand on code GUI il faut totalement tout repenser. Car la GUI c'est la boucle infinie. Et cette boucle réagit selon ce que l'utilisateur fait dans la GUI (il clique dans un menu, il rentre un texte dans un champ de saisie, il coche/décoche une case) etc. Bien évidemment il ne faut alors pas lancer sa propre boucle infinie dans la GUI sinon la GUI ne reprend plus la main.
Bon je connais pas assez Tkinter vu que je suis parti direct dans Qt mais justement Qt possède un objet "QTimer" qui peut lancer une action à intervalles périodiques. A mon avis Tkinter devrait avoir un truc analogue.
Petite question en lien avec la demande du PO :
Pourquoi j'ai ce résultat ave ce bout de code :
Resultat :Code:
1
2
3
4
5 new_path_contents = dict((f,os.stat(f).st_mtime) for f in os.listdir(path_to_watch) for f in new_path_contents: if "ZZ" in f or "1.png" in f: print(f, new_path_contents[f]) print(os.stat(f))
C'est fou, ça, non ?Code:
1
2 ZZZZ.png 1631015804.9225547 os.stat_result(st_mode=33206, st_ino=56576470318895521, st_dev=136258105, st_nlink=1, st_uid=0, st_gid=0, st_size=7175849, st_atime=1631015804, st_mtime=1629055024, st_ctime=1631015804)
Je lui demande son st_mtime il me renvoit son st_atime.
Ce doit la méthode After, mais le pb que je rencontre alors c'est l'appel en boucle de la variable stockant la liste des fichiers...
avec tkinter il y a moyen d'utiliser des événements personnalisés et avec le module python watchdog on peut surveiller des répertoires. Voir exemple ici
voici ce que donne ce code par exemple :
Pièce jointe 604490