Retourner aux forums || Retourner au forum Programmation.c
Programmation.c : comment realiser une GUI ?
Posté par NeoWerner () le 06 mai 2006Je suis bloqué depuis plusieurs jours sur un point de programmation que je n'arrive pas à résoudre, et malheureusement google ne m'aide pas beaucoup (enfin du moins j'arrive pas à lui demander suffisemment gentilment pour qu'il me réponde correctement).
Donc voila mon probleme :
J'ai un logiciel simple en lignes de commandes qui fait une succession de 'scanf' et 'printf' (ou equivalent) : en l'occurence ce soft est crafty (jeu d'échec) qui commence par demander notre deplacement d'une piece, puis repond si le coup est accepté et enfin repond le coup de l'IA.
Et j'aimerais faire une GUI sur ce programme. Mais voila je ne trouve pas du tout comment faire.
J'ai tenté la creation de 2 pipes (un pour les saisies, et lautre pour récupérer les donnees affichees en sortie) avec un fork et execlp pour communiquer entre mon programme et crafty, mais je suis tombé sur un probleme : le pipe de sortie ne me donne les differents textes *seulement* quand crafty est completement terminé. Or j'aimerais pouvoir recuperer les infos au fur et a mesure des saisies.
Donc si quelqu'un pouvait m'aider ca serait vraiment super.
Peut etre faut-il utiliser autre chose que les pipes ? j'ai testé avec 'popen()' (mais il limite a l'écriture *ou* la lecture, mais pas les 2 en meme temps) et j'ai le même problème :(
Peut etre que j'ai mal implementé mes pipes ?
Merci d'avance pour vos réponses.
> Lire le message (11 commentaires, moyenne: 1,5).
expect
Peut-être que tu pourrais aller voir du côté de expect,expectk et libexpect.
http://www.tcl.tk/man/expect5.31/libexpect.3.html
je ne sais pas si j'ai bien saisi ton problème, mais bon ....
Peut être que crafty n'affiche rien à cause des buffers. Tu peux vider un buffer avec fflush(stdout), ou avec un \n dans un printf().
Si jamais ton problème viens de la, une solution radicale est de désactiver la mémoire tampon pour stdout : setbuf (stdout, NULL);
Sinon, en alternative aux pipes,il existe les fifo (tubes nommés) : man mkfifo
Sinon, ca peut etre intéressant de faire une GUI dans un processus séparé (comme tu fait, quoi !) mais pourquoi ne pas tout mettre dans le meme processus ? au besoin, si tu doit faire de l'exécution concurente, les threads sont faits pour cela, c'est simple à mettre en oeuvre, et ca possède le meme espace d'addressage mémoire ; fini la communication par pipe ! (mais bonjour la synchronisation ...)
http://yolinux.com/TUTORIALS/LinuxTutorialPosixThreads.html
Bonne chance ...
Soutenez le logiciel libre, en adhérant dès maintenant à l'April
-
[^]Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....
Posté par NeoWerner () le 06/05/2006 à 21:23. (lien). Évalué à 2.1/ En fait j'ai donné crafty comme exemple, mais j'ai testé simplement avec un programme qui contenait de : 'scanf' puis 'printf' puis un second 'scanf' puis 'printf' : juste pour mes tests.
2/ pour le \n dans printf, j'ai deja testé, mais pas mieux. :(
3/ sinon les threads je connais, en effet c'est bien pratique pour faire des executions en parallele (notament des ecritures d'un coté pendant qu'il attends qu'une donnee lui parvienne). Ceci marche tres bien lorsque je fais des tests sur d'autres domaines : genre ports series ou sockets. Mais mon probleme n'est pas la.
Je vais prendre un exemple simple :
programme de test executé : printf("coucou\n"); sleep(10); printf("test\n");
dans le programme d'execution de ce dernier, je fais une boucle sur un read() et j'affiche tout ce qui arrive. Mais je ne recois le "test" comme le "coucou" seulement 10sec apres son execution (soit quand le prog de test a quitté).
Sinon tu me dis de tester en laissant tout dans le meme processus, mais comment puis-je recuperer les pointeurs de fichiers vers l'entree et la sortie du programme executé (crafty) ? (pour faire des read() et write() dessus)
4/ Sinon j'ai regardé le man du mkfifo, ca peut en effet etre une bonne solution : le principe serait de faire 2 fifo (fichiers 'virtuels') et d'ouvrir ces 2 "fichiers" dans ma GUI c'est bien ca ? ( avec un exec("fifo1 > crafty > fifo2") ) ?
merci beaucoup pour ton aide :)-
[^]Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....
Posté par Pol' uX () le 07/05/2006 à 09:33. (lien). Évalué à 2.Les fifo, c'est très puissant, je m'en suis déja servis pour télécommander des processus démonisés (enfin, surtout ils étaient temps réel). Je pense que les sockets, c'est bien aussi, pour faire cela, mais c'est plus compliqué a faire.
Quand je disais de tout mettre dans le processus, j'entendais par là réécrire un programme, avec GUI (perso j'aime bien GTK) qui fait ce que crafty fait. Vu que tu dit que crafty est simple, ca ne sera pas a priori très compliqué. En tout cas, je trouve ca plus propre.
Regarde du coté de libglade, ca peut te permettre d'adapter ton code très simplement : dans le processus crafty, tu fait un thead pour gtk_main() et un thread pour ton traitement de crafty. Tu remplace les entrées et sorties standarde par des variables ... et tu as juste à rajouter les fonctions de callback.--
Soutenez le logiciel libre, en adhérant dès maintenant à l'April-
[^]Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....
Posté par NeoWerner () le 07/05/2006 à 12:03. (lien). Évalué à 1.De retour apres plusieurs tests ;)
En fait j'ai testé avec les fifo, et jai le meme probleme. Par exemple j'ai cree un programme de test qui fait :
test.c : main() { printf("coucou"); sleep(10); printf("yo"); }
ensuite je lance le tout :
$ gcc -o test test.c
$ mkfifo ./fifotest
$ ./test > ./fifotest
et dans un autre terminal :
$ cat ./fifotest
ou
$ tail -f ./fifotest
et je recupere les donnees seulement apres les 10sec :( j'arrive pas a avoir le "coucou" avant la fin de l'execution du programme.
par contre si dans mon test.c je rajoute au debut ce que tu me disais dans ton message precedent : setbuf (stdout, NULL); ca marche super bien. mais ca implique que je modifie les sources de crafty pour rajouter juste une ligne ;) je comprends pas comment ils font les autres sans ca :p
j'en conclus donc que de base, le stdout a un buffer, et ce buffer serait peut etre recuperable dans mon code directement ?
Sinon ouai je crois que je vais finir par prendre les sources de crafty et y implementer ma GUI directement, mais si il y a des nouvelles versions de crafty c'est moins pratique.
Pour GTK je connais aussi, c'est ce que je prefere aussi ;)
merci :)-
[^]Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....
Posté par durandal () le 07/05/2006 à 16:38. (lien). Évalué à 1.Y'a déjà pas mal de programmes qui communiquent avec crafty pour faire une interface graphique, et ils n'ont pas eu besoin de modifier crafty, tu pourrais peut-être t'en inspirer : xboard, eboard, gnome-chess...
-
[^]Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....
Posté par NeoWerner () le 07/05/2006 à 17:54. (lien). Évalué à 1.je sais bien. J'ai telechargé les sources de : xboard, cboard, etc.... mais a chaques fois ya aucun commentaire (sans exagerer). C'est dommage et surtout pas tres pratique pour comprendre le code :(
j'ai essayé de lire et relire les sources où je pense que ca parle de tout ca (où il y a un fork et un exec de crafty) mais je comprends vraiment pas.-
[^]Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....
Posté par JaguarWan () le 07/05/2006 à 20:38. (lien). Évalué à 3.jaguarwan@Jaguar:~$ cat coincoin.c
#include <stdlib.h> /* la libc ! */
#include <stdio.h> /* printf(), fgets() */
#include <unistd.h> /* read(), write(), xxx_FILENO */
#include <string.h> /* memset() */
#include <sys/types.h> /* pid_t */
#include <sys/wait.h> /* wait() */
#define PIPE_R 0 /* l'entree du pipe (input) c'est zero */
#define PIPE_W 1 /* et le sortie c'est 1 */
int main(int argc, char **argv)
{
pid_t fiston;
int in[2];
int out[2];
char buffer[BUFSIZ];
memset(buffer, 0, sizeof(buffer));
/* on prepare les pipes */
if (pipe(in) == -1) {
perror("coincoin::pipe()");
exit(EXIT_FAILURE);
}
if (pipe(out) == -1) {
perror("coincoin::pipe()");
exit(EXIT_FAILURE);
}
fiston = fork();
/* mode papa */
switch(fiston) {
case -1:
/* Oops. on a un probleme. */
perror("Papa::fork()");
exit(EXIT_FAILURE);
break;
case 0:
/* ca a marche et on est dans le fiston.
on redirige son stdin et son stdout sur les pipe. */
printf("fiston est ne !\n");
if (dup2(in[PIPE_R], STDIN_FILENO) == -1) {
perror("Fiston::dup2()");
exit(EXIT_FAILURE);
}
if (dup2(out[PIPE_W], STDOUT_FILENO) == -1) {
perror("Fiston::dup2()");
exit(EXIT_FAILURE);
}
setbuf(stdout, NULL); setbuf(stdin, NULL);
/* ici on pourrait faire un execve pepere, ca conserve les descripteurs */
/* si on fait pas de setbuf(), il faut des \n (ou des fflush()) */
printf("plop ! plop !"); sleep(1);
printf("gruiiiiiik"); sleep(1);
printf("coincoin ?!");
/* on attend une reponse du papa avant de mourir */
fgets(buffer, sizeof(buffer), stdin);
fprintf(stderr, "papa a repondu: %s **argh**\n", buffer);
exit(EXIT_SUCCESS);
break;
default:
/* ca a marche et on est dans le papa. */
printf("papa est la.\n");
/* on ecoute les idioties du fiston */
for (int i = 0; i <= 2; i ++) {
read(out[PIPE_R], buffer, sizeof(buffer));
printf("(%i) le fiston dit: %s\n", i, buffer);
memset(buffer, 0, sizeof(buffer));
}
/* on envoie un message au fiston */
write(in[PIPE_W], "pan ! pan !\n", strlen("pan ! pan !\n"));
/* (il faut *obligatoirement* un \n ici a cause du fgets de l'autre cote) */
/* on attend qu'il creve */
wait(NULL);
}
exit(EXIT_SUCCESS);
}
jaguarwan@Jaguar:~$ gcc -std=c99 -posix -pedantic -Wall coincoin.c
jaguarwan@Jaguar:~$ ./a.out
fiston est ne !
papa est la.
(0) le fiston dit: plop ! plop !
(1) le fiston dit: gruiiiiiik
(2) le fiston dit: coincoin ?!
papa a repondu: pan ! pan !
**argh**
jaguarwan@Jaguar:~$-
[^]Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....
Posté par NeoWerner () le 07/05/2006 à 22:33. (lien). Évalué à 1.Salut JaguarWan,
merci pour ton code. J'ai testé comme tu l'as mis : ca marche impect. Mais j'ai toujours le meme probleme :
j'ai exporté la partie enfant dans un autre programme './test' puis je l'ai executé avec un execve.
Si je mets le setbuf(stdout, NULL) dans mon programme test, aucun probleme, ca marche toujours impec. Mais si je l'enleve (ce qui est le cas dans la majorité des programmes), bhen ca remarche plus :(
-
[^]Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....
Posté par JaguarWan () le 08/05/2006 à 01:19. (lien). Évalué à 2.Ach, effectivement je suis un boulet, c'est dans l'execve() que le buffering se met en place...
Je pense que pour être tranquille il faudrait utiliser une paire de pty et bricoler l'esclave en mode non canonical pour qu'il renvoie ses données sans faire de buffering, mais là c'est un peu plus compliqué à écrire que mon petit programme bidon de tout à l'heure.
Je laisse donc ça en exercice aux lecteurs :]
Voilà qui pourra t'être utile:
http://www.tnt.uni-hannover.de/soft/case/lang/c/libc/libc_17(...)
Allocation de pseudo terminaux:
http://www.tnt.uni-hannover.de/soft/case/lang/c/libc/libc_to(...)
Un bout de code pour mettre un terminal en mode non canonique, sans echo et qui lit caractères par caractères:
http://www.tnt.uni-hannover.de/soft/case/lang/c/libc/libc_to(...)
Si tu te fous de la portabilité, l'appel:
int forkpty (int *amaster, char *name, struct termios *termp, struct winsize *winp)
fait un peu le café.
(http://www.tnt.uni-hannover.de/soft/case/lang/c/libc/libc_to(...) )-
[^]Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....
-
-
-
-
-
-
-
-
Revenir en haut de page || Retourner aux forums || Retourner au forum Programmation.c



Cette discussion est archivée, il n'est plus possible de laisser des commentaires.
Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.