Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Python/curses et getch pendant raffraichissement de la fenêtre

3 réponses
Avatar
Doug713705
Bonjour,

Je suis en train de coder une petite application avec python/curses et
j'aimerai la rendre plus interactive et proposer à l'utilisateur de
pouvoir, grace à l'appui sur une touche, naviguer entre les différents
panneaux et fenêtres qui composent l'application.

Jusque là tout va bien.

Sauf que j'aimerai aussi _dans le même temps_ pouvoir continuer à mettre
à jour les différentes fenètres (l'application reçoit en continu des
données via le web et les affiche à l'écran) _y compris_ lorsque
l'application est en attente de la saisie de l'utilisateur.

J'ai bien tenté d'utiliser la saisie non bloquante avec curses.nodelay()
et de la combiner avec curses.cbreak() pour ne pas avoir à taper sur
entrée à la suite de la saisie mais rien n'y fait.

Soit l'application bloque en attente de la saisie de l'utilisateur, soit
il faut taper entrée pour valider et plus souvent les deux à la fois et
lorsque j'utilise nodelay pour obtenir la saisie non bloquante,
l'application plante sur une erreur curses (dont les messages sont pour
le moins succints) que je n'arrive pas à récupérer par try/except.

J'ai bien compris que l'erreur était dûe à l'absence de saisie qui fait
que curses renvoie -1 mais je ne comprends pas pourquoi je ne peux pas
l'attraper (mais ceci est un autre problème et ce n'est pas ce qui me
préoccupe ici).

Il y a probablement quelque chose que je n'ai pas compris dans
l'utilisation de cbreak et de nodelay mais je n'arrive pas à mettre le
doigt dessus (les docs que je trouve sont assez peu explicites sur ces
points et sans exemples) et j'en suis à me demander si ce que j'essaie
de faire est possible.

J'avoue avoir même penser à rendre l'application multi-threadée (un
thread pour le "moteur" et un autre pour l'interface utilisateur curses)
mais je reste dubitatif quand au succès de cette méthode.

Est-ce que quelqu'un ici aurait une idée de comment rendre cette
application plus interactive ?

Ou, si ce n'est pas possible, de me le dire afin que j'arrête de perdre
du temps sur ce problème qui n'en est peut-être pas un ;-)

Merci d'avance pour vos réponses.

--
Bourlinguer... errer,
Errer humanum est.
-- H.F. Thiéfaine, Errer humanum est

3 réponses

Avatar
Nicolas
Bonjour,

Le 02/10/2014 07:45, Doug713705 a écrit :
Bonjour,

Je suis en train de coder une petite application avec python/curses et
j'aimerai la rendre plus interactive et proposer à l'utilisateur de
pouvoir, grace à l'appui sur une touche, naviguer entre les différents
panneaux et fenêtres qui composent l'application.

Jusque là tout va bien.

Sauf que j'aimerai aussi _dans le même temps_ pouvoir continuer à mettre
à jour les différentes fenètres (l'application reçoit en continu des
données via le web et les affiche à l'écran) _y compris_ lorsque
l'application est en attente de la saisie de l'utilisateur.

J'ai bien tenté d'utiliser la saisie non bloquante avec curses.nodelay()
et de la combiner avec curses.cbreak() pour ne pas avoir à taper sur
entrée à la suite de la saisie mais rien n'y fait.

Soit l'application bloque en attente de la saisie de l'utilisateur, soit
il faut taper entrée pour valider et plus souvent les deux à la fois et
lorsque j'utilise nodelay pour obtenir la saisie non bloquante,
l'application plante sur une erreur curses (dont les messages sont pour
le moins succints) que je n'arrive pas à récupérer par try/except.

J'ai bien compris que l'erreur était dûe à l'absence de saisie qui fait
que curses renvoie -1 mais je ne comprends pas pourquoi je ne peux pas
l'attraper (mais ceci est un autre problème et ce n'est pas ce qui me
préoccupe ici).

Il y a probablement quelque chose que je n'ai pas compris dans
l'utilisation de cbreak et de nodelay mais je n'arrive pas à mettre le
doigt dessus (les docs que je trouve sont assez peu explicites sur ces
points et sans exemples) et j'en suis à me demander si ce que j'essaie
de faire est possible.

