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

Cours GTK 2

Date de publication : 20 Février 2007



Les pages à onglets

Nous allons étudier dans ce chapitre les pages à onglets qui sont souvent utilisés dans les fenêtres de configuration. Pour cela nous allons utiliser le widget GtkNotebook qui dérive du widget GtkContainer.

1. Utilisation du widget GtkNotebook.

1.1 Création.

Pour ne pas changer la création du widget en lui-même est très simple :

GtkWidget* gtk_notebook_new(void);

Maintenant que notre widget est créé, nous allons lui ajouter des pages.

1.2 Insertion de pages.

Nous avons là aussi trois fonctions qui restent très classiques :

void gtk_notebook_append_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
void gtk_notebook_prepend_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);
void gtk_notebook_insert_page (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, gint position);

La première fonction ajoute une nouvelle page à onglet à la suite des autres, la deuxième fonction l'ajoute au début, et la dernière l'ajoute à une position particulière.

Le premier paramètre, notebook, est bien sûr le GtkNotebook dans lequel nous voulons ajouter la page. Il faudra utiliser la macro de conversion GTK_NOTEBOOK().
Le second, child, est le widget qui sera insérer dans la nouvelle page, et le troisième (tab_label) le widget qui sera affiché dans l'onglet.
La troisième fonction demande un paramètre supplémentaire (position) qui est la position à laquelle il faut ajouter la page. Si la valeur n'est pas correcte (négative ou trop grande) la page sera ajoutée à la suite des autres.

1.3 Gestion des pages.

Nous allons maintenant voir les fonctions qui permettent de connaître le nombre de page, la page en cours et d'autres fonctions.

Tout d'abord, la fonction suivante permet de connaître le nombre total de pages contenus dans le GtkNotebook :

gint gtk_notebook_get_n_pages(GtkNotebook *notebook);

Ensuite, pour connaître le numéro de la page courante, nous avons cette fonction :

gint gtk_notebook_get_current_page (GtkNotebook *notebook);

Par contre pour connaître le numéro d'une autre page que la courante, il faudra utiliser cette fonction :

gint gtk_notebook_page_num (GtkNotebook *notebook, GtkWidget *child);

Cette fonction permet d'obtenir le numéro de la page contenant le widget child, ce qui impose donc d'avoir garder une trace de ce widget pour pouvoir utiliser cette fonction.

Avec ce numéro de page, nous allons pouvoir récupérer un pointeur sur le widget qui est contenu dans la page avec cette fonction :

GtkWidget* gtk_notebook_get_nth_page (GtkNotebook *notebook, gint page_num);

Ou bien nous allons pouvoir tout simplement supprimer la page :

void gtk_notebook_remove_page (GtkNotebook *notebook, gint page_num);

Et pour terminer, voici trois fonctions de navigation :

void gtk_notebook_next_page (GtkNotebook *notebook);
void gtk_notebook_prev_page (GtkNotebook *notebook);
void gtk_notebook_set_current_page (GtkNotebook *notebook, gint page_num);

La première fonction passe de la page courante à la page suivante. Si la dernière page est déjà affichée, il ne se passera rien.
La deuxième fonction, elle, passe de la page courante à la page précédente. Bien entendu, si la page courante est déjà la première cette fonction n'aura aucun effet.
La dernière fonction quant à elle passe directement à une page précise. Si la valeur de page_num est négative, nous passerons à la dernière page, par contre si cette valeur est trop grande, aucune action ne sera faite.

1.4 Gestion des labels.

Nous allons maintenant voir comment modifier ou récupérer le label d'une page. Attention pour chacune de ces fonctions, il faut connaître le widget contenu dans la page.

Tout d'abord, pour récupérer le label de la page, il existe deux fonctions différentes :

G_CONST_RETURN gchar* gtk_notebook_get_tab_label_text(GtkNotebook *notebook, GtkWidget *child);
GtkWidget* gtk_notebook_get_tab_label (GtkNotebook *notebook, GtkWidget *child);

La première fonction renvoie directement le label de la page sous la forme d'un gchar*. Cette fonction ne fonctionnera correctement uniquement si le label de la page est un GtkLabel, car comme nous l'avons lors de l'étude des fonctions d'insertion des pages, il est possible de définir le label comme autre chose qu'un GtkLabel. Dans ce cas, il faut utiliser la deuxième fonction qui elle renvoie le widget qui a été utilisé lors de la création.

Pour définir un nouveau label pour une page, il existe là aussi deux fonctions :

void gtk_notebook_set_tab_label_text (GtkNotebook *notebook, GtkWidget *child, const gchar *tab_text);
void gtk_notebook_set_tab_label (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label);

