Articles Taggés ‘POO’

Créer simplement une interface GTK en C++

14 avril 2009

hello

Introduction

Aujourd’hui, développer une application, inclut très souvent la création d’une interface graphique.
Sous Linux, LA librairie graphique utilisé sous GNOME est GTK.

L’utilisation de cette librairie peut-être très fastidieux en C, par exemple, car vous devez créer tout vos controls, les emboîter les uns les autres et ceux … sans voire le résultat. ( Vous le verrez uniquement a l’exécution. )
Je trouve, d’ailleurs, paradoxale de faire une interface graphique sans la dessiner … mais bon.

Nous allons donc voire comment créer visuellement, et facilement, une interface GTK, et l’implémenter dans un code C++.

Feuille de route

Voici un schéma simple, qui représente la hiérarchie à utiliser:

glade-gtkmm

Créer l’interface

Donc, dans un premier temps, il faut utiliser Glade pour créer votre interface graphique.
Prenons un exemple simple:
hello

Je pense que vous avez compris ce que fera notre exemple ;-)
Pour ceux qui sont à l’Ouest:
L’utilisateur entrera son nom, cliquera sur Appliquer, et le label Hello ! changera pour Hello sonnom !

Donc, nous obtenons un fichier glade. Ici appelé hello.glade. (Télécharger hello.glade)

J’ai laisser expret les noms d’origine de tout les controls pour que ce soit plus simple à suivre dans le code.

Implémenter l’interface dans le code

Nous voici dans la partie la plus dur… et heureusement … c’est pas dur ! :-D

Donc, vue que l’on bosse en C++, on va créer une objet de notre fenêtre et ses controls.
Pour ce faire, on va utiliser l’excellent GTKmm!
C’est une interface à GTK pour C++.

Le projet Hello sera composé de 3 fichiers:

  • hello.h
  • hello.cpp
  • main.cpp

Les hello.* c’est l’objet de la fenêtre, et le main ne sert uniquement qu’a initialiser GTK, charger le fichier glade et demander à GTK de lancer notre fenêtre.
Pour que notre projet C++ puisse utiliser les Widgets GTK, nous allons utiliser les Derived Widgets.

main.cpp

Commençons par le fichier main.cpp.
Comme dis plus haut, on va initialiser GTK, charger le fichier glade, puis appeler l’objet Hello que l’on aura créé:
[sourcecode language="cpp"]
//~ Pour accéder au std::cerr
#include

//~ Dépendances GTKmm
#include
#include

int main( int argc, char * argv[] )
{
//~Pointeur sur le fichier glade
Glib::RefPtr RefXmlGlade;

//~ Initialise GTK
Gtk::Main kit(argc, argv);

//~ Charge le fichier glade, et initialise ses widgets
#ifdef GLIBMM_EXCEPTIONS_ENABLED
try
{
//~ Ici on donne la position du fichier glade à utiliser
RefXmlGlade = Gnome::Glade::Xml::create(« hello.glade »);

} catch(const Gnome::Glade::XmlError& ex)
{

std::cerr << "GraphicalUserInterface::LoadGladeFile(): Loading failed !" << std::endl;
std::cerr << "GraphicalUserInterface::LoadGladeFile(): " << ex.what() << std::endl;

return false;
}
#else
//~ Ici on donne la position du fichier glade à utiliser
std::auto_ptr error;
RefXmlGlade = Gnome::Glade::Xml::create("hello.glade", "", "", error);
if ( error.get() )
{

std::cerr << "GraphicalUserInterface::LoadGladeFile(): Loading failed !" << std::endl;
std::cerr << "GraphicalUserInterface::LoadGladeFile(): " << error->what() << std::endl;

return false;
}
#endif

//~ TODO: Initialiser l'objet Hello de notre fenêtre, et demander à GTK de nous l'afficher.

return 0;
}
[/sourcecode]

Nous voici, ici, avec un main qui va pointer sur le fichier Glade.
Il est temps de créer notre Widget dérivé du fichier glade pour enfin afficher notre interface ! ;-)

hello.h