J'avoue avoir même penser à rendre l'application multi-threadée (un
thread pour le "moteur" et un autre pour l'interface utilisateur curses)
mais je reste dubitatif quand au succès de cette méthode.



De façon générale, un système graphique ne supporte pas de faire autre
chose que l'interface. Il faut par conséquent un et un seul thread qui
gère l'interface et un ou plusieurs threads "travailleurs" qui font le
boulot. De façon générale également, les threads "travailleurs" ont
interdiction de toucher à l'API de l'interface sous risque de faire
crasher l'application. Il faut donc mettre en place une communication
entre les threads "travailleurs" et le thread d'interface. Tous les
systèmes graphiques ont une API faite pour ça. Chaque système graphique
a sa méthode pour le faire (signaux et slots en Qt par exemple).

Est-ce que quelqu'un ici aurait une idée de comment rendre cette
application plus interactive ?

Ou, si ce n'est pas possible, de me le dire afin que j'arrête de perdre
du temps sur ce problème qui n'en est peut-être pas un ;-)



Je n'ai jamais utilisé curses. Je ne peux donc pas me prononcer.

Merci d'avance pour vos réponses.




Nicolas
Avatar
Doug713705
Le 02-10-2014, Doug713705 nous expliquait dans
fr.comp.lang.python
() :

Sauf que j'aimerai aussi _dans le même temps_ pouvoir continuer à mettre
à jour les différentes fenètres (l'application reçoit en continu des
données via le web et les affiche à l'écran) _y compris_ lorsque
l'application est en attente de la saisie de l'utilisateur.

J'ai bien tenté d'utiliser la saisie non bloquante avec curses.nodelay()
et de la combiner avec curses.cbreak() pour ne pas avoir à taper sur
entrée à la suite de la saisie mais rien n'y fait.



Après avoir tatouillé pendant un bon moment et tenté une application
multthreadée, il s'avère que curses n'aime pas trop le multithreading.
Dans ce cas, bien que tout fonctionna parfaitement, l'affichage
présentait sans raison des caractères ésothériques disséminés de manière
aléatoire.

J'ai fini par arriver à mes fins en allant chercher la saisie
utilisateur directement dans sys.stdin. Le tout a été emballé dans une
deux boucles while, une qui teste que le programme a toujours
l'autorisation de continuer son travail (histoire de se réserver une
porte de sortie) et la seconde qui teste la la disponibilité
d'informations dans sys.stdin.

Le code n'est probablement pas très propre (quoi que) mais c'est la
solution fonctionnelle la plus simple que j'ai trouvée.

--
Et leurs aéroports se transforment en bunkers
A quatre heures du matin derrière un téléphone
Quand leurs voix qui s'appellent se changent en revolvers
Et s'invitent à calter en se gueulant come on
-- H.F. Thiéfaine, Les dingues et le paumés
Avatar
Doug713705
Le 03-10-2014, Nicolas nous expliquait dans
fr.comp.lang.python
(<542e4500$0$21643$) :

J'avoue avoir même penser à rendre l'application multi-threadée (un
thread pour le "moteur" et un autre pour l'interface utilisateur curses)
mais je reste dubitatif quand au succès de cette méthode.



De façon générale, un système graphique ne supporte pas de faire autre
chose que l'interface. Il faut par conséquent un et un seul thread qui
gère l'interface et un ou plusieurs threads "travailleurs" qui font le
boulot. De façon générale également, les threads "travailleurs" ont
interdiction de toucher à l'API de l'interface sous risque de faire
crasher l'application. Il faut donc mettre en place une communication
entre les threads "travailleurs" et le thread d'interface. Tous les
systèmes graphiques ont une API faite pour ça. Chaque système graphique
a sa méthode pour le faire (signaux et slots en Qt par exemple).



C'est un peu ce que j'avais fait. Le travailleur était un objet dérivé
de threading.Thread et l'interface graphique un autre objet indépendant.

Le travailleur accédait à l'interface graphique au travers des méthodes
de l'objet associé et lui laissait donc le bon soin d'afficher les
données au bon moment et de raffraichier l'affichage quand nécessaire.

Cependant cela ne semblait pas suffisant et malgré tout des caractères
aléatoires sans aucun rapport avec les données traitées étaient des
temps à autres dissiminés aléatoirement sur l'écran.

Est-ce que quelqu'un ici aurait une idée de comment rendre cette
application plus interactive ?

Ou, si ce n'est pas possible, de me le dire afin que j'arrête de perdre
du temps sur ce problème qui n'en est peut-être pas un ;-)



Je n'ai jamais utilisé curses. Je ne peux donc pas me prononcer.



J'ai fini par m'en sortir avec 2 boucles while imbriquées et une lecture
de sys.stdin bien plus efficace que le getch bloquant de curses (il
existe un mode non bloquant pour curses mais ce n'était pas judicieux
dans mon cas).

Merci pour ta réponse.

--
Je me souviens de toi dans ces années obscures
Où tu te promenais avec un rat en laisse
Les cafards te disaient : l'amour vient du futur
Et te laissaient leurs croix comme on laisse une adresse
-- H.F. Thiéfaine, Une fille au rhésus négatif