La première fonction permet de définir un label de type GtkLabel. Cette fonction s'occupe de la création du GtkLabel et de son insertion dans l'onglet de la page. La deuxième fonction permet d'insérer n'importe quel widget dans l'onglet, comme pour les fonctions de création. Dans les deux cas, si les paramètres tab_text ou tab_label sont définis comme NULL, le label de la page sera "Page y", y étant le numéro de la page.

1.5 Modification des propriétés du GtkNotebook

Nous allons maintenant voir comment modifier trois des propriétés d'un GtkNotebook. Tout d'abord voyons comment gérer la position des onglets :

void gtk_notebook_set_tab_pos (GtkNotebook *notebook, GtkPositionType pos);
GtkPositionType gtk_notebook_get_tab_pos (GtkNotebook *notebook);

La première fonction permet de modifier la position des onglets. C'est le paramètre pos qui définit sa position, et il doit prendre une des valeurs suivantes :

  • GTK_POS_LEFT pour les mettre à gauche ;
  • GTK_POS_RIGHT pour les mettre à droite ;
  • GTK_POS_TOP pour les mettre en haut ;
  • GTK_POS_BOTTOM pour les mettre en bas.

La deuxième fonction permet au contraire de connaître la position des onglets. La valeur de retour est obligatoirement une des quatre valeurs précédentes.

Ensuite nous allons pouvoir définir si les onglets doivent s'afficher ou pas avec ces fonctions :

void gtk_notebook_set_show_tabs (GtkNotebook *notebook, gboolean show_tabs);
gboolean gtk_notebook_get_show_tabs (GtkNotebook *notebook);

Si nous voulons modifier ce paramètre, il faut utiliser la première fonction en mettant le paramètre show_tabs à TRUE pour les afficher et à FALSE dans le cas contraire. La deuxième fonction permet quant à elle de connaître l'état de cette propriété.

Et enfin, pour terminer nous allons voir comment ajouter deux boutons de navigation à la fin des onglets, pour le cas où il y aurait trop d'onglets à afficher :

void gtk_notebook_set_scrollable (GtkNotebook *notebook, gboolean scrollable);
gboolean gtk_notebook_get_scrollable (GtkNotebook *notebook);

Si nous mettons le paramètre scrollable de la première fonction à TRUE, deux boutons de navigation apparaîtront et une partie seulement des onglets sera affichée. Pour accéder aux autres onglets il faudra utiliser ces nouveaux boutons.
Bien entendu, la deuxième fonction permet de savoir si les boutons de navigation sont présents ou pas.

1.6. Exemple

Nous allons créer un programme qui insèrera un GtkNotebook de 8 pages dans une fenêtre. Chaque page contiendra uniquement un label "Je suis le GtkLabel numero x". Il y a aussi un bouton qui permettra d'afficher les informations de la page sélectionnée dans une boîte de dialogue.

1.7. Programme exemple.

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

void OnButton(GtkWidget *pButton, gpointer data);

int main(int argc, char **argv)
{
    GtkWidget *pWindow;
    GtkWidget *pVBox;
    GtkWidget *pNotebook;
    GtkWidget *pButton;
    gint i;

    gtk_init(&argc,&argv);

    pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(pWindow), "GtkNotebook");
    gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 200);
    g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    pVBox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(pWindow), pVBox);

    pButton = gtk_button_new_with_label("Informations");
    gtk_box_pack_start(GTK_BOX(pVBox), pButton, FALSE, FALSE, 0);

    /* Creation du GtkNotebook */
    pNotebook = gtk_notebook_new();
    gtk_box_pack_start(GTK_BOX(pVBox), pNotebook, TRUE, TRUE, 0);
    /* Position des onglets : en bas */
    gtk_notebook_set_tab_pos(GTK_NOTEBOOK(pNotebook), GTK_POS_BOTTOM);
    /* Ajout des boutons de navigation */
    gtk_notebook_set_scrollable(GTK_NOTEBOOK(pNotebook), TRUE);

    for(i = 0 ; i < 8 ; ++i)
    {
        GtkWidget *pLabel;
        GtkWidget *pTabLabel;
        gchar *sLabel;
        gchar *sTabLabel;

        sLabel = g_strdup_printf("Je suis le GtkLabel numero %d", i);
        sTabLabel = g_strdup_printf("Page %d", i);

        /* Creation des differents GtkLabel */
        pLabel = gtk_label_new(sLabel);
        pTabLabel = gtk_label_new(sTabLabel);

        /* Insertion de la page */
        gtk_notebook_append_page(GTK_NOTEBOOK(pNotebook), pLabel, pTabLabel);

        g_free(sLabel);
        g_free(sTabLabel);
    }

    g_signal_connect(G_OBJECT(pButton), "clicked", G_CALLBACK(OnButton), pNotebook);

    gtk_widget_show_all(pWindow);

    gtk_main();

    return EXIT_SUCCESS;
}

