Introduction à GTK en C++ Gimp Tool Kit for C++ Gauthier Quesnel et Eric Ramat {quesnel,eramat}@users.sourceforge.fr Institut National de la Recherche Agronomique Université du Littoral - Côte d’Opale G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 1 / 57 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 2 / 57 gtkmm qu’est ce ? gtkmm anciennement nommée gtk– est une API de programmation d’interfaces graphiques. C’est un wrapper sur gtk+ : the Gimp ToolKit. Disponible sur la plupart des plateformes : Unix, Windows. Cette bibliothèque se base sur les bibliothèques : I I I gdkmm le lien entre X-Window et gtkmm ou Win 32 et gtkmm . glibmm les fonctions de base, les outils de portabilité. sigc++ la gestion des événements via les signaux. Quelques exemples : Inkspace, K-3D, . . . G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 3 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 4 / 57 Histoire gtk+ est un toolkit développé pour Gimp 1.0 et repris par le projet GNU comme API de base pour le développement du projet Gnome. La philosophie de développement de gtkmm se base sur celle de gtk+ : écrire le moins de code possible pour définir des interfaces graphiques simples d’utilisation. Le nom des fonctions membres sont les mêmes que celle de gtk+. Il existe un très grand nombre de « wrappers » pour gtk+. Les plus connus sont : I I gtkmm , java-gnome, gtk2-perl, PyGTK GtkAda, GTKKit G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 5 / 57 Les événements : philosophie signal / slot Les événements sont gérés par la bibliothèques sigc++ sous formes d’appels de fonctions. Des paramètres peuvent être fournis à ces fonctions pour transmettre des information sur l’événement. Les événements dans les applications gtkmm se manipulent de deux manières : I I Par connexion d’un événement, signal, sur une fonction de classe, d’objet ou une fonction globale, slot. Par polymorphisme, via la surcharge des fonctions virtuelles représentant les événements d’une classe. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 6 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 7 / 57 La boucle événementielle Un programme graphique utilise une boucle événementielle : tant que l’utilisateur ne fait pas d’action sur l’interface, celle-ci ne réagit pas. Sur les systèmes X-Window, il existe une pile d’événements qui s’entassent et se dépilent au fur et à mesure des demandes de l’utilisateur ou du programme. Les événements sont les mouvements et clic sur la souris, l’appui sur une touche etc. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 8 / 57 La boucle événementielle Exemple d’implémentation simplifiée 1 2 3 4 5 6 7 8 9 10 11 while ( program == running ) { while ( not event_table . empty ()) { const Event & e = event_table . pop (); switch ( e . type ()) { case Event :: BUTT ON_CLICK ED : ... case Event :: NEED_REDRAW : ... default : } } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 9 / 57 La boucle événementielle Exemple d’implémentation simplifiée 1 2 3 4 5 6 7 8 9 10 11 while ( program == running ) { while ( not event_table . empty ()) { const Event & e = event_table . pop (); switch ( e . type ()) { case Event :: BUTT ON_CLICK ED : ... case Event :: NEED_REDRAW : ... default : } } Attention Il ne faut surtout pas rester trop longtemps dans une réponse sinon, les événements s’empileront dans la pile mais ne seront pas gérés au bon moment. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 9 / 57 La boucle événementielle, les problèmes 1 2 3 4 5 6 7 8 9 10 11 12 while ( program == running ) { while ( not event_table . empty () == false ) { const Event & e = event_table . pop (); if ( e . type () == Event :: BUTTON_ CLICKED ) { for ( int i = 0; i < 100; ++ i ) { simulation . make_step (); image . update_screen (); drawingarea . need_redraw (); // add NEED_REDRAW event } // to the event_table . } else if ( e . type () == Event :: NEED_REDRAW ) { drawingarea . copy ( image ); ... G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 10 / 57 La boucle événementielle, les problèmes 1 2 3 4 5 6 7 8 9 10 11 12 while ( program == running ) { while ( not event_table . empty () == false ) { const Event & e = event_table . pop (); if ( e . type () == Event :: BUTTON_ CLICKED ) { for ( int i = 0; i < 100; ++ i ) { simulation . make_step (); image . update_screen (); drawingarea . need_redraw (); // add NEED_REDRAW event } // to the event_table . } else if ( e . type () == Event :: NEED_REDRAW ) { drawingarea . copy ( image ); ... Le programme ne fonctionnera pas La pile d’événements contiendra 100 appels de modification de l’affichage, NEED_REDRAW, mais n’en fera aucun puisque vous ne rendait pas la main à la boucle événementielle. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 10 / 57 Correction du problème Le problème précédent peut se résoudre : timer ou un thread. 1 2 3 4 5 6 7 8 9 10 11 bool horloge () { static int i = 0; i = i + 1 if ( i != 100) { simulation . make_step (); image . update_screen (); drawingarea . need_redraw (); return true ; // the timer is not killed . } return false ; // the time is killed . } 12 13 14 15 16 int main () { // function horloge call every 100 ms timer = c r e a t e _ f o n c t i o n _ t i m e r (& horloge , 100); } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 11 / 57 Autre exemple On peut forcer la lecture des événements : 1 2 3 4 o u v r e _ d i a l o g u e _ a v e c _ b a r r e _ d e _ p r o g r e s s i o n (); for ( int i = 0; i < 100; ++ i ) { f a i t _ u n _ g r o s _ c a l c u l (); m a j _ b a r r e _ p r o g r e s s i o n (); 5 6 7 8 9 10 while ( Gtk :: Main :: events_pe nding ()) { // on mange les événements Gtk :: Main :: iteration ( false ); // restants dans la pile } } ferme _dialogu e G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 12 / 57 Structure du X Window System X est une application en fonctionnement client / serveur. I I serveur : gère l’écran, le clavier et la souris d’une machine. Reçoit et émet des requêtes d’affichage, d’entrée. client : une application graphique se connectant au serveur X et utilisant le protocole X en utilisant la Xlib. Les communications entre les clients et le serveur utilisent une « socket »permettant ainsi de déporter l’affichage. Les communications locales passes par un pipe, ie. aucune perte de vitesse due au socket. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 13 / 57 Structure du X Window System toto@local: $ ssh -X vle.univ-littoral.fr toto@vle: $ firefox & Attention Uniquement si le fichier /etc/ssh/sshd_config possède le paramètre X11Forwarding à yes. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 14 / 57 X Window System et les threads Le protocole X est un protocole asynchrone, cependant la bibliothèque Xlib est synchrone : I I Quand un programme demande de dessiner quelque chose au serveur, il doit recevoir de la Xlib un message indiquant que tout c’est bien passé avant de passer à autre chose. L’utilisation de plusieurs threads dans un processus doit faire l’objet d’une attention particulière afin de ne pas faire des demandes de dessin simultané. F F Pas propre : chaque thread protège son accès à Gtk/Gdk/Xlib par un mutex. Propre : un seul thread accède à X, les autres manipulent les données. Attention Étudier proprement votre interface graphique afin de limiter les protections mutex. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 15 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 16 / 57 Introduction aux widgets La version de Gtkmm utilisée en TP est la version 2.0, compatible avec la version 2.2. mais incompatible avec la version courante, 2.4 / 2.6 / 2.8. Les incompatibilités concernent principalement la bibliothèque sigc++ . G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 17 / 57 G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 18 / 57 Fenêtre La classe Window est le widget représentant une fenêtre dans l’environnement graphique. Cette classe possède les fonctions en relation avec le window manager, comme par exemple iconifier la fenêtre, l’enrouler etc. 1 2 3 4 5 6 int main ( int argc , char ** argv ) { Gtk :: Main app ( argc , argv ); Gtk :: Window w ; app . run ( w ); } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 19 / 57 Fenêtre La classe Window est le widget représentant une fenêtre dans l’environnement graphique. Cette classe possède les fonctions en relation avec le window manager, comme par exemple iconifier la fenêtre, l’enrouler etc. 1 2 3 4 5 6 int main ( int argc , char ** argv ) { Gtk :: Main app ( argc , argv ); Gtk :: Window w ; app . run ( w ); } Attention La fenêtre est un conteneur d’un widget G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 19 / 57 Label Le Label est un composant simple qui représente une chaîne de caractères dans une zone graphique. 1 2 int main ( int argc , char ** argv ) { Gtk :: Main app ( argc , argv ); 3 Gtk :: Window w ; Gtk :: Label label ; label . set_markup ( " <i > hello </ i > <u > world </ u > <b >! </ b > " ); 4 5 6 7 w . add ( label ); app . run ( w ); 8 9 10 } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 20 / 57 Label Le Label est un composant simple qui représente une chaîne de caractères dans une zone graphique. 1 2 int main ( int argc , char ** argv ) { Gtk :: Main app ( argc , argv ); 3 Gtk :: Window w ; Gtk :: Label label ; label . set_markup ( " <i > hello </ i > <u > world </ u > <b >! </ b > " ); 4 5 6 7 w . add ( label ); app . run ( w ); 8 9 10 } Example À noter que ce widget peut accepter une syntaxe simplifiée du langage HTML. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 20 / 57 Bouton Le Button est très simple à gérer. Plusieurs possibilités existent comme la création d’un bouton avec un label, une icône, un bouton fourni par la bibliothèque. 1 2 int main ( int argc , char ** argv ) { Gtk :: Main app ( argc , argv ); 3 Gtk :: Window w ; Gtk :: Button b ( " bonjour " ); 4 5 6 w . add ( b ); app . run ( w ); 7 8 9 } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 21 / 57 Bouton Le Button est très simple à gérer. Plusieurs possibilités existent comme la création d’un bouton avec un label, une icône, un bouton fourni par la bibliothèque. 1 2 int main ( int argc , char ** argv ) { Gtk :: Main app ( argc , argv ); 3 Gtk :: Window w ; Gtk :: Button b ( " bonjour " ); 4 5 6 w . add ( b ); app . run ( w ); 7 8 9 } Example À noter que plusieurs constructeurs existent avec des icônes, textes, images etc. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 21 / 57 Zone de textes Le widget TextView fonctionne en modèle/vue/contrôleur. On retrouve toutes les fonctions nécessaires comme la coloration syntaxique, la gestion des paragraphes, l’alignement du texte. 1 2 3 Gtk :: TextView m_text ; // Get a reference on the text . Glib :: RefPtr < Gtk :: TextBuffer >& buffer = m_text - > get_buffer (); 4 5 6 // Put string " Hello World !" buffer - > insert ( buffer - > end () , " Hello World ! " ); G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 22 / 57 Zone de textes Le widget TextView fonctionne en modèle/vue/contrôleur. On retrouve toutes les fonctions nécessaires comme la coloration syntaxique, la gestion des paragraphes, l’alignement du texte. 1 2 3 Gtk :: TextView m_text ; // Get a reference on the text . Glib :: RefPtr < Gtk :: TextBuffer >& buffer = m_text - > get_buffer (); 4 5 6 // Put string " Hello World !" buffer - > insert ( buffer - > end () , " Hello World ! " ); Example Un exemple d’implémentation d’un TextView se trouve dans le logiciel gedit. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 22 / 57 Zone de dessin La classe DrawingArea est un widget sans spécificité. Il est laissé libre aux développeurs pour être hérité et amélioré. Les fonctions de dessins sont disponibles en récupérant une référence sur le Gdk::Window et le Gdk::GC. 1 2 Gtk :: DrawingArea aire ; int largeur , hauteur ; 3 4 5 6 7 8 // Récupère la zone de dessin du widget , de a taille // de la fenêtre et d ’ un pinceau noir par défaut . Glib :: RefPtr < Gdk :: Window > win = aire . get_window (); win - > get_size ( largeur , hauteur ); Glib :: RefPtr < Gdk :: GC > gc = aire . get_style () - > get_black_gc (); 9 10 11 12 // Draw on the Gdk :: Window win - > draw_line ( gc , 0 , 0 , largeur , hauteur ); win - > draw_line ( gc , 0 , hauteur , largeur , 0); G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 23 / 57 Les conteneurs Deux types de conteneurs existent en gtk+ suivant la capacité qu’il possède : Conteneurs à un widget, héritent de Gtk::Bin I I I I Frame : un rectangle avec un label. Dialog : la boîte de dialogue minimale. Alignement : placement aligné sur une bordure. Window : la fenêtre. Conteneurs multiple, héritent de Gtk::Container I I I I VBox : une liste dynamiques d’espaces verticaux. HBox : une liste dynamiques d’espaces horizontaux. NoteBook : un widget à onglets. Table : une tableau de taille dynamique. Information Il existe bien sûr d’autres conteneurs. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 24 / 57 Conteneurs : un exemple 1 2 3 4 5 6 7 8 int main ( int argc , char ** argv ) { Gtk :: Main app ( argc , argv ); Gtk :: Window w ; Gtk :: VBox vbox ; Gtk :: HBox hbox ; Gtk :: Button b1 ( " b1 " ); // create 3 buttons . Gtk :: Button b2 ( " b2 " ); Gtk :: Button b3 ( " b3 " ); 9 hbox . pack_start ( b1 , true , true ); // pack_start add widget hbox . pack_start ( b2 , false , false ); // see Gtkmm documentation vbox . pack_start ( b3 , true , true ); vbox . pack_start ( hbox , false , false ); 10 11 12 13 14 w . add ( vbox ); w . show_all (); w . set_title ( " Test d ’ un conteneur " ); app . run ( w ); 15 16 17 18 19 } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 25 / 57 Conteneurs : un exemple Fig.: Résultat du programme conteneurs.cc G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 26 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 27 / 57 Gérer les événements Pour rappel, il existe deux modes de gestions des événements : I I héritage : surcharger la fonction de gestion de l’événement par votre propre fonction. Les fonctions se nomment : on_[widget]_[event]. connexion : connecter le signal de l’événement à une fonction. Les fonctions se nomment : signal_[event] Deux exemples de la gestion d’un clic sur un bouton : void on_button_clicked() { ...} bouton.signal_clicked().connect(sigc::mem_fun(*this, &Function)); G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 28 / 57 Où trouver les noms ? La source principale d’information : http://www.gtkmm.org/gtkmm2/docs/reference/html/ Par exemple pour un bouton, les signaux à connecter sont : Glib::SignalProxy0<void> signal_pressed(); Glib::SignalProxy0<void> signal_released(); Glib::SignalProxy0<void> signal_clicked(); Glib::SignalProxy0<void> signal_enter(); Glib::SignalProxy0<void> signal_leave(); Les fonctions à virtual void virtual void virtual void virtual void virtual void hériter sont : on_pressed() on_released() on_clicked() on_enter() on_leave() G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 29 / 57 Connexion Un premier exemple de connexion du clic sur le bouton de souris à une fonction membre de la classe : class Fenetre : public Gtk::Window { Gtk::Button button; void cliquer() { std::cout << "cliquer\n"; } public: Fenetre() : button("ok") { button.signal_clicked().connect(sigc::mem_fun(*this, &Fenetre::cliquer)); } } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 30 / 57 Héritage Si nous reprenons le même exemple du Button, nous pouvons définir une classe MonBouton qui surcharge la fonction virtuelle du clic sur le bouton de la souris. class MonButton : public Gtk::Button { public: MonButton() : Gtk::Button("Ok") virtual void on_clicked() { std::cout << Cliquer"; } } class Fenetre : public Gtk::Window { MonButton button; public: Fenetre() { } } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 31 / 57 Les événements utiles expose_event() : Elle a le même rôle que la fonction paint() du java, elle est appelé par la pile événementielle pour réafficher le contenu d’un widget. configure_event() : Cette fonction est appelée lors de la modification d’un composant : sa taille ou sa position. key_press_event() : appelée lors de l’appuie sur une touche du clavier. Information Pour insérer un demande de mise à jour de la zone graphique d’un dessin, on appel la fonction queue_draw(); G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 32 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 33 / 57 Quelques outils Glib::Rand : classe pour la génération de nombres aléatoires basé sur le Mersenne Twister. Il fournit les fonctions suivantes : get_bool(), get_int(), get_int_range(), get_double(),. . . Glib::Date : gestion des dates du calendrier julien, en vérifiant l’existence réelle des dates. Glib::Thread : gestion des threads dans les applications C++. ... G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 34 / 57 Glib::ustring Cette classe existe pour combler un énorme défaut de la STL : elle ne gère pas l’unicode UTF-8. I I I I ISO : 8 bits, utilisé par Unix et un peu les autres : compatible ASCII et ajoute les informations des pays, par exemple ISO8859-15 pour le français avec le symbole euro. UTF-16 : 16 bits, utilisé par Windows, un caractère prend deux octets sur le système et n’est donc pas compatible avec l’ASCII. UTF-32 : 32 bits, utilisé par Mac, un caractère prend quatre octects sur le systèmes et n’est donc pas compatible avec l’ASCII. UTF-8 : 8 bits minimum, 32 maximum. Utilisé de plus en plus car compatible ASCII. La taille d’un caractère est calculée suivant son taux d’utilisation dans les langues. ’a’ = 1, ’ç’ = 2, etc. La taille d’une chaîne est obligatoirement calculée. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 35 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 36 / 57 Glade Glade est une application qui permet de générer des interfaces graphiques. Elles possèdent deux modes de fonctionnement : G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 37 / 57 Glade Glade est une application qui permet de générer des interfaces graphiques. Elles possèdent deux modes de fonctionnement : Génération automatique de code, nécessite de possèder le programme glademm qui génère le code C++. Problème chaque modification d’un widget nécéssite la génération entière du projet. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 37 / 57 Glade Glade est une application qui permet de générer des interfaces graphiques. Elles possèdent deux modes de fonctionnement : Génération automatique de code, nécessite de possèder le programme glademm qui génère le code C++. Problème chaque modification d’un widget nécéssite la génération entière du projet. Génération d’un fichier d’extension glade qui contient l’interface graphique du projet. Cette méthode est à privilégier car elle est plus souple d’utilisation. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 37 / 57 Glade, le programme Fig.: L’outil de développement d’interfaces graphiques, glade en version 2.6.8 G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 38 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 39 / 57 libglademm Le rôle de cette bibliothèque est de lire le fichier d’extension .glade et de générer l’interface graphique en mémoire. Une fois chargée, l’utilisateur peut récupérer des pointeurs sur les éléments de l’interface graphiques. On peut transformer un widget de l’arbre XML en classe dérivée de ce widget. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 40 / 57 Exemple 1 1 2 # include < gtkmm .h > # include < libglademm .h > 3 4 5 6 int main ( int argc , char ** argv ) { Gtk :: Main application ( argc , argv ); Glib :: RefPtr < Gnome :: Glade :: Xml > xml ; 7 // une référence sur la hiérarchie de widgets créer // par la libglademm . xml = Gnome :: Glade :: Xml :: create ( " fenetre . glade " ); 8 9 10 11 Gtk :: Window * w = 0; 12 13 // récupération d ’ une fenêtre . xml - > get_widget ( " window " , w ); 14 15 16 if ( w ) { w - > show_all (); application . run (* w ); } 17 18 19 20 21 } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 41 / 57 Exemple 2 : explications Dans l’exemple suivant, nous allons remplacer la fenêtre fournies par la libglademm par une autre que nous avons définie dans une classe. La bibliothèque libglademm fournie la fonction reparent_widget pour placer le widget fourni en paramêtre dans un autre conteneur. Cette technique n’est pas propre puisque deux fenêtres sont alors chargées en mémoire dont une cachée. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 42 / 57 Exemple 2 class Fenetre : public Gtk::Window { public: Fenetre(); private: Gtk::VBox* v; Gtk::Button b1, b2; Gtk::Label* l; Glib::RefPtr<Gnome::Glade::Xml> xml; }; Fenetre::Fenetre() : v(0), b1("Ok"), b2("Annule"), l(0) { xml = Gnome::Glade::Xml::create("fenetre.glade"); xml->get_widget("vbox1", v); xml->get_widget("label1", l); // on déplace la VBox de l’instance générée par le fichier glade // vers la fenêtre courante xml->reparent_widget("vbox1", *this); // on connecte deux boutons b1.signal_clicked().connect(sigc::mem_fun(*this, &Gtk::Window::hide)); b2.signal_clicked().connect(sigc::mem_fun(*this, &Gtk::Window::hide)); v->add(b1); v->add(b2); v->show_all_children(); } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 43 / 57 Transformation de widgets Dans cette partie, nous allons utiliser la fonction get_widget_derived qui permet de transformer un widget de l’arbre XML chargé en mémoire dans une classe qui dérive de ce widget. Dans Glade, les widgets utilisés sont des composants prédéfinis dans la bibliothèque gtkmm . La fonction précédente va permettre de transformer un objet dans un autre du moment qu’ils ont un héritage commun. L’exemple suivant montre la transformation de la fenêtre courante du fichier glade dans une nouvelle classe DerivedDialog. Pour que cette opération soit valide, gtkmm demande le développement d’un constructeur particulier qui va lui permettre de construire l’objet dérivé. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 44 / 57 Exemple 3 class DerivedDialog : public Gtk::Dialog { public: // Le constructeur que la fonction demande obligatoirement DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade); protected: virtual void on_button_quit(); Glib::RefPtr<Gnome::Glade::Xml> m_refGlade; Gtk::Button* m_pButton; }; DerivedDialog::DerivedDialog(BaseObjectType* cobject, const Glib::RefPtr<Gnome::Glade::Xml>& refGlade) : Gtk::Dialog(cobject), m_refGlade(refGlade), m_pButton(0) { // On récupère un pointeur sur le bouton et on affecte la // fonction virtuelle m_refGlade->get_widget("quit_button", m_pButton); if(m_pButton) m_pButton->signal_clicked().connect( sigc::mem_fun(*this, &DerivedDialog::on_button_quit)); } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 45 / 57 Exemple 3 - suite 1 2 # include < gtkmm .h > # include < libglademm .h > 3 4 5 6 int main ( int argc , char ** argv ) { Gtk :: Main application ( argc , argv ); Glib :: RefPtr < Gnome :: Glade :: Xml > xml ; 7 // une référence sur la hiérarchie de widgets créer // par la libglademm . xml = Gnome :: Glade :: Xml :: create ( " dialog . glade " ); 8 9 10 11 DerivedDialog * d = 0; 12 13 // récupération de la boîte de dialogue xml - > g e t _ w i d g e t _ d e r i v e d ( " dialog " , d ); 14 15 16 if ( d ) { d - > show_all (); application . run (* d ); } 17 18 19 20 21 } G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 46 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 47 / 57 pkg-config Gère les chemins vers les bibliothèques et flags d’édition de liens pour les bibliothèques compatibles installées sur le système. La description des ces bibliothèques se trouvent dans le dossier : /usr/lib/pkgconfig Par exemple, la commande suivante affiche toutes les includes et bibliothèques nécessaire à la compilation d’un fichier. pkg-config –libs –cflags gtkmm-2.0 G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 48 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 49 / 57 Makefile make est un outils de gestion de fichiers, et pas seulement de fichier C. make accepte une syntaxe type sh et donc tous les programmes accessible par ce biais. La syntaxe de make se gère en arbre de priorité. La tête de l’arbre se nomme all Le fonctionnement et le suivant : but : [dépendances] <tabulation> Comment réaliser le but. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 50 / 57 Makefile : un premier exemple Un premier exemple de fichier Makefile pour compiler un programme C écrit en cinq fichiers. all : fichier1.o fichier2.o main.o g++ -o executable fichier1.o fichier2.o main.o fichier1.o : fichier1.c fichier1.h g++ -c fichier1.c -Wall fichier2.o : fichier2.c fichier2.h g++ -c fichier2.c -Wall main.o : main.c fichier1.h fichier2.h g++ -c main.c -Wall clean : rm *~ *.o executable G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 51 / 57 taper make dans le console signifie make all, c’est-à-dire, utiliser l’arbre de dépendance complet. Taper make fichier1.o indique de n’utiliser que la branche de dépendance fichier1.o donc générer ce fichier. Taper make clean indique de n’utiliser que la branche clean, c’est-à-dire, supprimer les fichiers destinations. Taper make clean all appel l’arbre clean puis l’arbre all. Example Le prochain fichier Makefile utilise le programme pkg_config pour récupérer les emplacements des bibliothèques de développement et leurs noms. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 52 / 57 Exemple de fichier Makefile CC=g++ CFLAGS=-Wall -W -g ‘pkg-config gtkmm-2.4 libglademm-2.4 –cflags‘ LFLAGS=‘pkg-config gtkmm-2.4 libglademm-2.4 –libs‘ OBJECTS=main.o application.o HEADERS=application.hpp TARGET=helloworld all: $(TARGET) $(TARGET):$(OBJECTS) $(CC) $(LFLAGS) -o $(TARGET) $(OBJECTS) %.o: %.cc $(CC) $(CFLAGS) -c $< -o $@ clean: rm -f $(OBJECTS) $(TARGET) *~ G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 53 / 57 autotools GNU Rendre les programmes portable en récupérant les paramètres du compilateur, du système d’exploitation, des bibliothèques disponibles. Permet la création de scripts de tests d’existence de bibliothèques ou des fichiers. Génération des fichiers Makefile automatiquement via des prototypes de Makefile : Makefile.am. Les programmes founis sont autoscan, autoheader, automake, aclocal et autoconf. Pour plus d’information reportez-vous aux documentations en lignes du projet GNU. G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 54 / 57 Plan 1 gtkmm La philosophie La boucle événementielle Les widgets Les événements 2 glibmm , glade et libglademm glibmm glade libglademm 3 Outils pkg_config Makefile Les liens G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 55 / 57 Les liens Une petite liste de liens : gtkmm http://www.gtkmm.org gtkmm le livre : http://www.gtkmm.org/gtkmm2/docs/tutorial/html/index.html gtk+ http://www.gtk.org stl http://www.sgi.com/tech/stl/ C++ http://www.cplusplus.com/ faq C++ http://www.parashift.com/c++-faq-lite/index.html G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 56 / 57 Licence Cours GTKmm Copyright (C) 2007-2008 - VLE Development Team {quesnel,eramat}@users.sourceforge.net Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.2 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". G. Quesnel et E. Ramat (INRA et ULCO) GTKmm 57 / 57