Bon le fichier header est simple. La seule complexité ici, mais une fois compris ca n’en ai plus une c’est le constructeur.
En effet, nous allons créer une objet héritant de Gtk::Window, et il va falloir faire un lien avec le fichier glade.

[sourcecode language="cpp"]
#ifndef HELLO_H
#define HELLO_H

#include
#include

//~ Déclaration de la class de notre objet Hello, héritant de Gtk::Window
class Hello : public Gtk::Window
{

public:
//~ Ici notre constructeur un peu particulier.
Hello(BaseObjectType* cobject, const Glib::RefPtr& refGlade);
virtual ~Hello();
private:
//~ Le pointeur Glade de notre classe. Il récupérera une référence sur celui, créé dans le main.cpp
Glib::RefPtr RefXmlGlade;

};

#endif

[/sourcecode]

Et maintenant le fichier hello.cpp

[sourcecode language="cpp"]
#include « hello.h »

//~ Ici notre constructeur un peu particulier.
Hello::Hello(BaseObjectType* cobject, const Glib::RefPtr& refGlade)
: Gtk::Window(cobject),
RefXmlGlade(refGlade)
{
}

Hello::~Hello()
{
}
[/sourcecode]

Ici, tout ce que l’on fais c’est prendre la référence du pointeur glade venant du main.cpp à la ligne 5, et l’on donne une référence sur notre classe ayant hérité de Gtk::Window.
A noter que les lignes 4 et 5 auraient put être écrite dans les acollades du constructeur … mais ca fat plus de boulot pour rien. ( Merci Rniamo ;-) )

Il ne reste plus qu’a passer notre objet à GTK pour qu’il dessine notre interface !
Retour dans le main.cpp:
Ligne 45, au todo:
[sourcecode language="cpp"]
//~ Créer un pointeur windowHello sur l’élément window1 du fichier glade
RefXmlGlade->get_widget_derived(« window1″, windowHello);
if( windowHello )
{
//~ Ici la fenêtre est dessiné par GTK, et fonctionnelle.
kit.run(*windowHello);

//~ La ligne précédente est bloquante. Le curseur d’execution arrive
//~ ici qu’une fois la fenêtre détruite par GTK.
//~ Donc on libère la mémoire
delete windowHello;
windowHello = 0;
}
[/sourcecode]

Compilation

Il ne reste plus qu’a compiler le tout, et le lancer.
Serte nous aurons qu’une fenêtre sans réactions… mais ca va venir ;-)

[sourcecode language="bash"]
g++ -o test `pkg-config libglademm-2.4 –cflags –libs` *.cpp
[/sourcecode]

[sourcecode language="bash"]
./test
[/sourcecode]

Bouton Quitter

Occupons nous de ce bouton pour fermer notre fenêtre.
Il va donc falloir lier le signale clicked() du bouton à une méthode de notre classe, qui appellera le hide() de Gtk::Window

Donc, première étape, créer un objet de notre bouton Quitter et une methode qui sera appellé au signal clicked() dans le hello.h :
[sourcecode language="cpp"]
#ifndef HELLO_H
#define HELLO_H

#include
#include
#include

class Hello : public Gtk::Window
{
public:
Hello(BaseObjectType* cobject, const Glib::RefPtr& refGlade);
virtual ~Hello();
private:
//~ Ici on ajoute, en privé, la méthode, qui ne doit rien renvoyer, qui sera appelé
void on_button_quit();

Glib::RefPtr m_refXmlGlade;
//~ Voici notre bouton GTK !
Gtk::Button * m_buttonQuit;
};

#endif

[/sourcecode]

Et dans notre hello.cpp, ajoutons l’appelle au bouton, son lien vers la methode on_button_quit() et ajoutons cette dernière :
[sourcecode language="cpp"]
#include « hello.h »

