Partage
  • Partager sur Facebook
  • Partager sur Twitter

[GTK +] Je comprend pas...

Les notions d'objet, de creation...etc

Sujet résolu
    28 mai 2006 à 1:07:50

    Bonjours!

    J'ai commencé a me mettre au GTK + en C il y a peu. J'ai lu deux ou trois tutos tels que:
    Celui-ci
    Lui pour installer sous C:B

    Et là je suis même pas rendu à la page 15 qu'on me balance un exemple de fonctions qu'on doit créer pour envoyer des sic=gnal, se connecter ou quelquechose comme ça... o_O

    Je ne comprend vraiment pas la notion de GTK +, si quelqu'un a du temps a perdre pour m'expliquer un peu...

    En passant le morceau du tuto que je ne comprend pas est celui-là:
    Avant de commencer l'étude de la création d'interface graphique grâce à Gtk+, il faut
    savoir que les objets graphiques de Gtk+ sont appelés des widgets (Window Gadget).
    Un widget est en fait une structure définissant les propriétés d'un objet associé à une
    large panoplie de fonctions permettant de manipuler ces objets.
    Ici, le terme "objet" est à prendre au sens littéral, mais aussi au sens Programmation
    Orientée Objet (POO). En effet, bien que GTK+ soit écrit en C, il introduit la notion
    d'héritage et les widgets de Gtk+ suivent une hiérarchie bien définie. Ainsi tous les
    objets graphiques héritent des propriétés et des fonctions d'un widget de base qui
    s'appelle GtkWidget.
    Ainsi le widget permettant d'afficher une fenêtre (GtkWindow) a bien sûr ses propres
    fonctions, mais grâce à l'héritage il bénéficie aussi des fonctions des autres widgets
    dont il dérive.
    2. La gestion des évènements
    Afin de faire réagir une application aux actions de l'utilisateur, Gtk+les traite comme
    des évènements dans une boucle événementielle.
    Lorsque l'utilisateur interagit avec l'application, qu'il clique sur un bouton, qu'il ferme
    une fenêtre, le widget concerné émet un signal spécifique. Chaque widget possède un
    signal pour chaque action possible.
    Le signal est intercepté par une boucle événementielle. Celle-ci met en
    correspondance le signal envoyé et l'action spécifique prévue pour le signal. Si la
    correspondance est prévue, la fonction associée sera exécutée. Ces fonctions
    s'appellent fonction "callback".
    Programmer avec les Widget revient à créer ces fonctions "callback" pour chacun des
    évènements susceptible d'avoir lieu pendant l'exécution du programme et à associer
    ces fonctions avec les signaux.
    La première étape consiste donc à créer une fonction "callback". Dans la majorité des
    cas, ce sera sous cette forme :
    void nom_de_la_fonction(GtkWidget *widget, gpointer data)
    Le paramètre widget est le widget qui a émis le signal, et data est une donnée
    supplémentaire utile à l'application.
    Pour connecter un signal à notre fonction "callback", Gtk+ utilise une fonction de la
    bibliothèque GLib :
    gulong g_signal_connect(gpointer *object, const gchar *name, GCallback func, gpointer
    func_data );
    Le paramètre object, correspond au Widget qui émet le signal. Cependant, la variable
    demandée par g_signal_connect étant de type gpointer* (correspond à void* du C
    standard) et le widget de type GtkWidget*, il faut convertir ce dernier pour ne pas
    Page 11/161
    Gtk-Fr Cours Gtk+
    provoquer d'erreur lors de la compilation. Pour cela Gtk+ (ou dans ce cas GLib) fournit
    une macro de conversion (G_OBJECT) qui sera à utiliser à chaque utilisation de cette
    fonction.
    Le paramètre name, est le signal qui doit être intercepté par la boucle événementielle.
    Dans ce cours, certains signaux seront utilisés dans les exemples, mais la rubrique "En
    savoir plus" donnera une liste complète des signaux qui peuvent être émis par un
    widget.
    Le paramètre func, définit la fonction callback à associer au signal. Cette fois encore, il
    faudra utiliser une macro de conversion qui est G_CALLBACK(func).
    Le paramètre func_data, permet de spécifier une donnée quelconque à laquelle la
    fonction callback peut avoir accès pour effectuer son travail correctement.
    Une fois que les signaux sont connectés, il faut lancer la boucle événementielle en
    appelant cette fonction :
    void gtk_main(void);
    Cela aura pour effet de faire entrer Gtk+ dans une boucle infinie qui ne pourra être
    stoppée que par l'appel de la fonction de fin de boucle qui est :
    void gtk_main_quit(void);
    Ces fonctions correspondent au minimum nécessaire afin de pouvoir créer une
    application Gtk+ correcte. D'autres fonctions permettent une utilisation avancée des
    signaux et de la boucle événementielle et sont traitées dans le chapitre GSignal du
    cours.
    • Partager sur Facebook
    • Partager sur Twitter
      28 mai 2006 à 7:29:15

      Si tu n'as fait que les tutos de Matheo, NE TE LANCE PAS DANS GTK+, c'est du C++, donc, orienté objet, et tu n'as pas encore vu ça.
      • Partager sur Facebook
      • Partager sur Twitter
      Anonyme
        28 mai 2006 à 8:27:31

        Citation : Insomniak

        Si tu n'as fait que les tutos de Matheo, NE TE LANCE PAS DANS GTK+, c'est du C++, donc, orienté objet, et tu n'as pas encore vu ça.

        *
        N'imp'!!!! C'est du C!
        Je vais essayer de t'expliquer clairement: gtk est basé sur les GtkWidget* , qui représentent les objets de base que l'on peut modeler à l'infini, et on utilise différentes fonctions de création, telles que gtk_image_new() etc...
        Si tu veux utiliser ensuite, par exemple une table, il faut utiliser la macro GTK_TABLE(table) qui convertit table en GtkTable

        Après gtk utilise un système de callback, le plus démonstratif est celui-ci:
        g_signal_connect(G_OBJECT(pWindow)/*pWindow est la fenêtre*/, "destroy" /*On clique sur la croix*/, G_CALLBACK(gtk_main_quit) /*gtk_main_quit, c'est la fin de la boucle gtk_main, donc le programme*/, NULL/*les paramètres à passer: ici, aucun*/);

        Il y en a évidemment d'autres comme le clic sur un bouton etc... ça faut voir les tutos.

        Pose des questions si tu ne comprend pas
        (je te conseille come site gtk-fr.org, ils expliquent tout et tu peux lire une partie sans avoi lu les autres (sauf les premières où ils expliquent le principe de fonctionnement, évidemment ^^ )
        • Partager sur Facebook
        • Partager sur Twitter
          28 mai 2006 à 8:47:51

          Insomniak, c'est un peu la honte quand même, dans la troisième ligne de son texte on lit que c'est codé en C :p

          458.KNB > Tu ne comprends pas à partir de quelle ligne ? Tu t'es renseigné un peu sur la POO ?
          (en googlant/wikipédiant deux secondes je trouve http://hdd34.developpez.com/cours/artpoo/)
          • Partager sur Facebook
          • Partager sur Twitter
          Anonyme
            28 mai 2006 à 9:38:13

            Hé mais c'est bien expliqué ton truc là! je m'y met tout de suite (en fait gtk c'et un peu de l'OO, non?)
            • Partager sur Facebook
            • Partager sur Twitter
              28 mai 2006 à 9:51:17

              Oui, et c'est marqué environ à la 5e ligne de la citation de 458.KNB.
              • Partager sur Facebook
              • Partager sur Twitter
              Anonyme
                28 mai 2006 à 9:54:04

                Ha ^^
                Sinon la partie 4, c'est du Pascal, mais ça peut être intéressant quand même? je veux dire: est-il intéressant d elire la partie 4 si on programme en C?
                • Partager sur Facebook
                • Partager sur Twitter
                  28 mai 2006 à 9:56:18

                  En gros Gtk ca marche comme ca:

                  GtkWidget *truc; -> on creer un element

                  truc = gtk_window_new(GTK_WINDOW_TOPLEVEL); -> on lui associe un type (une fenetre, un bouton...)

                  gtk_init (&argc, &argv); -> on demarre le gtk (obligatoire)

                  g_signal_connect(G_OBJECT(bouton_generer), "clicked", G_CALLBACK(generate), NULL); -> c'est un evenement, la c'est quand on clique sur le bouton generer, on execute un fonction "generate".

                  gtk_widget_show_all (fenp); -> la on affiche toute la fenetre fenp ainsi que ses widgets (je rapelle que se sont des objets)

                  gtk_main (); -> la c'est pour dire que gtk attends toute forme d'evenement déclaré plus haut (a mettre une fois sa suffit)

                  gtk_main_quit(); -> on ferme gtk (loublie pas sinon ca va consommer du cpu)

                  Bref si ta des question mp moi!
                  • Partager sur Facebook
                  • Partager sur Twitter
                    28 mai 2006 à 9:56:18

                    Citation : bluestorm

                    Insomniak, c'est un peu la honte quand même, dans la troisième ligne de son texte on lit que c'est codé en C :p)



                    :lol: j'étais pas réveillé moi :p

                    Non, il parle de notion d'objet, alors je me dit que c'est du c++ :-°
                    • Partager sur Facebook
                    • Partager sur Twitter
                    Anonyme
                      28 mai 2006 à 10:00:37

                      @ Uims: Moi je préfère mettre gtk_main_quit au destroy de la fenêtre principale, c'est pas mieux? Parce que sinon la boucle gtk_main ne s'arrête jamais...
                      • Partager sur Facebook
                      • Partager sur Twitter
                        28 mai 2006 à 10:02:58

                        Oui la je la sort de la fonction pour expliquer, mais effectivement je la met dans une fonction "static destroy", ca me permet par exemple de mettre un avertissement avant de fermer...:p
                        • Partager sur Facebook
                        • Partager sur Twitter
                          28 mai 2006 à 13:19:21

                          Bon matin! Enfin pour moi qui est Canadien... ^^

                          Je suis servis avec toutes ces réponses, je vais essayer de rectifier un peu.

                          bluestorm > Ouai, j'ai touché un peu à la POO grâce à un superbe livre que je ne comprenais malheureusement pas :p

                          Insomniak > Alors la bravo! :-°;)

                          Zulon > Premièrement, je comprend très bien le système de Widdgets, la création mais c'est les callsback, de signal et tu parles aussi de tables... o_O Bref c'est le fouilli total...

                          Uims > Mouais, c'est clair mais encore un fois, c'est quoi ces foutus callbacks!!! o_O

                          En passant merci beaucoup pour toutes ces belles réponses :D
                          • Partager sur Facebook
                          • Partager sur Twitter
                            28 mai 2006 à 15:36:39

                            Citation

                            Le signal est intercepté par une boucle événementielle. Celle-ci met en
                            correspondance le signal envoyé et l'action spécifique prévue pour le signal. Si la
                            correspondance est prévue, la fonction associée sera exécutée. Ces fonctions
                            s'appellent fonction "callback".



                            En gros t'as une grosse fonction qui prend en argument un signal, une fonction, et qui les "lie" entre eux : quand par la suite GTK recevra le signal que tu as donné, il appellera la fonction.
                            (callback ça veut dire en gros "fonction qu'on donne en argument pour qu'elle soit appellée plus tard)

                            g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);

                            (j'ai viré les commentaires car avec on comprend rien)
                            Ce code de Zulon veut dire "Quand pWindow recevra le signal destroy, il appellera gtk_main_quit, et lui donnera NULL (rien) en argument".
                            • Partager sur Facebook
                            • Partager sur Twitter
                              28 mai 2006 à 23:28:57

                              Alors si je comprend bien, on peut créer nous même une fonction pour la passer en paramètre à g_signal_connect pour que les instructions dedans ma fonctions soient exécutées quand un évènement se produit! :)

                              Mais dans le tutos ils donnent ça comme exemple d'une fonction "callback" (si je comprend bien):

                              La première étape consiste donc à créer une fonction "callback". Dans la majorité des
                              cas, ce sera sous cette forme :
                              void nom_de_la_fonction(GtkWidget *widget, gpointer data)
                              Le paramètre widget est le widget qui a émis le signal, et data est une donnée
                              supplémentaire utile à l'application.


                              Mais quand j'associe ma fonction à un signal, dans:

                              G_CALLBACK(gtk_main_quit)


                              Pourquois ne faut-il pas envoyer des paramètres??? Du genre:

                              G_CALLBACK(gtk_main_quit(...,...))


                              Parceque le prototype d'une fonction callback est:

                              void nom_de_la_fonction(GtkWidget *widget, gpointer data)


                              • Partager sur Facebook
                              • Partager sur Twitter
                                29 mai 2006 à 0:28:04

                                Et bien on donne juste le nom de la fonction (car le nom d'une fonction en C représente un pointeur vers cette fonction, cf. http://www.siteduzero.com/tuto-3-4976-1-les-pointeurs-de-fonctions.html).
                                Ainsi, au lieu d'appeler la fonction avec des arguments pour regarder la valeur, il va garder juste la fonction, pour pouvoir l'appeler en temps voulu.

                                Avec quels arguments ? Et bien le widget (dans le prototype de la fonction), c'est toi qui le lui donne en premier argument de g_signal_connect. Et tu as le dernier argument de g_signal_connect, un pointeur, dans lequel tu peux mettre les arguments que tu voudras passer à la fonction au moment où le signal sera reçu (cela correspond au "gpointer data" du prototype).
                                • Partager sur Facebook
                                • Partager sur Twitter
                                  29 mai 2006 à 0:34:34

                                  Mais justement, c'est quoi qui s'occupe d'envoyer les paramètres???

                                  PS: merci pour le lien, je vais le lire!
                                  • Partager sur Facebook
                                  • Partager sur Twitter
                                    29 mai 2006 à 0:35:38

                                    Et bien c'est GTK, qui gère la boucle des évènement et appelle les fonctions dans tout dos. C'est ça l'avantage des bibliothèques : elles font des trucs à ta place.

                                    (pour la SDL c'est pareil, d'ailleurs)
                                    • Partager sur Facebook
                                    • Partager sur Twitter
                                      29 mai 2006 à 0:57:17

                                      Et bien merci beaucoup! je comprend enfin ^^
                                      • Partager sur Facebook
                                      • Partager sur Twitter
                                      Anonyme
                                        29 mai 2006 à 17:20:32

                                        Je crois que j'ai plus embrouillé qu'autre chose... désolé ^^ mais je fais du gtk depuis un certain temps maintenant, je me rappelais plus comment c'était quand j'y comprenais pas grand chose
                                        Sinon si tu as compris bravo, tu fais partie des programmeurs gtk ^^
                                        • Partager sur Facebook
                                        • Partager sur Twitter
                                          29 mai 2006 à 23:38:23

                                          Ce que j'ai jamais capté c'est ça :



                                          /* Soit maFonction tel que... */

                                          void maFonction(char *nom, int age)
                                          {
                                          [...]
                                          }

                                          /*

                                          Comment puis-je faire passer les paramètres de ma fonction (nom et age) par signal_connect() ?

                                          */


                                          /* Si je fais ça... */

                                          signal_connect(G_OBJECT(pButton), "clicked", G_CALLBACK(maFonction("DDxS", 16)), NULL);

                                          /* ... ça marche pas :( */
                                          • Partager sur Facebook
                                          • Partager sur Twitter
                                            30 mai 2006 à 0:47:16

                                            Justement, tu peux pas...enfin je crois :p
                                            • Partager sur Facebook
                                            • Partager sur Twitter
                                              30 mai 2006 à 4:12:14

                                              Tu ne peux pas mettre de parenthèses sur le nom de la fonction. Tu dois créer une structure contenant le informations à passer et la passer en argument de ta fonction de callback. Tu ne respectes pas bien les paramètre d'une fonction de callback.
                                              • Partager sur Facebook
                                              • Partager sur Twitter
                                                30 mai 2006 à 13:57:54


                                                struct infos {
                                                   char *nom;
                                                   int age;
                                                }

                                                /* Soit maFonction tel que... */
                                                 
                                                 void maFonction(struct *infos)
                                                 {
                                                // infos->nom, infos->age...
                                                 [...]
                                                 }
                                                 

                                                struct infos des_infos { "quelqu'un", 18 };
                                                 /*
                                                 
                                                 Comment puis-je faire passer les paramètres de ma fonction (nom et age) par signal_connect() ?
                                                 
                                                 */

                                                 
                                                 /* Si je fais ça... */
                                                 
                                                 signal_connect(G_OBJECT(pButton), "clicked", G_CALLBACK(maFonction), &des_infos);
                                                 
                                                 /* ... ça marche pas :( */


                                                Je dirais qu'un truc comme ça marche. (j'ai jamais testé)
                                                • Partager sur Facebook
                                                • Partager sur Twitter
                                                Anonyme
                                                  30 mai 2006 à 17:32:49

                                                  Nan ça ira pas, faut que le premier paramètre soit un pointeur vers le widget qui appelle, non?
                                                  Sinon c'est sûr faut tout mettre dans une structure et passer au callback
                                                  • Partager sur Facebook
                                                  • Partager sur Twitter
                                                    30 mai 2006 à 18:15:56

                                                    Le code ne marchera pas. En effet, on doit passer dans une structure les arguments pour notre fonction de callback. Voici la forme obligatiore d'une fonction de callback :

                                                    void nom_de_la_fonction_de_callback(GtkWidget *widget, gpointer data)
                                                    {
                                                       
                                                        /* ... */

                                                    }


                                                    Le premier paramètre correspond à un pointeur sur le widget qui a envoyé le signal. Le deuxième correspond à la structure envoyée en paramètre. Tu passe ta structure en dernier paramètre de :

                                                    g_signal_connect(gpointer *object, const gchar *name, GCallback func, gpointer func_data ); // La structure est passée en dernier paramètre
                                                    • Partager sur Facebook
                                                    • Partager sur Twitter
                                                      30 mai 2006 à 23:46:18

                                                      Euh mais euh, c'est ce que j'ai fait non ?
                                                      • Partager sur Facebook
                                                      • Partager sur Twitter
                                                        31 mai 2006 à 4:00:06

                                                        Oui mais ta fonction de callback n'avait pas le bon prototype. Tu dois avoir obligatoirement en premier argument un pointeur sur le widget qui a émit le signal et en deuxième argument, une structure avc les données que tu veux envoyer.
                                                        • Partager sur Facebook
                                                        • Partager sur Twitter

                                                        [GTK +] Je comprend pas...

                                                        × Après avoir cliqué sur "Répondre" vous serez invité à vous connecter pour que votre message soit publié.
                                                        × Attention, ce sujet est très ancien. Le déterrer n'est pas forcément approprié. Nous te conseillons de créer un nouveau sujet pour poser ta question.
                                                        • Editeur
                                                        • Markdown