Forum Programmation.c comment realiser une GUI ?

Posté par  .
Étiquettes : aucune
0
6
mai
2006
Bonsoir tout le monde,

Je 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.
  • # expect

    Posté par  (site web personnel) . Évalué à 1.

    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 ....

    Posté par  (site web personnel) . Évalué à 2.

    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 ...

    Adhérer à l'April, ça vous tente ?

    • [^] # Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....

      Posté par  . É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  (site web personnel) . É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.

        Adhérer à l'April, ça vous tente ?

        • [^] # Re: je ne sais pas si j'ai bien saisi ton problème, mais bon ....

          Posté par  . É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  . É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  . É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  . É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:~$

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.