Outils pour utilisateurs

Outils du site


issue223:gtk4

In the previous article a contact class which inherited from GObject was created and used to add some fictitious contacts to a GListStore so that they could be viewed using GtkColumnView. This article shows how to expand the application into a simple address book. This requires that a new contact can be created and a selected contact deleted. A contacts list needs to be maintained which can be automatically saved to disk and opened when the application is restarted. A screenshot of the application is shown below which has been developed using Ubuntu 24.04. Again fictitious individuals, Mr Jellyfish, Mr Puffin, Mrs Fossa and Mr Numbat named after Ubuntu releases will be used. The full source code for this project and can be downloaded using the web link: https://github.com/crispinprojects/fullcircle Open and view the files person-contact.h, person-contact.c and main.c file to follow the explanation below. The main.c file is updated from the last article.

Dans l'article précédent, une classe de contact héritant de GObject a été créée et utilisée pour ajouter des contacts fictifs à un GListStore afin de pouvoir les visualiser avec GtkColumnView. Cet article explique comment étendre l'application pour en faire un carnet d'adresses simple. Cela nécessite de pouvoir créer un nouveau contact et supprimer un contact sélectionné. Une liste de contacts doit être gérée ; elle doit pouvoir être automatiquement enregistrée sur le disque et s'ouvrir au redémarrage de l'application.

Une capture d'écran de l'application, développée sous Ubuntu 24.04, est présentée ci-dessous. On y retrouve des personnages fictifs : M. Jellyfish, M. Puffin, Mme Fossa et M. Numbat, nommés d'après des versions d'Ubuntu.

Le code source complet de ce projet est disponible au téléchargement à l'adresse suivante : https://github.com/crispinprojects/fullcircle

Ouvrez et consultez les fichiers person-contact.h, person-contact.c et main.c pour suivre les explications ci-dessous. Le fichier main.c a été mis à jour depuis l'article précédent.

Saving Contacts A way is needed to save contacts stored in the GListStore so that when the application is closed data has been saved to disk. In this example contact details will be saved to a .csv file. The extension “csv” stands for comma-separated value. With a .csv file each line in the file represents a contact record and the values (e.g. the name, email and phone fields) within each record are separated by commas. This format is easily viewed using a text editor or spreadsheet. However, in a data-intensive system a database would be used as these are more efficient. With a .csv file all the data has to be read in before it can be used but with a database a query can be made to read in a portion of the data that is required. The code for saving a GListStore of contacts to a .csv file is shown on the next page. GFile is an identifier for a file and is constructed using g_file_new_for_path() which takes one parameter, a string containing the path for the file to be opened. In this case a file called “contacts.csv” is saved to the current working directory. A data output stream is created for writing data directly to a file output stream. This is done using GDataOutputStream and GFileOutputStream. The code iterates over the store getting each item from the store, extracting the name, email and phone values using g_object_get() and then concatenates these to a single line of text separating each value with a comma. Each line is then saved using GDataOutputStream.

Enregistrement des contacts

Il est nécessaire de sauvegarder les contacts stockés dans GListStore afin que les données soient enregistrées sur le disque à la fermeture de l'application. Dans cet exemple, les informations de contact seront enregistrées dans un fichier .csv. L'extension « .csv » signifie « comma-separated value » (valeurs séparées par des virgules). Dans un fichier .csv, chaque ligne représente une fiche contact et les valeurs (nom, adresse e-mail et numéro de téléphone, par exemple) sont séparées par des virgules. Ce format est facilement visualisable avec un éditeur de texte ou un tableur. Cependant, pour un système traitant un grand nombre de données, une base de données est préférable car elle est plus performante. Avec un fichier .csv, toutes les données doivent être chargées avant utilisation, tandis qu'avec une base de données, une requête permet de charger uniquement les données nécessaires.

