IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Cours GTK 2

Date de publication : 20 Février 2007



Les labels

Maintenant que nous savons créer une fenêtre, nous allons créer l'incontournable "Hello World!". Pour cela, nous allons utiliser le widget GtkLabel qui nous permet d'afficher du texte.

1. Création et affichage d'un label.

Nous allons maintenant voir comment créer un label, et comment l'insérer dans la fenêtre principale.

1.1 Création d'un label.

On crée un pointeur vers la structure GtkWidget.

Dans un premier temps, il faut déclarer le pointeur sur l'objet GtkLabel :

GtkWidget *pLabel;

Ensuite il faut initialiser cet objet. Pour cela, il n'existe qu'une seule fonction :

GtkWidget* gtk_label_new(const char* str);

Le paramètre str n'est autre que la chaîne de caractères qu'il faudra afficher.

Pour notre exemple, la ligne de code sera :

pLabel = gtk_label_new("Hello World!");

1.2 Insérer le texte dans la fenêtre.

Pour pouvoir afficher le texte, il faut insérer le widget pLabel dans la fenêtre principale (widget pWindow). Pour cela, nous allons utiliser le fait que le widget GtkWindow dérive du widget GtkContainer. L'atout principal d'un GtkContainer est, comme son nom le laisse entendre, qu'il peut contenir et afficher un autre widget. Les widgets de ce type sont appelés des conteneurs. Il faudra donc différencier deux types d'objets :

  • le widget conteneur (aussi appelé widget parent) ;
  • le widget contenu (aussi appelé widget enfant) qui pourra par la suite devenir lui-même un conteneur s'il possède les propriétés de GtkContainer.

Etudions donc maintenant la fonction qui nous servira à insérer un widget dans un widget conteneur :

void gtk_container_add(GtkContainer *container, GtkWidget *widget);

Le premier paramètre, container, est le widget conteneur dans lequel on veut insérer le widget widget qui lui est passé en deuxième paramètre. Le premier paramètre de cette fonction est de type GtkContainer, alors que les widgets conteneurs seront tous de type GtkWidget. Il faudra donc à nouveau utiliser une macro de conversion qui cette fois est GTK_CONTAINER().

Pour notre exemple, la ligne de code sera :

gtk_container_add(GTK_CONTAINER(pWindow), pLabel);

1.3 Afficher la fenêtre complète

Dans le chapitre précédent, nous avons utilisé la fonction gtk_widget_show pour afficher la fenêtre. Mais cette fonction n'affiche que la fenêtre et pas son contenu. Pour régler ce problème, il est tout à fait possible d'utiliser deux fois cette fonction (une première fois pour la fenêtre et deuxième fois pour le label). Mais cette solution peut s'avérer très lourde s'il y a beaucoup de widget à afficher.

La deuxième solution existante consiste à appeler cette fonction :

void gtk_widget_show_all(GtkWidget *widget);

Cette fonction affiche, bien sur, le widget widget mais aussi tous les widgets enfants qu'il inclut. Notre ligne de code sera donc :

gtk_widget_show_all(pWindow);

1.4 Programme exemple

#include <stdlib.h>
#include <gtk/gtk.h>

int main(int argc,char **argv)
{
    GtkWidget* pWindow;
    GtkWidget* pLabel;

    gtk_init(&argc,&argv);

    pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(pWindow), "Les labels");
    gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 200);

    /* Creation du label */
    pLabel=gtk_label_new("Hello World!");

    /* On ajoute le label a l'interieur de la fenetre */
    gtk_container_add(GTK_CONTAINER(pWindow), pLabel);

    /* Affichage de la fenetre et de tout ce qu'il contient */
    gtk_widget_show_all(pWindow);

    /* Connexion du signal
    /* On appelle directement la fonction de sortie de boucle */

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

    gtk_main();

    return EXIT_SUCCESS;
}

Résultat :

2. Les caractères accentués

Vous avez peut-être déjà essayé d'afficher du texte contenant des caractères tel que "é, è, à, …", et lors de l'exécution, votre texte ne s'affiche complètement. Nous allons maintenant voir le pourquoi du comment.

2.1 Application test

Pour vous montrer tout cela, nous allons reprendre l'exemple précédent en remplaçant " Hello Word " par " Texte à afficher ", et cela ne marche pas! En effet vous obtenez cela :

Et en plus sur la console, vous avez le message d'erreur suivant :
** (Label2.exe) : WARNING **: Invalid UTF8 string passed to pango_layout_set_text()

2.2 Comment ça marche ?

