C GTK+ : Text Completion on a GtkEntry with GtkEntryCompletion

Articles may may have files attached at the end of the post

Text completion is quite a nifty feature to have on an interactive software, saves you loads of typing, helps you remember the exact spelling on one's email, lost urls (thanks firefox 3 for the regex based search :-) )....

Gtk+ offers this ability through the use of GtkEntryCompletion that we will hook to the GtkEntry.

This tutorial will explain through a code sample how to set it up.

Text completion works a bit like a GtkTreeView, except that the our GtkEntry will act as the TreeView. The text that will be used for the completion is going to be store in a GtkListStore column.
Then, we will simply have to set the GtkEntryCompletion to the GtkEntry and Gtk will do the rest for us.

GtkEntryCompletionGtkEntryCompletionIn this code sample, we will create some fake "group contacts", that have a name, a nickname and an email.
We want to be able to have the user type the name, and match it selection with its email.
To achieve this, we will fill up the datastore withe name, nickname and email, tell the GtkEntryCompletion to do its completion on the first column of the liststore. Then, when a match is selected we will pick up the signal and find out the email associated to it and print it out to the console.

  1. /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
  2. /*
  3.  * Copyright (C) 2008 chantra.
  4.  *
  5.  * This program is free software; you can redistribute it and/or
  6.  * modify it under the terms of the GNU General Public License as
  7.  * published by the Free Software Foundation; either version 2 of the
  8.  * License, or (at your option) any later version.
  9.  *
  10.  * Authors: chantra <chantra_AT_debuntu_-DOT-_org>
  11.  */
  12.  
  13. /** compile with
  14.  * gcc -Wall -g entry_completion.c -o entry_completion `pkg-config --cflags gtk+-2.0` `pkg-config --libs gtk+-2.0`
  15.  */
  16.  
  17. #include <stdio.h>
  18.  
  19. #include <gtk/gtk.h>
  20.  
  21. #define PACKAGE "ContactLookUp"
  22. #define VERSION "0.1.0"
  23.  
  24. typedef struct contact {
  25.   char *name;
  26.   char *nickname;
  27.   char *email;
  28. } contact;
  29.  
  30. typedef enum {
  31.   CONTACT_NAME = 0,
  32.   CONTACT_NICK,
  33.   CONTACT_EMAIL
  34. } ContactCol;
  35.  
  36. contact contact_list[] = {
  37.   { "Foobar", "foo", "foobar@example.com" },
  38.   { "Super Framework", "frame", "frame@work.com" },
  39.   { "Gtk Framework", "gtk", "gtk@framework.com" },
  40.   { "Non sense", "bla", "nowhere@myplace.net" },
  41.   { "GtkEntryCompletion", "completion", "fancybox@mail.com" },
  42.   { "Gtk rules", "fantastic", "gtk@gtk.org" },
  43.   { "some more words", "fillingTheGap", "another@email.com" },
  44.   { "new line", "somemore nick", "again@mail.com"},
  45.   { NULL, NULL, NULL}
  46. };
  47.  
  48. /*
  49.  * Terminate the main loop.
  50.  */
  51. static void
  52. on_destroy(GtkWidget *widget, gpointer data)
  53. {
  54.     gtk_main_quit();
  55. }
  56.  
  57. static gboolean
  58. on_match_select(GtkEntryCompletion *widget,
  59.   GtkTreeModel       *model,
  60.   GtkTreeIter        *iter,
  61.   gpointer            user_data)
  62. {  
  63.   GValue value = {0, };
  64.   gtk_tree_model_get_value(model, iter, CONTACT_EMAIL, &value);
  65.   fprintf(stdout, "You have selected %s\n", g_value_get_string(&value));
  66.   g_value_unset(&value);
  67.   return FALSE;
  68. }    
  69.  
  70. int main(int argc, char **argv)
  71. {
  72.     contact *l;
  73.  
  74.     GtkWidget *window;
  75.     GtkWidget *textentry;
  76.     GtkEntryCompletion *completion;
  77.     GtkListStore *model;
  78.     GtkTreeIter iter;
  79.     gtk_init (&argc, &argv);
  80.  
  81.     /* create the main, top level, window */
  82.     window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  83.     gtk_container_set_border_width (GTK_CONTAINER (window), 20);
  84.     gtk_window_set_title (GTK_WINDOW (window), PACKAGE " " VERSION);
  85.     gtk_window_set_default_size (GTK_WINDOW (window), 200, 50);
  86.  
  87.     /* Connect the destroy event of the window */
  88.     g_signal_connect (G_OBJECT (window), "destroy",
  89.                       G_CALLBACK (on_destroy), l);
  90.  
  91.     textentry = gtk_entry_new ();
  92.     /* set up completion */
  93.     completion = gtk_entry_completion_new();
  94.     /* set completion on the first column, the
  95.     * 2 others won't be used for now */
  96.     gtk_entry_completion_set_text_column(completion, CONTACT_NAME);
  97.     gtk_entry_set_completion(GTK_ENTRY(textentry), completion);
  98.     g_signal_connect(G_OBJECT (completion), "match-selected",
  99.                 G_CALLBACK (on_match_select), NULL);
  100.     /* Create the ListStore, add "contacts" and
  101.      * set it as the model of the entrycompletion */
  102.     model = gtk_list_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
  103.     for(l=contact_list; l && l->name; l++) {
  104.       gtk_list_store_append(model, &iter);
  105.       gtk_list_store_set(model, &iter, CONTACT_NAME, l->name,
  106.               CONTACT_NICK, l->nickname,
  107.               CONTACT_EMAIL, l->email, -1);
  108.     }
  109.     gtk_entry_completion_set_model(completion, GTK_TREE_MODEL(model));
  110.  
  111.     /* and insert our entry into the main window  */
  112.     gtk_container_add (GTK_CONTAINER (window), textentry);
  113.     /* make sure that everything is visible */
  114.     gtk_widget_show_all (window);
  115.     /* start the main loop */
  116.     gtk_main ();
  117.     return 0;
  118. }

AttachmentSize
entry_completion.c3.56 KB