Le code permettant d'enregistrer les contacts d'un GListStore dans un fichier .csv est présenté à la page suivante. GFile est un identifiant de fichier, créé à l'aide de la fonction g_file_new_for_path() qui prend un paramètre : une chaîne de caractères contenant le chemin d'accès au fichier à ouvrir. Dans ce cas, un fichier nommé « contacts.csv » est enregistré dans le répertoire de travail courant. Un flux de sortie de données est créé pour écrire les données directement dans un flux de sortie de fichier. Ceci est réalisé à l'aide de GDataOutputStream et GFileOutputStream. Le code parcourt la base de données, récupérant chaque élément, en extrayant le nom, l'adresse e-mail et le numéro de téléphone à l'aide de g_object_get(), puis en les concaténant sur une seule ligne de texte, chaque valeur étant séparée par une virgule. Chaque ligne est ensuite enregistrée à l'aide de GDataOutputStream.

Creating New Contacts A new button called button_new_contact is created within the activate() function and then added to the window header. The g_signal_connect() function connects the button clicked signal to the callback called “callbk_new_contact” using the store as the gpointer parameter. GtkWidget *button_new_contact; button_new_contact = gtk_button_new_with_label(“New Contact”); g_signal_connect(button_new_contact, “clicked”, G_CALLBACK(callbk_new_contact), store); Within “callbk_new_contact” a dialog window is created and entry widgets are used for capturing the contact name, email and phone. Inspecting the code in the download shows that the positioning of widgets is handled with a box container. Widgets are appended to a box container which is a child of the dialog window. Pressing the “Add Contact” button invokes the callback called “callbk_add_new_contact”.

Création de nouveaux contacts

Un nouveau bouton nommé « button_new_contact » est créé dans la fonction activate() puis ajouté à l'en-tête de la fenêtre. La fonction g_signal_connect() connecte le signal de clic du bouton à la fonction de rappel callbk_new_contact en utilisant « store » comme paramètre gpointer.

GtkWidget *button_new_contact;

button_new_contact = gtk_button_new_with_label(“Nouveau contact”);

g_signal_connect(button_new_contact, “clicked”, G_CALLBACK(callbk_new_contact), store);

Dans callbk_new_contact, une boîte de dialogue est créée et des champs de saisie permettent de recueillir le nom, l'adresse e-mail et le numéro de téléphone du contact.

L'examen du code source montre que le positionnement des champs est géré par un conteneur de type Box. Les champs sont ajoutés à ce conteneur, qui est un enfant de la boîte de dialogue. Appuyer sur le bouton « Ajouter un contact » déclenche la fonction de rappel appelée « callbk_add_new_contact ».

The function g_object_set_data() allows an association to be made between the “button_add” and the entry called “entry_name” using the key parameter named “entry-name-key” as shown below. g_object_set_data(G_OBJECT(button_add), “entry-name-key”,entry_name); This allows the GtkWidget pointer called entry_name to be obtained in the add new contact callback using the code line shown below. GtkWidget *entry_name = g_object_get_data(G_OBJECT(button), “entry-name-key”); The same approach is used to make associations between the “button_add” and the email and phone entries. A new contact is created using g_object_new(). Then g_object_set() is used to set the values for the person name, email address and phone details from the text retrieved from the entry widgets. The code snip below shows how this is done.

La fonction g_object_set_data() permet d'associer le bouton « Ajouter » à l'entrée nommée « entry_name » grâce au paramètre clé « entry-name-key », comme illustré ci-dessous.

g_object_set_data(G_OBJECT(button_add), “entry-name-key”,entry_name);

Ceci permet d'obtenir le pointeur entry_name du widget GtkWidget dans la fonction de rappel d'ajout de contact, grâce à la ligne de code ci-dessous.

GtkWidget *entry_name = g_object_get_data(G_OBJECT(button), “entry-name-key”);

La même approche est utilisée pour associer le bouton « Ajouter » aux champs email et phone.