Pour afficher du texte, Gtk utilise la librairie Pango qui s'occupe du rendu et de l'affichage du texte. Le but de Pango est de permettre l'internationalisation des applications, et pour cela Pango utilise l'encodage UTF8. Ce charset est codée sur 16 bits, ce qui offre la possibilité d'afficher plus 65000 caractères, permettant ainsi d'afficher des caractères accentués et bien plus (ex : pour le grec, le chinois, ...).

Puisque Pango sait faire tout cela, pourquoi le test n'a-t-il pas fonctionné? Et bien, tout simplement parce que votre système d'exploitation n'utilise pas ce charset. Lorsque vous souhaitez afficher "Texte à afficher", Pango va avant tout vérifier l'encodage d'un caractère et si l'un de ces caractères n'est pas correct, Pango va arrêter son processus de rendu et envoyer un message d'erreur.

Le moyen le plus simple pour voir les effets d'une erreur d'encodage est de changer celui de votre navigateur. Modifiez les options de votre navigateur afin d'utiliser l'encodage UNICODE. Cette page web utilisant le charset iso-8859-1, les caractères accentués deviendront des carrés ou autre chose.

2.3 Solution

Une seule chose s'impose à nous : il faut convertir notre chaîne de caractère en UTF8. Pour cela, il faut utiliser une fonction de Glib qui est :

gchar* g_locale_to_utf8(const gchar *opsysstring, gsize len, gsize *bytes_read, gsize *bytes_written, GError **error);

La valeur de retour est le pointeur sur la chaîne de caractère fraîchement convertie. Si une erreur est survenue lors de la conversion, g_locale_to_utf8 renvoie NULL. Il faudra tout de même libérer le mémoire allouée par cette fonction lorsque la variable ne sera plus utile.

Le premier paramètre opsysstring est la chaîne de caractère à convertir et le second paramètre len correspond à la longueur de la chaîne. Ce paramètre sera en général égal à -1 (on laisse la bibliothèque calculer la longueur toute seule).

Les trois derniers paramètres sont utiles en cas d'erreur lors de la conversion. Tout d'abord bytes_read est le nombre d'octet qui ont été lus dans le texte à convertir, et bytes_writen le nombre d'octet qui ont été écris dans la nouvelle chaîne de caractères.

Le dernier paramètre error, donne plus de précision en cas d'erreur. Voici la liste des messages d'erreur possibles :

  • G_CONVERT_ERROR_NO_CONVERSION ;
  • G_CONVERT_ERROR_ILLEGAL_SEQUENCE ;
  • G_CONVERT_ERROR_FAILED ;
  • G_CONVERT_ERROR_PARTIAL_INPUT ;
  • G_CONVERT_ERROR_BAD_URI ;
  • G_CONVERT_ERROR_NOT_ABSOLUTE_PATH.

Pour notre exemple, nous n'allons pas utiliser les trois derniers paramètres. En cas d'erreur, il n'y aura donc aucun moyen d'avoir plus de précision sur l'erreur survenue.

2.4 Programme exemple

#include <stdlib.h>
#include <gtk/gtk.h>

int main(int argc,char **argv)
{
    GtkWidget* pWindow;
    GtkWidget* pLabel;
    gchar* sUtf8;

    gtk_init(&argc, &argv);

    pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(pWindow), "Les labels II");
    gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 200);

    /* Creation du label avec     g_locale_to_utf8 */
    sUtf8 = g_locale_to_utf8("Texte à afficher", -1, NULL, NULL, NULL);
    pLabel=gtk_label_new(sUtf8);
    g_free(sUtf8);

    /* On ajoute le label a l'interieur de la fenetre */
    gtk_container_add(GTK_CONTAINER(pWindow), pLabel);

    /* Affichage de la fenetre et de tout ce qu'il contient */
    gtk_widget_show_all(pWindow);

    /* Connexion du signal
    /* On appelle directement la fonction de sortie de boucle */

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

    gtk_main();

    return EXIT_SUCCESS;
}

Résultat :

3. Formatage du texte

Nous allons maintenant voir comment modifier l'apparence de notre texte (police, couleur, …).
Pour notre application test, nous allons afficher une ligne en Courier gras taille 10, une ligne en Times New Roman italique bleu taille 12, et une ligne en Verdana souligné taille 16. Et tout cela centré (bien sûr).

3.1 Définition du format

