The CList widget has replaced the List widget (which is still
available).
The CList widget is a multi-column list widget that is capable of
handling literally thousands of rows of information. Each column can
optionally have a title, which itself is optionally active, allowing
us to bind a function to its selection.
Creating a CList is quite straightforward, once you have learned
about widgets in general. It provides the almost standard two ways,
that is the hard way, and the easy way. But before we create it, there
is one thing we should figure out beforehand: how many columns should
it have?
Not all columns have to be visible and can be used to store data that
is related to a certain cell in the list.
The first form is very straightforward, the second might require some
explanation. Each column can have a title associated with it, and this
title can be a label or a button that reacts when we click on it. If
we use the second form, we must provide pointers to the title texts,
and the number of pointers should equal the number of columns
specified. Of course we can always use the first form, and manually
add titles later.
Note: The CList widget does not have its own scrollbars and should
be placed within a ScrolledWindow widget if your require this
functionality. This is a change from the GTK 1.0 implementation.
which, as the name implies, sets the selection mode of the
CList. The first argument is the CList widget, and the second
specifies the cell selection mode (they are defined in gtkenums.h). At
the time of this writing, the following modes are available to us:
GTK_SELECTION_SINGLE - The selection is either NULL or contains
a GList pointer for a single selected item.
GTK_SELECTION_BROWSE - The selection is NULL if the list
contains no widgets or insensitive ones only, otherwise it contains a
GList pointer for one GList structure, and therefore exactly one list
item.
GTK_SELECTION_MULTIPLE - The selection is NULL if no list items
are selected or a GList pointer for the first selected item. That in
turn points to a GList structure for the second selected item and so
on. This is currently the default for the CList widget.
GTK_SELECTION_EXTENDED - The selection is always NULL.
Others might be added in later revisions of GTK.
We can also define what the border of the CList widget should look
like. It is done through
When you create a CList widget, you will also get a set of title
buttons automatically. They live in the top of the CList window, and
can act either as normal buttons that respond to being pressed, or
they can be passive, in which case they are nothing more than a
title. There are four different calls that aid us in setting the
status of the title buttons.
An active title is one which acts as a normal button, a passive one is
just a label. The first two calls above will activate/deactivate the
title button above the specific column, while the last two calls
activate/deactivate all title buttons in the supplied clist widget.
But of course there are those cases when we don't want them at all,
and so they can be hidden and shown at will using the following two
calls.
Note that only the title of one column can be set at a time, so if all
the titles are known from the beginning, then I really suggest using
gtk_clist_new_with_titles (as described above) to set them. It saves
you coding time, and makes your program smaller. There are some cases
where getting the job done the manual way is better, and that's when
not all titles will be text. CList provides us with title buttons
that can in fact incorporate whole widgets, for example a pixmap. It's
all done through
The GtkJustification type can take the following values:
GTK_JUSTIFY_LEFT - The text in the column will begin from the
left edge.
GTK_JUSTIFY_RIGHT - The text in the column will begin from the
right edge.
GTK_JUSTIFY_CENTER - The text is placed in the center of the
column.
GTK_JUSTIFY_FILL - The text will use up all available space in
the column. It is normally done by inserting extra blank spaces
between words (or between individual letters if it's a single
word). Much in the same way as any ordinary WYSIWYG text editor.
The next function is a very important one, and should be standard in
the setup of all CList widgets. When the list is created, the width
of the various columns are chosen to match their titles, and since
this is seldom the right width we have to set it using
Note that the width is given in pixels and not letters. The same goes
for the height of the cells in the columns, but as the default value
is the height of the current font this isn't as critical to the
application. Still, it is done through
We can also move the list around without user interaction, however, it
does require that we know what we are looking for. Or in other words,
we need the row and column of the item we want to scroll to.
The gfloat row_align is pretty important to understand. It's a value
between 0.0 and 1.0, where 0.0 means that we should scroll the list so
the row appears at the top, while if the value of row_align is 1.0,
the row will appear at the bottom instead. All other values between
0.0 and 1.0 are also valid and will place the row between the top and
the bottom. The last argument, gfloat col_align works in the same way,
though 0.0 marks left and 1.0 marks right instead.
Depending on the application's needs, we don't have to scroll to an
item that is already visible to us. So how do we know if it is
visible? As usual, there is a function to find that out as well.
Note that it will only tell us if a row is visible. Currently there is
no way to determine this for a column. We can get partial information
though, because if the return is GTK_VISIBILITY_PARTIAL, then
some of it is hidden, but we don't know if it is the row that is being
cut by the lower edge of the listbox, or if the row has columns that
are outside.
We can also change both the foreground and background colors of a
particular row. This is useful for marking the row selected by the
user, and the two functions that is used to do it are
In these calls we have to provide a collection of pointers that are
the texts we want to put in the columns. The number of pointers should
equal the number of columns in the list. If the text[] argument is
NULL, then there will be no text in the columns of the row. This is
useful, for example, if we want to add pixmaps instead (something that
has to be done manually).
Also, please note that the numbering of both rows and columns start at 0.
There is also a call that removes all rows in the list. This is a lot
faster than calling gtk_clist_remove once for each row, which is the
only alternative.
void gtk_clist_clear( GtkCList *clist );
There are also two convenience functions that should be used when a
lot of changes have to be made to the list. This is to prevent the
list flickering while being repeatedly updated, which may be highly
annoying to the user. So instead it is a good idea to freeze the list,
do the updates to it, and finally thaw it which causes the list to be
updated on the screen.
It's quite straightforward. All the calls have the CList as the first
argument, followed by the row and column of the cell, followed by the
data to be set. The spacing argument in gtk_clist_set_pixtext is
the number of pixels between the pixmap and the beginning of the
text. In all cases the data is copied into the widget.
The returned pointers are all pointers to the data stored within the
widget, so the referenced data should not be modified or released. It
isn't necessary to read it all back in case you aren't interested. Any
of the pointers that are meant for return values (all except the
clist) can be NULL. So if we want to read back only the text from a
cell that is of type pixtext, then we would do the following, assuming
that clist, row and column already exist:
There is also a function that will let us set the indentation, both
vertical and horizontal, of a cell. The indentation value is of type
gint, given in pixels, and can be both positive and negative.
With a CList it is possible to set a data pointer for a row. This
pointer will not be visible for the user, but is merely a convenience
for the programmer to associate a row with a pointer to some
additional data.
The functions should be fairly self-explanatory by now.
And also a function that will take x and y coordinates (for example,
read from the mousepointer), and map that onto the list, returning the
corresponding row and column.
When we detect something of interest (it might be movement of the
pointer, a click somewhere in the list) we can read the pointer
coordinates and find out where in the list the pointer is. Cumbersome?
Luckily, there is a simpler way...
As with all other widgets, there are a few signals that can be used. The
CList widget is derived from the Container widget, and so has all the
same signals, but also adds the following:
select_row - This signal will send the following information, in
order: GtkCList *clist, gint row, gint column, GtkEventButton *event
unselect_row - When the user unselects a row, this signal is
activated. It sends the same information as select_row
click_column - Send GtkCList *clist, gint column
So if we want to connect a callback to select_row, the callback
function would be declared like this
/* example-start clist clist.c */
#include <gtk/gtk.h>
/* User clicked the "Add List" button. */
void button_add_clicked( gpointer data )
{
int indx;
/* Something silly to add to the list. 4 rows of 2 columns each */
gchar *drink[4][2] = { { "Milk", "3 Oz" },
{ "Water", "6 l" },
{ "Carrots", "2" },
{ "Snakes", "55" } };
/* Here we do the actual adding of the text. It's done once for
* each row.
*/
for ( indx=0 ; indx < 4 ; indx++ )
gtk_clist_append( (GtkCList *) data, drink[indx]);
return;
}
/* User clicked the "Clear List" button. */
void button_clear_clicked( gpointer data )
{
/* Clear the list using gtk_clist_clear. This is much faster than
* calling gtk_clist_remove once for each row.
*/
gtk_clist_clear( (GtkCList *) data);
return;
}
/* The user clicked the "Hide/Show titles" button. */
void button_hide_show_clicked( gpointer data )
{
/* Just a flag to remember the status. 0 = currently visible */
static short int flag = 0;
if (flag == 0)
{
/* Hide the titles and set the flag to 1 */
gtk_clist_column_titles_hide((GtkCList *) data);
flag++;
}
else
{
/* Show the titles and reset flag to 0 */
gtk_clist_column_titles_show((GtkCList *) data);
flag--;
}
return;
}
/* If we come here, then the user has selected a row in the list. */
void selection_made( GtkWidget *clist,
gint row,
gint column,
GdkEventButton *event,
gpointer data )
{
gchar *text;
/* Get the text that is stored in the selected row and column
* which was clicked in. We will receive it as a pointer in the
* argument text.
*/
gtk_clist_get_text(GTK_CLIST(clist), row, column, &text);
/* Just prints some information about the selected row */
g_print("You selected row %d. More specifically you clicked in "
"column %d, and the text in this cell is %s\n\n",
row, column, text);
return;
}
int main( int argc,
gchar *argv[] )
{
GtkWidget *window;
GtkWidget *vbox, *hbox;
GtkWidget *scrolled_window, *clist;
GtkWidget *button_add, *button_clear, *button_hide_show;
gchar *titles[2] = { "Ingredients", "Amount" };
gtk_init(&argc, &argv);
window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_widget_set_usize(GTK_WIDGET(window), 300, 150);
gtk_window_set_title(GTK_WINDOW(window), "GtkCList Example");
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
GTK_SIGNAL_FUNC(gtk_main_quit),
NULL);
vbox=gtk_vbox_new(FALSE, 5);
gtk_container_set_border_width(GTK_CONTAINER(vbox), 5);
gtk_container_add(GTK_CONTAINER(window), vbox);
gtk_widget_show(vbox);
/* Create a scrolled window to pack the CList widget into */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS);
gtk_box_pack_start(GTK_BOX(vbox), scrolled_window, TRUE, TRUE, 0);
gtk_widget_show (scrolled_window);
/* Create the CList. For this example we use 2 columns */
clist = gtk_clist_new_with_titles( 2, titles);
/* When a selection is made, we want to know about it. The callback
* used is selection_made, and its code can be found further down */
gtk_signal_connect(GTK_OBJECT(clist), "select_row",
GTK_SIGNAL_FUNC(selection_made),
NULL);
/* It isn't necessary to shadow the border, but it looks nice :) */
gtk_clist_set_shadow_type (GTK_CLIST(clist), GTK_SHADOW_OUT);
/* What however is important, is that we set the column widths as
* they will never be right otherwise. Note that the columns are
* numbered from 0 and up (to 1 in this case).
*/
gtk_clist_set_column_width (GTK_CLIST(clist), 0, 150);
/* Add the CList widget to the vertical box and show it. */
gtk_container_add(GTK_CONTAINER(scrolled_window), clist);
gtk_widget_show(clist);
/* Create the buttons and add them to the window. See the button
* tutorial for more examples and comments on this.
*/
hbox = gtk_hbox_new(FALSE, 0);
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, TRUE, 0);
gtk_widget_show(hbox);
button_add = gtk_button_new_with_label("Add List");
button_clear = gtk_button_new_with_label("Clear List");
button_hide_show = gtk_button_new_with_label("Hide/Show titles");
gtk_box_pack_start(GTK_BOX(hbox), button_add, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), button_clear, TRUE, TRUE, 0);
gtk_box_pack_start(GTK_BOX(hbox), button_hide_show, TRUE, TRUE, 0);
/* Connect our callbacks to the three buttons */
gtk_signal_connect_object(GTK_OBJECT(button_add), "clicked",
GTK_SIGNAL_FUNC(button_add_clicked),
(gpointer) clist);
gtk_signal_connect_object(GTK_OBJECT(button_clear), "clicked",
GTK_SIGNAL_FUNC(button_clear_clicked),
(gpointer) clist);
gtk_signal_connect_object(GTK_OBJECT(button_hide_show), "clicked",
GTK_SIGNAL_FUNC(button_hide_show_clicked),
(gpointer) clist);
gtk_widget_show(button_add);
gtk_widget_show(button_clear);
gtk_widget_show(button_hide_show);
/* The interface is completely set up so we show the window and
* enter the gtk_main loop.
*/
gtk_widget_show(window);
gtk_main();
return(0);
}
/* example-end */