Un nouveau contact est créé à l'aide de g_object_new(). Ensuite, g_object_set() est utilisé pour définir les valeurs du nom, de l'adresse e-mail et du numéro de téléphone à partir du texte récupéré des widgets d'entrée. L'extrait de code ci-dessous montre comment cela se fait.

PersonContact *contact_new= g_object_new(PERSON_TYPE_CONTACT,0); g_object_set (contact_new, “name”, name, NULL); g_object_set (contact_new, “email”, email, NULL); g_object_set (contact_new, “phone”, phone_str, NULL); g_list_store_append(store,contact_new); save_contacts(store); The new contact is appended to the GListStore and the “save_contacts()” method is called to update the saved contacts. Opening Contacts When the application is closed the contacts remain saved in the “contacts.csv” file located in the working directory. When the application is restarted a method is needed within activate() to open the saved contacts and load them into a GListStore so that they can be displayed using the GtkColumnView widget. Inspecting the code in the download shows that this is done using the open_contacts() method which returns a pointer to a GListStore. The g_file_read() function is used with the GFile pointer to open the “contacts.csv” file for reading. The “contacts.csv” file is assumed to be located in the working directory. A GFileInputStream is used to read the contents of the file. A check is made to ensure that the file stream exists and, if not, NULL is returned.

PersonContact *contact_new= g_object_new(PERSON_TYPE_CONTACT,0);

g_object_set (contact_new, “name”, name, NULL);

g_object_set (contact_new, “email”, email, NULL);

g_object_set (contact_new, “phone”, phone_str, NULL);

g_list_store_append(store,contact_new);

save_contacts(store);

Le nouveau contact est ajouté à la GListStore et la méthode « save_contacts() » est appelée pour mettre à jour les contacts enregistrés.

Ouvrir des contacts

À la fermeture de l'application, les contacts restent enregistrés dans le fichier « contacts.csv » situé dans le répertoire de travail. Au redémarrage de l'application, une méthode est nécessaire dans la fonction activate() pour ouvrir les contacts enregistrés et les charger dans un GListStore afin qu'ils puissent être affichés à l'aide du widget GtkColumnView. L'examen du code téléchargé montre que cela est réalisé grâce à la méthode open_contacts(), qui renvoie un pointeur vers un GListStore.

La fonction g_file_read() est utilisée avec le pointeur GFile pour ouvrir le fichier « contacts.csv » en lecture. Ce fichier est supposé se trouver dans le répertoire de travail. GFileInputStream est utilisé pour lire le contenu du fichier. Une vérification est effectuée pour s'assurer de l'existence du flux de fichiers ; si ce n'est pas le cas, la valeur NULL est renvoyée.

A GListStore pointer called store is declared and g_list_store_new() is used to create a new GListStore with items of type G_TYPE_OBJECT which is the fundamental type for GObject. Then g_data_input_stream_new() is used to create a new data input stream for the file input stream. This allows g_data_input_stream_read_line() to be used to read a line from the data input stream. A while loop is used to read the data lines one by one from the “contacts.csv” file. The C string token function called strtok() is used to break each line string into pieces representing the name, email and phone fields. Each piece of data is separated by a comma and so a comma is used as the delimiter i.e. break character. With strtok() the first parameter is the string and the second is the delimiter and it returns a char pointer to the occurrence of each piece of data. There are three pieces of data which are the field’s name, email and phone and so strtok() is called three times for each line. Notice in subsequent strtok() calls the first parameter is a null pointer to ensure that the position after the end of the last token is used as the new starting location for scanning. See the strtok() documentation in the external links for more information.

Un pointeur GListStore nommé store est déclaré, puis la fonction g_list_store_new() est utilisée pour créer un nouvel objet GListStore contenant des éléments de type G_TYPE_OBJECT, le type fondamental de GObject. Ensuite, la fonction g_data_input_stream_new() est utilisée pour créer un nouveau flux d'entrée de données pour le fichier. Ceci permet à la fonction g_data_input_stream_read_line() de lire une ligne de ce flux.