Une fois encore, nous allons utiliser les propriétés de Pango (même si nous n'allons pas utiliser les fonctions de Pango directement).
Pour définir le format du texte, il suffit d'insérer des balises à l'intérieur même de notre texte. Pango s'occupe ensuite de rechercher les balises puis de formater le texte à notre convenance.

3.2 Les balises rapides

Les balises rapides servent à mettre le texte en gras, italique ou autre de manière très simple. Voici l'intégralité de ces balises :

Balise Action Exemple
<b> Met le texte en gras
<big> Augment légèrement la taille du texte
<i> Met le texte en italique
<s> Barre le texte
<sub> Met le texte en indice
<sup> Met le texte en exposant
<small> Diminue légèrement la taille du texte
<tt> Met le texte en télétype
<u> Souligne le texte

Pour utiliser ces balises, il suffit d'encadrer le texte à modifier des balises de formatage. Par exemple, pour mettre le texte en gras, il faudra entrer : "Normal vs <b>Gras</b>".

Mais cela ne suffit pas, il faut aussi dire que le texte utilise les balises Pango, ce qui est possible avec la fonction suivante :

void gtk_label_set_use_markup(GtkLabel *label, gboolean setting);

Il faut mettre le paramètre setting à TRUE, et le texte sera alors formaté en conséquence.

Un autre moyen de spécifier l'utilisation des balises, est d'utiliser cette fonction :

void gtk_label_set_markup(GtkLabel *label, const gchar *str);

Cette fonction dit à Pango qu'il faut utiliser les balises, mais elle modifie aussi le label en affichant la chaîne de caractères str (deuxième paramètre).

3.3 La balise <span>

Cette fois-ci, nous allons étudier la balise <span> en détail. Avec celle-ci, nous allons pouvoir changer la police de caractères, la couleur du texte et bien d'autres choses.

Cette balise s'utilise comme les précédentes si ce n'est qu'elle accepte des paramètres. Le tableau ci-dessous présente tous les paramètres et les effets sur le texte.

Paramètre Utilisation Exemple
font_family
Pour définir la police à utiliser. Si la valeur donnée à ce paramètre est incorrecte, la police par défaut (Sans Serif) sera utilisée.
Exemple : <span font_family=\"Courier New\">Courier New</span>
face
Identique à font_family
Exemple : <span face=\"Times New Roman\">Times New Roman</span>
size Pour définir la taille du texte (par défaut 10).
Exemple : <span size=\"12\">Taille 12</span>
style Pour définir le style du texte. Trois valeurs possibles : normal, oblique, italic.
Exemple : <span style=\"oblique\">Oblique</span>
font_desc Permet de combiner les paramètres précédents en un seul.
Exemple : <span font_desc=\"Courier New italic 12\">Courier New italic 12</span>
weight Permet de définir l'épaisseur des lettres. Les valeurs peuvent être ultralight, light, normal, bold, utrabold, heavy ou encore une valeur numérique. (Vous remarquerez qu'il n'y a que peu ou pas de différence).
Exemple : <span weight=\"bold\">Bold</span>
variant Pour définir si l'on veut du texte normal (normal) ou en petite majuscule (smallcaps).
Exemple : <span variant=\"smallcaps\">Smallcaps</span>
Afin de pourvoir l'utiliser, il faut avoir la police : nom smallcaps
 
stretch Permet d'étirer le texte. La valeur de ce paramètre peut être :
ultracondensed, extracondensed, condensed, semicondensed, normal, semiexpanded, expanded, extraexpanded, ultraexpanded.
Afin de pourvoir l'utiliser, il faut avoir la police : nom condensed (ou autre).
 
foreground Pour définir la couleur du texte. Il faut donner la valeur hexadécimale de la palette RVB.
Exemple : <span foreground=\"#FF0000\">Couleur Texte</span>
background Pour définir la couleur du fond. Il faut donner la valeur hexadécimale de la palette RVB.
Exemple : <span background=\"#FF0000\">Couleur Texte</span>
underline Pour souligner le texte.
Exemple : <span underline=\"double\">Double</span>
rise Pour déplacer le texte verticalement.  
strikethrough Pour barrer le texte.
Exemple : <span strikethrough=\"true\">Striketrough = "true"</span>
lang Pour indiquer la langue du texte.  

Tous ces paramètres peuvent être mis à l'intérieur d'une seule balise <span>.

3.4 Alignement du texte

Maintenant, nous allons voir comment aligner notre texte, lorsque celui-ci comporte plusieurs lignes. Comme d'habitude, GTK+ nous fourni une fonction très simple d'utilisation :

void gtk_label_set_justify (GtkLabel *label, GtkJustification jtype);

Le paramètre jtype correspond à l'alignement du texte et peut prendre une de ces valeurs :

  • GTK_JUSTIFY_LEFT pour aligner le texte à gauche (par défaut) ;
  • GTK_JUSTIFY_RIGHT pour aligner le texte à droite ;
  • GTK_JUSTIFY_CENTER pour centrer le texte ;
  • GTK_JUSTIFY_FILL pour justifier le texte.

Au contraire, pour obtenir l'alignement du texte, la fonction est :

GtkJustification gtk_label_get_justify (GtkLabel *label);

3.5 Programme exemple.

#include <stdlib.h>
#include <gtk/gtk.h>

int main(int argc,char **argv)
{
    GtkWidget* pWindow;
    GtkWidget* pLabel;
    gchar* sUtf8;

    gtk_init(&argc,&argv);

    pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(pWindow),"Les labels III");
    gtk_window_set_default_size(GTK_WINDOW(pWindow),320,200);

    /* Creation du label avec g_locale_to_utf8 */
    pLabel=gtk_label_new(NULL);

    /* On utilise les balises */
    sUtf8 = g_locale_to_utf8("<span face=\"Courier New\"><b>Courier New 10 Gras</b></span>\n"
        "<span font_desc=\"Times New Roman italic 12\" foreground=\"#0000FF\">Times New Roman 12 Italique</span>\n"
        "<span face=\"Sans\" size=\"16\"><u>Sans 16 Souligné</u></span>",
        -1, NULL, NULL, NULL);
    gtk_label_set_markup(GTK_LABEL(pLabel), sUtf8);
    g_free(sUtf8);

    /* On centre le texte */
    gtk_label_set_justify(GTK_LABEL(pLabel), GTK_JUSTIFY_CENTER);

     /* On ajoute le label a l'interieur de la fenetre */
     gtk_container_add(GTK_CONTAINER(pWindow),pLabel);

     /* Affichage de la fenetre et de tout ce qu'il contient */
    gtk_widget_show_all(pWindow);

    /* Connexion du signal
    /* On appelle directement la fonction de sortie de boucle */

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

     gtk_main();

    return EXIT_SUCCESS;
}