void OnButton(GtkWidget *pButton, gpointer data)
{
    GtkWidget *pDialog;
    GtkWidget *pChild;
    gint iPageNum;
    const gchar *sLabel;
    const gchar *sTabLabel;
    gchar *sDialogText;

    /* Recuperation de la page active */
    iPageNum = gtk_notebook_get_current_page(GTK_NOTEBOOK(data));
    /* Recuperation du widget enfant */
    pChild = gtk_notebook_get_nth_page(GTK_NOTEBOOK(data), iPageNum);

    /* Recuperation du label */
    sLabel = gtk_label_get_text(GTK_LABEL(pChild));
    /* Recuperation du label de l'onglet */
    sTabLabel = gtk_notebook_get_tab_label_text(GTK_NOTEBOOK(data), pChild);

    /* Creation du label de la boite de dialogue */
    sDialogText = g_strdup_printf("C'est la page %d\n"
        "Le label est \"%s\"\n"
        "Le label de l'onglet est \"%s\"\n",
        iPageNum,
        sLabel,
        sTabLabel);

    pDialog = gtk_message_dialog_new (NULL,
        GTK_DIALOG_MODAL,
        GTK_MESSAGE_INFO,
        GTK_BUTTONS_OK,
        sDialogText);

    gtk_dialog_run(GTK_DIALOG(pDialog));

    gtk_widget_destroy(pDialog);

    g_free(sDialogText);
}

Résultat :

2. Ajouter un menu de navigation.

Nous allons maintenant voir comment ajouter un menu qui apparaîtra lorsque nous ferons un clic droit de la sourie sur une page du GtkNotebook. Cela ne se fait pas par le biais du widget GtkMenu mais directement avec les fonctions de GtkNotebook.

2.1 Création.

Pour avoir un GtkNotebook avec un menu de navigation, trois nouvelles fonctions de création sont disponibles :

void gtk_notebook_append_page_menu (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, GtkWidget *menu_label);
void gtk_notebook_prepend_page_menu (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, GtkWidget *menu_label);
void gtk_notebook_insert_page_menu (GtkNotebook *notebook, GtkWidget *child, GtkWidget *tab_label, GtkWidget *menu_label, gint position);

La majorité des paramètres de ces trois fonctions sont identiques sauf pour le paramètre menu_label qui est le widget qui sera affiché dans le menu de navigation. Le fonctionnement des ces fonctions est le même que pour les fonctions sans menu.

Ensuite pour activer ou désactiver la possibilité d'afficher le menu il faut utiliser une de ces fonctions :

void gtk_notebook_popup_enable (GtkNotebook *notebook);
void gtk_notebook_popup_disable (GtkNotebook *notebook);

La première fonction permet d'afficher le menu, et la deuxième au contraire empêche le menu de s'afficher.

2.2 Gestion des labels.

Comme pour les onglets, il existe des fonctions pour gérer les labels du menu. Pour récupérer le widget ou directement le texte du menu, nous avons ces deux fonctions :

GtkWidget* gtk_notebook_get_menu_label (GtkNotebook *notebook, GtkWidget *child);
G_CONST_RETURN gchar* gtk_notebook_get_menu_label_text(GtkNotebook *notebook, GtkWidget *child);

La première fonction renvoie donc le widget, quel qu'il soit, qui est à l'intérieur du menu alors que la seconde renvoie le texte du menu si l'élément est de type GtkLabel.

Et pour changer le label du menu, il existe ces deux fonctions :

void gtk_notebook_set_menu_label (GtkNotebook *notebook, GtkWidget *child, GtkWidget *menu_label);
void gtk_notebook_set_menu_label_text(GtkNotebook *notebook, GtkWidget *child, const gchar *menu_text);

La première accepte n'importe quel type de widget, tandis que la seconde crée elle-même un widget de type GtkLabel avec comme texte la valeur du paramètre menu_text.

2.3 Exemple.

Nous allons reprendre le même exemple que pour la première partie en rajoutant le menu de navigation.

2.4 Programme exemple.

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

void OnButton(GtkWidget *pButton, gpointer data);

