Voila, je te joins mon logiciel.
c'est le fichier MKVExtractorGui.py qui nous concerne je pense voir peut etre MKVExtractorGuiUI.py...
merci à toi
Voila, je te joins mon logiciel.
c'est le fichier MKVExtractorGui.py qui nous concerne je pense voir peut etre MKVExtractorGuiUI.py...
merci à toi
Je me doutais d'un truc comme ça: closeEvent est une méthode de QWidget et non de QObject! Ton closeEvent n'est ici qu'une méthode parmi d'autres, et il n'y a pas de raison que la fermeture d'une fenêtre la solicite automatiquement.
En fait, on se débrouille pour que les fenêtres sous-classent QWidget (fenêtre simple sans menu ni barre d'outil) ou QMainWindow (fenêtre complète). De ce fait, on peut en surcharger facilement les méthodes pour changer certains comportements. En plus de closeEvent, il y en a beaucoup d'autres intéressants comme keyPressEvent qui permet de récupérer toutes les touches adressées à la fenêtre. Il y a aussi tout ce qui permet de piloter la souris, etc...
Tu me parles de la class ?
Si oui j'ai essayé de passer via QWidget et pas de changement.
Code : Sélectionner tout - Visualiser dans une fenêtre à part class MKVExtractorGui(QObject):
Ou est-ce au niveau de la creation de la gui ?
il faut créer une qwidget et non un qmainwindow ?
Car en effet ce que tu expliques donne envie
Vis à vis de closeEvent, tu peux prendre QWidget ou QMainWindow (qui hérite de QWidget).
Ainsi, tu remplaces:
Par:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 class MKVExtractorGui(QObject): def __init__(self, parent=None): """Fonction d'initialisation appellée au demarrage.""" super(MKVExtractorGui, self).__init__(parent) self.mainWindow = QMainWindow()
La ligne "self.mainWindow = QMainWindow()" est supprimée. Tu remplaces donc automatiquement tous les "self.mainWindow." par "self.". J'espère qu'il n'y aura pas d'effet de bord (garde une sauvegarde avant modif!). Je ne peux pas essayer: je n'ai pas "VWidget".
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4 class MKVExtractorGui(QMainWindow): def __init__(self, parent=None): """Fonction d'initialisation appellée au demarrage.""" super(MKVExtractorGui, self).__init__(parent)
Alors, closeEvent sera de nouveau la méthode de QMainWindows surchargée par toi pour en modifier son contenu.
Apres quelques tests rapides, tout semble fonctionner comme il faut et la fonction est bien appelée lors de la fermeture
merci beaucoup !
Je reviens vers ce systeme car je voudrais aller plus loin dans son systeme d'arret.
Petites soucis :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 def run(self): """Fonction éxucant du travail en arriere plan pour ne pas bloquer la GUI.""" try: reply = subprocess.Popen(Configs["CmdWorkInProgress"], universal_newlines=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) # Execute la commande en fond except (IOError, OSError) as exc: self.print(self.tr("\nSubprocess ERROR: {}").format(exc)) return old_text = "" # Variable anti doublon while 1: # Boucle infinie attendant un break if self.stop: reply.kill() break # arrêt anticipé demandé text = reply.stdout.readline()[:-1] # Récupération du retour de la commande if type(text) != str or text == '' and reply.poll() != None: # Terminé ! break else: self.info2.emit(text) # Envoie de la valeur à la fonction de retour d'info self.fini.emit(self.stop) # Signal de fin envoyant False en cas d'arret normal et True en cas d'arret forcé @pyqtSlot(bool) def stop(self, etat): """Fonction lancée quand le travail se termine.""" if self.WorkInProgressVar != None and self.WorkInProgressVar.isRunning(): self.WorkInProgressVar.terminate()
- lorsque j'arrete ainsi, la commande se stoppe mais n'est pas vraiment killé mais le processus reste en mode zombie.
J'ai testé :
mais pas de changement
Code : Sélectionner tout - Visualiser dans une fenêtre à part os.killpg(reply.pid, signal.SIGKILL)
- Mon autre soucis n'est pas en lien avec ca mais avec :
j'ai le droit au bout d'un moment à un plantage :
Code : Sélectionner tout - Visualiser dans une fenêtre à part text = reply.stdout.readline()[:-1] # Récupération du retour de la commande
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108 Fatal Python error: Cannot recover from stack overflow. Thread 0x00007f60f7a7a700: File "MKVExtractorGui.py", line 1029 in run Current thread 0x00007f610fdd6740: File "<frozen importlib._bootstrap>", line 1032 in get_data File "<frozen importlib._bootstrap>", line 954 in get_code File "<frozen importlib._bootstrap>", line 853 in _load_module File "<frozen importlib._bootstrap>", line 560 in module_for_loader_wrapper File "<frozen importlib._bootstrap>", line 1003 in load_module File "<frozen importlib._bootstrap>", line 1022 in load_module File "<frozen importlib._bootstrap>", line 584 in _check_name_wrapper File "<frozen importlib._bootstrap>", line 1532 in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 1565 in _find_and_load File "<frozen importlib._bootstrap>", line 313 in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 1512 in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 1565 in _find_and_load File "/usr/lib/python3/dist-packages/apport/report.py", line 15 in <module> File "<frozen importlib._bootstrap>", line 313 in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 868 in _load_module File "<frozen importlib._bootstrap>", line 560 in module_for_loader_wrapper File "<frozen importlib._bootstrap>", line 1003 in load_module File "<frozen importlib._bootstrap>", line 1022 in load_module File "<frozen importlib._bootstrap>", line 584 in _check_name_wrapper File "<frozen importlib._bootstrap>", line 1532 in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 1565 in _find_and_load File "/usr/lib/python3/dist-packages/apport/__init__.py", line 5 in <module> File "<frozen importlib._bootstrap>", line 313 in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 868 in _load_module File "<frozen importlib._bootstrap>", line 560 in module_for_loader_wrapper File "<frozen importlib._bootstrap>", line 1003 in load_module File "<frozen importlib._bootstrap>", line 1022 in load_module File "<frozen importlib._bootstrap>", line 584 in _check_name_wrapper File "<frozen importlib._bootstrap>", line 1532 in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 1565 in _find_and_load File "<frozen importlib._bootstrap>", line 313 in _call_with_frames_removed File "<frozen importlib._bootstrap>", line 1512 in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 1565 in _find_and_load File "/usr/lib/python3/dist-packages/apport_python_hook.py", line 64 in apport_excepthook File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo File "MKVExtractorGui.py", line 934 in ReplyInfo ... Abandon (core dumped)
Kubuntu 13.04 64bits
Salut,
La documentation de subprocess ne recommande pas .stdout.readline mais .communicate pour éviter des pbs de deadlock.
Pourquoi ne pas commencer par la?
Une autre piste est "/usr/lib/python3/dist-packages/apport_python_hook.py".
Ca a l'air de planter mais son objet est de générer un post-mortem, il y a peut être des pistes a exploiter dans les informations que ça a capture.
Pas facile de trouver une solution a un problème qu'on ne peut pas reproduire.
De plus votre code n'est pas facile a comprendre.
A vue de nez, j'ai l'impression que vous vous compliquez bien la vie pour pas grand chose. Ce n'est qu'une impression, il faudrait que je teste pour les conforter et j'ai d'autres chats a fouetter.
- W
Pauvres chats
Je viens de tester et de bien relire :
Si je comprends bien, il me renvoie toutes les infos d'un bloc et non au fur et à mesure.Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate.
Du coup la récupération de l'info bloque ma boucle.
Mais vu mon niveau j'ai peut être raté un truc...
J'ai trouvé ça sur plusieurs sites :
Il semble que le retour soit un peut trop lourd et que si je passe par un fichier ca ne plante pas. Je continue mes recherches et testsQue ça soit avec os, popen2 ou subprocess, lorsque l'exécutable doit fonctionner en étant alimenté régulièrement en données et/ou doit fournir un flux de résultats, il faut alors directement manipuler les pipes et utiliser leurs méthodes write(), flush(), readline()…
Ouais il y a un problème de compréhension entre nous alors...
Donc j'ai bien compris la doc et ce que tu me proposes n'est pas du tout adapté à ma demande puisque je veux récupérer les infos au fur et à mesure pour les envoyer à une autre fonction.
D'où l’intérêt d'utiliser une boucle....
Il est clair que j'ai du mal avec python pour le moment, mais quitte à prendre le temps de me répondre, toi qui a tellement de chats à fouetter, autant que ce soit constructif et que ça me permettre de combler mes lacunes, non ?
Je suis d'ailleurs étonné que mon système de débutant ne soit pas compréhensible par un expert.
Pour info, en passant par un fichier temporaire, il semble en effet que tout fonctionne bien.
Votre système n'est pas une construction de débutant.
Le GUI est Qt, les threads et Popen sont des fonctionnalités du système d'exploitation. Python n'est que langage de programmation qui permet d'y accéder facilement. Il faut du temps pour maîtriser ces bêtes la.Il est clair que j'ai du mal avec python pour le moment, mais quitte à prendre le temps de me répondre, toi qui a tellement de chats à fouetter, autant que ce soit constructif et que ça me permettre de combler mes lacunes, non ?
A vous de prendre le temps d'apprendre pour combler vos lacunes.
- W
Comme les chats sont partis.
On redirige stdout vers un PIPE mais les primitives de Python .communicate() and Co ne reviennent qu’après avoir vu EOF.
Pas top pour réaliser: "je veux récupérer les infos au fur et à mesure".
Lire au fur et a mesure suppose une sorte de pooling via select pour savoir ce qui est arrive (ou pas) sur le file descriptor du PIPE.
Ça se code mais c'est OS dépendant et pour l'interfacer avec Qt, il faut se farcir toute la plomberie: beurk.
Qui plus est Qt est un framework pour le programmeur C++, tout comme Python et sa "standard library" est un framework pour le programmeur Python. Le module subprocess de Python dans le monde Qt est realise par classe QProcess.
Comme Qt est "cohérent", ils ont déjà les tuyaux prêt a l'emploi.
In fine, ça se code en quelque lignes ou il n'y a pas beaucoup de Python excepte "lambda" que j'utilise: c'est plus court que de
sous classer le widget.
"emulate_command.py random" est un petit programme qui expédie un nombre aléatoire de lignes sur (son) stdout en attendant un peu histoire de.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import sys from PyQt4.QtCore import QProcess, QObject, SIGNAL from PyQt4.QtGui import QApplication, QTextEdit def has_data(display, process): data = process.readAllStandardOutput() display.append('**' + str(data)) app = QApplication(sys.argv) display = QTextEdit() display.show() process = QProcess() QObject.connect(process, SIGNAL("readyReadStandardOutput()"), lambda diplay=display, process=process: has_data(display, process)) QObject.connect(process, SIGNAL("finished(int)"), lambda sts, display=display: display.append('*DONE*')) process.start('py -3.3 emulate_command.py random') app.exec_()
In fine, le thread qui ne faisant que passe-plat entre le widget Qt et la sortie de la commande a été vire.
Mais bon, il faut prendre le temps de lire et de comprendre.
- W
Bonsoir,
En effet... c'est légèrement plus simple tout ça :p
Merci bien pour ce bon exemple !
Apres dissection du code je pense l'avoir plutôt pas mal compris et adapté (j'ai adapté la récupération de valeur dont j'extrait un pourcentage que j'envoie a une progressBar). J'arrive simplement à l’arrêter.
Il me reste plus qu'a essayer d'adapter tout ca comme il faut
EDIT : Je rencontre encore un soucis (pour changer...) :
J'execute des programme s qui envoient les retours dans le StandardError, j'arrive à récuperer les retours mais ils sont pleins de \r et de \n.
J'ai essayé de virer les \r via replace() et une expression re, ca en supprime une partie mais en reste toujours...
Et aucun \n n'est supprimé...
Je ne comprends pas trop pourquoi il en reste...
Du coup ma question est : comment réussir à virer ces infos ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 ==> WRN0C0: First Block for video track #1 in Cluster at 1952150190 is not a keyframe\r\n\rWRN0C0: First Block for video track #1 in Cluster at 1954549890 is not a keyframe\r\n\rWRN0C0: First Block for video track #1 in Cluster at 1955480773 is not a keyframe\r\n <== ==> \r\r <== ==> ...\r\r <==
et comment faire pour faire interpréter les \n ?
Il ne me manque plus que ça pour finaliser le systeme
Il est clair, que c'est plus simple dans la mise en place.
Salut,
Alors, cote lacunes tu avais déjà la programmation système, réseau, Qt,... j'oubliais Python
Il faut juste muscler la ligne:
avec:
Code : Sélectionner tout - Visualiser dans une fenêtre à part display.append('**' + str(data))
.splitlines sait déjà traiter les fins de lignes sur Windows et Linux.
Code : Sélectionner tout - Visualiser dans une fenêtre à part self.append('**' + ''.join(bytes(data).decode('utf-8').splitlines()))
"re" est super mais on le garde pour les cas désespérés...
- W
PS: Python est un bon langage pour apprendre a programmer quand on débute. Mais c'est loin d’être un langage de débutant: il faut vraiment savoir programmer pour l’apprécier et faire des trucs oses avec.
ça ne règle que partiellement le problème.
Tous les \r ont disparu mais les sauts de lignes ne se font pas :
au lieu de :
Code : Sélectionner tout - Visualiser dans une fenêtre à part ==> WRN0C0: First Block for video track #1 in Cluster at 1949746207 is not a keyframeWRN0C0: First Block for video track #1 in Cluster at 1951251136 is not a keyframeWRN0C0: First Block for video track #1 in Cluster at 1952150190 is not a keyframeWRN0C0: First Block for video track #1 in Cluster at 1954549890 is not a keyframeWRN0C0: First Block for video track #1 in Cluster at 1955480773 is not a keyframe..... <==
Et sans splitlines(), les sauts de lignes sont ok mais c'est le bazar dans les retours :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 ==> WRN0C0: First Block for video track #1 in Cluster at 1949746207 is not a keyframe WRN0C0: First Block for video track #1 in Cluster at 1951251136 is not a keyframe WRN0C0: First Block for video track #1 in Cluster at 1952150190 is not a keyframe WRN0C0: First Block for video track #1 in Cluster at 1954549890 is not a keyframe WRN0C0: First Block for video track #1 in Cluster at 1955480773 is not a keyframe..... <==
Toutes les lignes ne sont pas complètes.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 ==> .. <== . <== ==> ... <==
c'est étrange le nombre d'info qu'il récupère d'un coup sur une même ligne, comme si il n'avait pas eu le temps de retourner à la ligne...
Si on vire les fins de lignes, ils sont plus la...ous les \r ont disparu mais les sauts de lignes ne se font pas :
Normal non?
Ce qui surprend, c'est l'effet "buffered" sur les PIPE: en fait, il reçoit les lignes par paquets. Le programme qui ecrit sur stdout n'a pas de bonnes raison de faire des .flush.
Si on veut que .append les remette, il faut lui un truc comme:
- W
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3 for line in bytes(data).decode('utf-8').splitlines(): if line: self.append(line)
En ajoutant des vérifications pour éviter l'envoie d'info doublon, tout est parfait !
Merci pour le temps que tu m'as consacré et les réponses de qualités que tu m'as apporté.
Bonne nuit.
Bonsoir je reviens dans ce topic.
J'ai adapté le code que tu m'as indiqué et il marche parfaitement pour tous mes commandes à exécuter mais je rencontre un soucis pour lancer ces commandes les unes à la suite des autres sans geler mon interface.
J'ai testé des boucles qui teste l’état du QProcess et attente de la fin du travail pour passer à la suite, j'ai testé la commande waitForFinished de QProcess (mais c'était bien indiqué que cela ferait friser la GUI), j'ai testé de lancer les qprocess depuis une boucle... et je ne sais plus quoi encore...
Bien évidemment le soucis est toujours le même, à savoir que oui ça fonctionne bien comme il faut, mais ça bloque la gui...
Je pourrais lancé toutes mes commandes en parallèles via startDetached mais il serait impossible d'afficher la progression et ça ne serait pas une bonne idée pour les petites configs.
Pourrais tu m'indiquer une direction à prendre pour régler ce soucis ?
merci et bonne soirée.
Vous avez un bloqueur de publicités installé.
Le Club Developpez.com n'affiche que des publicités IT, discrètes et non intrusives.
Afin que nous puissions continuer à vous fournir gratuitement du contenu de qualité, merci de nous soutenir en désactivant votre bloqueur de publicités sur Developpez.com.
Partager