Résultat :

4. En savoir plus :

4.1 Fonctions documentées

void gtk_label_set_text (GtkLabel* label, const char* str)
void gtk_label_set_label(GtkLabel* label, const gchar* str)
Ces deux fonctions permettent de changer le texte d'un GtkLabel.
Entrée(s) :
label : objet GtkLabel.
str : nouveau texte.
Sortie : rien.
G_CONST_RETURN gchar* gtk_label_get_text(GtkLabel* label)
G_CONST_RETURN gchar* gtk_label_get_label(GtkLabel* label)
Permet de recevoir l'adresse de la chaîne de caractère affichée par le label.
Entrée(s) :

label
: objet GtkLabel.
Sortie : const gchar*.
gboolean gtk_label_get_use_markup (GtkLabel *label);
Permet de savoir si un label utilise les balises de formatages Pango.
Entrée(s) :

label
: objet GtkLabel.
Sortie : gboolean, si oui TRUE, sinon FALSE.

4.2 Fonctions non documentées

void gtk_label_set_attributes (GtkLabel *label, PangoAttrList *attrs);
void gtk_label_set_markup_with_mnemonic(GtkLabel *label, const gchar *str);
void gtk_label_set_pattern (GtkLabel *label, const gchar *pattern);
guint gtk_label_parse_uline (GtkLabel *label, const gchar *string);
void gtk_label_set_line_wrap (GtkLabel *label, gboolean wrap);
void gtk_label_get_layout_offsets (GtkLabel *label, gint *x, gint *y);
guint gtk_label_get_mnemonic_keyval (GtkLabel *label);
gboolean gtk_label_get_selectable (GtkLabel *label);
GtkWidget* gtk_label_new_with_mnemonic (const char *str);
void gtk_label_select_region (GtkLabel *label, gint start_offset, gint end_offset);
void gtk_label_set_mnemonic_widget (GtkLabel *label, GtkWidget *widget);
void gtk_label_set_selectable (GtkLabel *label, gboolean setting);
void gtk_label_set_text_with_mnemonic(GtkLabel *label, const gchar *str);
PangoAttrList* gtk_label_get_attributes (GtkLabel *label);
PangoLayout* gtk_label_get_layout (GtkLabel *label);
gboolean gtk_label_get_line_wrap (GtkLabel *label);
GtkWidget* gtk_label_get_mnemonic_widget (GtkLabel *label);
gboolean gtk_label_get_selection_bounds (GtkLabel *label, gint *start, gint *end);
gboolean gtk_label_get_use_underline (GtkLabel *label);
void gtk_label_set_use_underline (GtkLabel *label, gboolean setting);

Date de mise à jour : 17 mai 2003