Une boucle while est utilisée pour lire les lignes de données une par une depuis le fichier « contacts.csv ». La fonction strtok() du langage C, qui manipule les jetons de chaînes de caractères, est utilisée pour découper chaque ligne en segments représentant les champs nom, email et téléphone. Chaque segment est séparé par une virgule, qui sert donc de délimiteur. La fonction strtok() prend comme premier paramètre la chaîne de caractères et comme second le délimiteur ; elle renvoie un pointeur char pointant vers l'occurrence de chaque segment. Il y a trois éléments de données : le nom, l’adresse e-mail et le numéro de téléphone. La fonction `strtok()` est donc appelée trois fois pour chaque ligne. Notez que lors des appels suivants à strtok(), le premier paramètre est un pointeur nul afin de garantir que la position suivant la fin du dernier élément soit utilisée comme point de départ de l’analyse. Consultez la documentation de strtok() dans les liens externes pour plus d’informations.

Selection Everything can now be glued together to create a simple address book application to store contacts. A GtkSingleSelection *selection pointer can be created and used to select a single contact in the column_view so that it can be deleted. This is done by passing the selection pointer to a callback. An example is shown below for a button to delete a selected contact when clicked. button_delete_contact = gtk_button_new_with_label(“Delete Contact”); g_signal_connect(button_delete_contact, “clicked”, G_CALLBACK(callbk_delete_contact), selection); The selection pointer allows the index position “p” of a contact to be obtained as shown below. guint p = gtk_single_selection_get_selected((GtkSingleSelection*) selection); The index position can then be used to remove a contact from the GListStore using g_list_store_remove(). The save_contacts() method is called after a contact has been removed so that it is no longer saved in the “contacts.csv “ data file. The same selection approach can be used to expand the application so that a contact can be edited.

Sélection

Il est désormais possible d'assembler tous les éléments pour créer une application de carnet d'adresses simple permettant de stocker des contacts. Un pointeur de sélection GtkSingleSelection* peut être créé et utilisé pour sélectionner un contact dans la vue en colonnes afin de le supprimer. Pour ce faire, le pointeur de sélection est transmis à une fonction de rappel. L'exemple ci-dessous illustre un bouton permettant de supprimer un contact sélectionné lorsqu'on clique dessus.

`button_delete_contact = gtk_button_new_with_label(“Delete contact”);`

`g_signal_connect(button_delete_contact, “clicked”, G_CALLBACK(callbk_delete_contact), selection);`

Le pointeur de sélection permet d'obtenir la position d'index « p » d'un contact, comme indiqué ci-dessous.

`guint p = gtk_single_selection_get_selected((GtkSingleSelection*) selection);`

L'index peut ensuite être utilisé pour supprimer un contact de GListStore à l'aide de la fonction `g_list_store_remove()`. La méthode save_contacts() est appelée après la suppression d'un contact afin qu'il ne soit plus enregistré dans le fichier de données « contacts.csv ».

Cette même méthode de sélection peut être utilisée pour étendre l'application et permettre la modification des contacts.

Use the Makefile in the download to build the application which produces an executable called “addressbook”. Hopefully these articles and code examples have provided enough information to get started with GTK4 programming in C. External Links GListStore https://docs.gtk.org/gio/class.ListStore.html strtok to split a string into tokens https://cplusplus.com/reference/cstring/strtok/

Utilisez le Makefile inclus dans le téléchargement pour compiler l'application qui générera un exécutable nommé « addressbook ».

Nous espérons que ces articles et exemples de code vous auront fourni suffisamment d'informations pour débuter la programmation GTK4 en C.

Liens externes :

GListStore https://docs.gtk.org/gio/class.ListStore.html

strtok pour découper une chaîne en jetons https://cplusplus.com/reference/cstring/strtok/

issue223/gtk4.txt · Dernière modification : 2025/12/01 10:13 de d52fr