Hello::Hello(BaseObjectType* cobject, const Glib::RefPtr& refGlade)
: Gtk::Window(cobject),
m_refXmlGlade(refGlade),
m_buttonQuit(0)
{
//~ On pointe, dans le fichier glade, sur le bouton « button1″
m_refXmlGlade->get_widget(« button1″, m_buttonQuit);
if ( m_buttonQuit )
{
//~ Ici on créer le lien vers notre methode on_button_quit() de notre objet Hello.
m_buttonQuit->signal_clicked().connect( sigc::mem_fun(*this, &Hello::on_button_quit) );

} else {
std::cerr << "Unable to hook the Quit button !" << std::endl;
}

}

Hello::~Hello()
{
}

//~ Et voici la méthode on_button_quit() qui sera appelé par le signal clicked() tu bouton.
void Hello::on_button_quit()
{
//~ Et donc, on appelle la méthode hide() de Gtk::Window par héritage
hide();
}
[/sourcecode]

Après recompilation, et lancement, vous pouvez fermer la fenêtre avec le bouton.

Maintenant, pour le bouton appliquer, qui va changer la caption du label, c'est exactement le même procédé pour le bouton.
Seule la le contenue de la méthode qui sera appelé, changera ! :-)

Le bouton appliquer

Bon donc, on redéclare une bouton Gtk, on pointe dans le fichier Glade sur « button2″, et on fait un lien vers une méthode.
Pour avoir un pointeur sur le label, c’est le même code que pour le bouton, sans le lien et le if, et il faut créer un Gtk::Lable vers « label2″.
Ha oui, et pour le Gtk:Entry ( la boite de texte pour entrer le nom ), c’est pareil que pour le label.
Pour l’exemple, je l’ai appelé, sans originalité on_button_apply().
Aussi, pour avoir un code clair, j’ai créé une méthode sayHello() qui prend le nom de la personne en paramètre et change le label. Mais ca aurai tout aussi bien put être fais entièrement dans la méthode on_button_apply().

[sourcecode language="cpp"]
#include « hello.h »

//~ Ici j’ai ajouté le bouton, le label et la boite de text en initialization à 0
Hello::Hello(BaseObjectType* cobject, const Glib::RefPtr& refGlade)
: Gtk::Window(cobject),
m_refXmlGlade(refGlade),
m_buttonQuit(0),
m_buttonApply(0),
m_entryName(0),
m_labelName(0)
{

m_refXmlGlade->get_widget(« button1″, m_buttonQuit);
if ( m_buttonQuit )
{

m_buttonQuit->signal_clicked().connect( sigc::mem_fun(*this, &Hello::on_button_quit) );

} else {
std::cerr << "Unable to hook the Quit button !" << std::endl;
}

//~ Ici notre bouton Appliquer
m_refXmlGlade->get_widget(« button2″, m_buttonApply);
if ( m_buttonApply )
{
//~ Que nous lions à la méthode on_button_apply()
m_buttonApply->signal_clicked().connect( sigc::mem_fun(*this, &Hello::on_button_apply) );

} else {
std::cerr << "Unable to hook the Apply button !" << std::endl;
}

//~ Ici on récupère le lable et la boite de text.
m_refXmlGlade->get_widget(« entry1″, m_entryName);
m_refXmlGlade->get_widget(« label1″, m_labelName);
}

Hello::~Hello()
{
}

void Hello::on_button_quit()
{
hide();
}

//~ Notre nouvelle méthode, appelé au clique sur appliquer
void Hello::on_button_apply()
{
//~ Qui appelle la méthode sayHello() en passant ce qui à été entré dans la boite de text
//~ Il suffit d’utiliser get_text() sur la boite de dialog pour récupérer son text… facile hun ! :-D
this->sayHello( m_entryName->get_text() );
}

//~ La méthode qui va modifier le Label
void Hello::sayHello( Glib::ustring name )
{
//~ Avec la valeur passé en argument.
//~ Il est évident qu’il faudrait faire des petites vérifications avant de modifier le label :-)
m_labelName->set_text(« Hello  » + name + « ! »);
}
[/sourcecode]

Voila, quand vous lancer le projet, vous aller pouvoir afficher votre nom dans le label.

Conclusion:

Je sais que ca peux paraitre long au vue de l’article, mais bon… c’est la première fois pour moi ce genre de chose, et j’ai certainement pas fais comme il le fallait..
Mais si vous regardez le code source, vous verrez que c’est enfantin … surtout comparé à la méthode du « je code l’interface graphique au lieu de la dessiner ! » xD
En tout, le projet fais 6.1Ko… Et il doit y avoir a peine 50 lignes.

Je pense donc, qu’il est clairement plus interessant de coder avec Glade, rien que pour la facilité de Glade à modifier l’interface.
Surtout que vous n’avez pas à recompiler le code, chose à faire avec l’autre méthode !

Voici le projet au complet pour vous aider: helloproject.tar.gz

PHPSvnGraph 0.1

30 mars 2009

Voici la toute première version de mon nouveau projet.

Son but

Le but de cet outil est de générer un graphique clair de ce qui s’est passé sur le repository pour un projet précis.
J’ai donc essayé de faire une représentation simple pour que d’un coup d’oeil vous poussiez voire où vous en êtes dans votre projet, et qui fait quoi.
( Sous la condition que vous et votre équipe remplissiez comme il faut les champs de subversions comme le champ auteur etc … ).

Pourquoi en PHP !?

Tout simplement pour aller vite.
C’est un langage orienté objet simple d’utilisation ( Pas de typage… Ouais, faut pas codé comme un barbare ! :p )
Mais je ne compte pas le faire en PHP indéfiniment.

A quoi ca ressemble ?

Où puis-je l’essayer ?

Pour le moment, seule la version subversion est disponible !
http://svn.zedroot.org/PHPSvnGraph/

ZF + Designe Pattern MVC

20 mars 2009

Je bosse actuellement sur Zend Framework pour apprendre à m’en servir pour mes prochain sites.

Venant du C++ et de Java, j’ai tout de suite put apprécier le fonctionnement du framework. Par contre, je ne connaissais pas encore le Design Pattern MVC ( Modèle-Vue-Contrôleur ).

ash-mvc-architecture1.gif

ash-mvc-architecture1.gif

Ce schéma, représente ce Design Pattern.
Globalement, l’idée est bien représenter: TOUT passe par un contrôleur .

Encore un petit schéma pour la route, piqué sur le net, comme celui d’avant:

akelos_mvc-fr.png

akelos_mvc-fr.png

Grossièrement, le principe est de définir une action, que le contrôleur va comprendre, et va appeler un phtml ( dans le cas de Zend ) nommé comme cette dite action.

Donc, pour exemple, si j’ai l’URL http://localhost/index/ajouter le contrôleur IndexControleur.php sera appelé, contenant toutes les actions que l’index contient ( on peut dire, je pense, qu’une action représente un lien hypertexte ), puis c’est ajouterAction.phtml qui sera appelé pour afficher l’action.

Si vous connaissez la POO (Programmation Orienté Objet), l’architecture des dossiers du design pattern MVC coulera de source.
Elle consiste surtout à un dossier application, contenant les contrôleurs, les vues, les modèles, etc …, puis un dossier public pour l’index et le .htaccess pour l’URL rewrite (mod_rewrite d’apache ).

Maintenant que j’ai fais quelques pas avec le FrameWork Zend, et le Design pattern MVC, je trouve ce framework vraiment intéressant !
La construction de formulaires, comprenant sa validation; les Db Modèles; le système de contrôleurs; …

Il est certain que si vous maîtrisez ce framework, vous pourrez construire des sites web très rapidement, voire même des RIA ( Riche Internet Applications ) en un rien de temps !

Les gens qui pense que « Ce que j’écris est meilleur, plus fiable,… », comme le faisaient nos père, devient aujourd’hui une vaste connerie !
Les FrameWorks sont vraiment fais pour avancer, pour ne pas perdre de temps à ré-inventer la roue, surtout si elle à été faite presque à la perfection.
Il ne faut pas avoir peur de la « rigidité » d’un FrameWork… Bien souvent, ils sont largement flexible pour ne pas vous dérangez dans votre travail (une fois que l’on à appris à ce servir de ce dernier ! )
Sauf si vous ne connaissez que la programmation procédurale ….. :s