int main(int argc, char **argv)
{
    GtkWidget *pWindow;
    GtkWidget *pVBox;
    GtkWidget *pNotebook;
    GtkWidget *pButton;
    gint i;

    gtk_init(&argc,&argv);

    pWindow = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(pWindow), "GtkNotebook");
    gtk_window_set_default_size(GTK_WINDOW(pWindow), 320, 200);
    g_signal_connect(G_OBJECT(pWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);

    pVBox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(pWindow), pVBox);

    pButton = gtk_button_new_with_label("Informations");
    gtk_box_pack_start(GTK_BOX(pVBox), pButton, FALSE, FALSE, 0);

    /* Creation du GtkNotebook */
    pNotebook = gtk_notebook_new();
    gtk_box_pack_start(GTK_BOX(pVBox), pNotebook, TRUE, TRUE, 0);
    /* Position des onglets : en bas */
    gtk_notebook_set_tab_pos(GTK_NOTEBOOK(pNotebook), GTK_POS_BOTTOM);
    /* Ajout des boutons de navigation */
    gtk_notebook_set_scrollable(GTK_NOTEBOOK(pNotebook), TRUE);

    for(i = 0 ; i < 8 ; ++i)
    {
        GtkWidget *pLabel;
        GtkWidget *pTabLabel;
        GtkWidget *pMenuLabel;
        gchar *sLabel;
        gchar *sTabLabel;
        gchar *sMenuLabel;

        sLabel = g_strdup_printf("Je suis le GtkLabel numero %d", i);
        sTabLabel = g_strdup_printf("Page %d", i);
        sMenuLabel = g_strdup_printf("Menu -> Page %d", i);

        /* Creation des differents GtkLabel */
        pLabel = gtk_label_new(sLabel);
        pTabLabel = gtk_label_new(sTabLabel);
        pMenuLabel = gtk_label_new(sMenuLabel);

        /* Insertion de la page */
        gtk_notebook_append_page_menu(GTK_NOTEBOOK(pNotebook), pLabel, pTabLabel, pMenuLabel);

        g_free(sLabel);
        g_free(sTabLabel);
        g_free(sMenuLabel);
    }
    /* Activation du menu popup */
    gtk_notebook_popup_enable(GTK_NOTEBOOK(pNotebook));

    g_signal_connect(G_OBJECT(pButton), "clicked", G_CALLBACK(OnButton), pNotebook);

    gtk_widget_show_all(pWindow);

    gtk_main();

    return EXIT_SUCCESS;
}

void OnButton(GtkWidget *pButton, gpointer data)
{
    GtkWidget *pDialog;
    GtkWidget *pChild;
    gint iPageNum;
    const gchar *sLabel;
    const gchar *sTabLabel;
    const gchar *sMenuLabel;
    gchar *sDialogText;

    /* Recuperation de la page active */
    iPageNum = gtk_notebook_get_current_page(GTK_NOTEBOOK(data));
    /* Recuperation du widget enfant */
    pChild = gtk_notebook_get_nth_page(GTK_NOTEBOOK(data), iPageNum);

    /* Recuperation du label */
    sLabel = gtk_label_get_text(GTK_LABEL(pChild));
    /* Recuperation du label de l'onglet */
    sTabLabel = gtk_notebook_get_tab_label_text(GTK_NOTEBOOK(data), pChild);
    /* Recuperation du label du menu pop-up */
    sMenuLabel = gtk_notebook_get_menu_label_text(GTK_NOTEBOOK(data), pChild);

    /* Creation du label de la boite de dialogue */
    sDialogText = g_strdup_printf("C'est la page %d\n"
        "Le label est \"%s\"\n"
        "Le label de l'onglet est \"%s\"\n"
        "Le label du menu est \"%s\"\n",
        iPageNum,
        sLabel,
        sTabLabel,
        sMenuLabel);

    pDialog = gtk_message_dialog_new (NULL,
        GTK_DIALOG_MODAL,
        GTK_MESSAGE_INFO,
        GTK_BUTTONS_OK,
        sDialogText);

    gtk_dialog_run(GTK_DIALOG(pDialog));

    gtk_widget_destroy(pDialog);

    g_free(sDialogText);
}

Résultat :

3. En savoir plus.

3.1. Les signaux.

change-current-page
Prototype fonction callback : void user_function(GtkNotebook *notebook, gint arg1, gpointer user_data);
focus-tab
Prototype fonction callback : gboolean user_function(GtkNotebook *notebook, GtkNotebookTab arg1, gpointer user_data);
move-focus-out
Prototype fonction callback : void user_function(GtkNotebook *notebook, GtkDirectionType arg1, gpointer user_data);
select-page
Prototype fonction callback : gboolean user_function(GtkNotebook *notebook, gboolean arg1, gpointer user_data);
switch-page
Prototype fonction callback : void user_function(GtkNotebook *notebook, GtkNotebookPage *page, guint page_num, gpointer user_data);

3.2. Fonctions non documentées.

void gtk_notebook_reorder_child (GtkNotebook *notebook, GtkWidget *child, gint position);
void gtk_notebook_set_show_border (GtkNotebook *notebook, gboolean show_border);
gboolean gtk_notebook_get_show_border (GtkNotebook *notebook);
void gtk_notebook_query_tab_label_packing(GtkNotebook *notebook, GtkWidget *child, gboolean *expand, gboolean *fill, GtkPackType *pack_type);
void gtk_notebook_set_tab_label_packing(GtkNotebook *notebook, GtkWidget *child, gboolean expand, gboolean fill, GtkPackType pack_type);

Date de mise à jour : 07 juin 2003