Working with GtkTreeView and GtkListStore with the Glade Starter Editor

    In this post I want to talk about working with very interesting widgets (objects) of the GTK + GUI library: GtkTreeView and GtkListStore . GtkTreeView - widget for displaying trees and lists. GtkListStore - A widget representing a list model.
    I will create them using the Glade editor, on the Internet there is very little material specifically on working with GTK + widgets (and especially these) using this interface editor. I already wrote a little about working with him. Those who have never worked with him - I advise you to read this post.

    There are a lot of possibilities for working with these widgets and I plan to write a few more articles on this topic (if this is of course interesting to readers). This post is intended for beginners just to get acquainted with the GTK + library and its capabilities. Therefore, today I will consider a fairly simple example.

    Its meaning will be that we will add data to the object of the GtkListStore class (I will sometimes call it a repository) about the character of a computer game and display it in a visual form using GtkTreeView.



    But we will add not only character information to the GtkListStore. This storage allows you to store various data. For example, font styles, font name, colors, pictures, various widget settings. In this example, I will show how it is possible for each individual character to set the color of his writing separately in GtkTreeView (it is also called the tree view widget, although in this example we will look at the structure of the list format, not the tree view).

    Let's start by looking at the data warehouse - the GtkListStore widget. It represents a data structure similar to a table (just like a table in a database) each row is a record, a record consists of various types of (atomic) data. Each column sets its own data type. The columns are identified by a serial number: the first column is 0, the second column is 1, the third column is 2, etc.

    Usually create an enumeration for a more understandable reference to the storage columns:
    enum
    {
        NAME = 0,
        HEALTH,
        POWER,
        SELECTED,
        FONT_COLOR
    };
    

    First, open Glade (for example, I will use version 3.6.7 - from the Ubuntu repository, although there are newer versions that support GTK + 3.0). We create the form, on the left in the object panel we look for Window and put it on the workspace. On the left on the property panels in the General tab, look for the Window Title and set it as: “An example of working with GtkTreeView and GtkListStore” , in the Common tab, set Width request and Height requst: 650 and 350, respectively. Next, you will need to put Horizontal Panes on it, in two compartments of which the Scrolled Window is placed. You should be able to do it at this step, as shown in the picture below (clickable): now go to the object panel, click on the Tree Model and look for the List Store there - our future storage (GtkLitStore widget).

    image



    image

    By clicking on this widget, it will automatically appear in the widget tree on the right in the Objects tab. Click on it and look at the properties. These settings will be displayed, though you can scroll down even lower and there will be Add and remove rows, but we don’t need it, because we will enter the data from the controls (which we will do a little later).

    image

    First, change the name to liststorePlayers . Secondly, in Add and Remove Columns we need to add the following columns: Name (name) - string, Health (non-health) - integer, Strength (power) - integer, Flag selection (seleted) - logical and font color (colortext) - color type.

    So add the first column name - select the type gchararray in the Column type, and write the name in Column name. Next, the second column is health - in the Column type we write gint , in Column name health . Similarly for the power type gint . Next, the selection flag - select the type gboolean , and in Column name selected. And then ... And then a little trouble awaits us. We need a font color of type GdkColor (the structure used in GTK + to represent color). You look at that many possible choices of type, but GdkColor is not there. Apparently this is a flaw of the developers of Glade and will come to add ourselves. If we try to enter it there, nothing will come out anyway. It must be remembered that Glade saves the description of the interface in an XML file, and therefore it can be fixed. So, we create one more field of type gchararray , for example, in Column type we write colortext .

    image

    We save our interface description with the name mainForm and open the resulting file. We are looking for a GtkListStore there.

    <objectclass="GtkListStore"id="liststorePlayers"><columns><!-- column-name name --><columntype="gchararray"/><!-- column-name health --><columntype="gint"/><!-- column-name power --><columntype="gint"/><!-- column-name selected --><columntype="gboolean"/><!-- column-name colortext --><columntype="gchararray"/></columns></object>


    Change our gchararray to GdkColor

    <objectclass="GtkListStore"id="liststorePlayers"><columns><!-- column-name name --><columntype="gchararray"/><!-- column-name health --><columntype="gint"/><!-- column-name power --><columntype="gint"/><!-- column-name selected --><columntype="gboolean"/><!-- column-name colortext --><columntype="GdkColor"/></columns></object>


    Save and reopen in Glade. We look at the type of column and see that everything is as we need it:



    Setting up the GtkListStore storage is now complete. Now we need to make sure that the data can be displayed in a less beautiful form. To do this, go again to the object panel and look for there Tree View - this is a GtkTreeView widget.

    image

    We put it on the left scrolledwindow (I have it called scrolledwindow1, you can rename all objects in general, but I rename only those that will be used later in the code, generally rename everything). After you have taken the Tree View in the object panel and clicking on the left scrolledwindow you will get a message saying that you should specify the TreeView Model.

    image

    In our case, the TreeView Model is our repository - GtkListStore, namely the liststorePlayers widget. Click ... and select liststorePlayers there .



    Click OK for this dialog and for the previous one. Now we need to configure or it will be more correct to say to associate data from the storage with a specific form of displaying them on the screen. We click on treeview1 (which is exactly what you call it) in the right panel of objects and go to the top menu where we are looking for Edit.

    image

    The edit dialog of our Tree View opens.

    image

    The General tab contains general properties for the entire Tree View as a whole. First, change Name to treeviewPlayers . And also set the Enable Grid Lines property to Horizontal and Vertical- display of visual separation of lines and columns. Go to the Hierarcy tab. In it, we will just associate the data from the storage with a specific implementation of their display.

    image

    A bit of theory. Remember that the columns in the List Store and the columns in the Tree View are completely different things and there is no connection between them. Specific data is not bound to Tree View columns. The Tree View columns are more of some kind of logical-visual separation for the output data. Objects of the GtkCellRenderer class are used to represent specific data from the storage .

    In our example, 4 different types of presentation objects will be used:
    GtkCellRendererText - plain text to display name from the repository;
    GtkCellRendererProgress- the progress bar, and if more simply - this is a normal ProgressBar, with it we will display health and power from the repository;
    GtkCellRendererSpin - carousel button, with it we can change the value of power directly in the Tree View;
    GtkCellRendererToggle - the switch button in the cell, with the help of it we will display the flag for highlighting the record.

    We return to Glade. Click the Add button and we will have one column. In general, you can not add columns in principle. One is enough, but it will not be very beautiful and not very flexible in terms of output. Therefore, we do as follows. We will have 4 columns: Name, Health, Power, Seleted. But in the Power column, we get the Power value from the repository in both the GtkCellRendererSpin and GtkCellRendererProgress.

    Right-click on the added row: column column and select Add child Text item there. As a result, you should have the following:

    image

    Thus, we added GtkCellRendererText - to display text content. We begin to change the properties that are located on the right. In Name, put the name cellrenderertextName . Next is the Text property. Where u says unset, click on the arrows and select name - gchararray in the drop-down menu . Zero means that the column with number 0 is attached from the repository (GtkListStore), with the data stored there (character name string, which we specified in GtkListStore: name of type gchararray ).

    image

    Scroll down the property list and look for Background color. I suggest setting it rigidly, i.e. all lines of this GtkCellRendererText will have the same background color. To do this, uncheck and the color selection button will appear. Click on it and choose a color that you prefer. And here comes the Foreground color property below. I already suggest taking it from the repository. Thus, for each particular line, a different property of the font color will be possible. To do this, click on unset on the right and select colortext there - GdkColor. And you should have the number 4. i.e. column number from the GtkListStore repository where we store the color. It is also necessary to make it possible to edit the name directly in the Tree View. To do this, scroll down the properties even lower and look for Editable there. Uncheck and click the button so that Yes appears. You should be able to do this:

    image

    I think it has become more or less clear what the essence of the binding is. When a property is checked, the data is taken from the storage. By default, all properties have -1, i.e. from which column of the GtkListStore storage nothing is taken. Our task is to specify the number of the storage column from where the values ​​for the property will be taken. If we want to set something hard ourselves - uncheck and configure as we want. But then already these settings will not depend on the data in the GtkListStore repository in any way and will be applied to absolutely all lines of this view object.

    Next, create another column. Click on our first column, it will stand out and click Add. Another column will be added. If we had our GtkCellRendererText allocated, then another view object would be added to the first column. Glade is sometimes a little uncomfortable. But that's okay.

    Now add the GtkCellRendererProgress view object, where we will display the Health - the health of our character using the ProgressBar. Right-click on the new column and select Add child Progress item. We set the Name property in cellrendererprogressHealth , select Health - gint in Value , the number 1 will appear - then the data will be taken from the first column of the GtkListStore storage.

    image

    Set the Background color property. You can choose the same color as for GtkCellRendererText in the previous step (I did just that) or you can choose your own color. It may result in a small bug, when you select a color on the button, it will be displayed, and the color code in the line will be # 000000000000. Dont be upset. The color is set normally, after you close the editing dialog of this Tree View and open it again, everything will be fine. Small glade glade.

    image

    Now add another column and paste GtkCellRendererSpin and GtkCellRendererProgress into it (just like we inserted GtkCellRendererText above). For the first Add child Spin item, for the second Add child Progress item. Let's call them cellrendererspinPower and cellrendererprogressPower respectively(property Name).



    Now, temporarily, you need to close the Tree View Editor window and create a GtkAdjustment widget called adjCellRendererSpinPower for cellrendererspinPower . In the objects panel, select Adjustment, as shown in the figure below and it will appear in the widgets tree in Objects.



    In the adjCellRendererSpinPower properties, set the Maximum value: 100.00 , Page Size: 0.00 . We return to the editing mode of our GtkTreeView widget. Now you need to define adjCellRendererSpinPower for cellrendererspinPower. Uncheck Adjustment, click ... and select adjCellRendererSpinPower.



    There is another bad bug in Glade. When you open a GladeXML file with a description of the interface that we create, this very Adjustment flag is reset. Do not forget about it. Now set other properties, start with Text. Choose power - gint from the drop-down list , i.e. bind from the storage column number 2 with data, with data on the strength.



    as well as Editable we do Yes :



    It is also necessary to set, as for previous objects width: 60 ; Cell background color: # c0c0e5e5e7e7 (I remind you that you may have a different color) and Horizontal Padding: 5 . Now for cellrendererprogressPower we set Text (the displayed text on the scale) and Value (scale value) alsopower - gint .



    And of course we set, as for past objects width: 100 ; Cell background color: # c0c0e5e5e7e7 and Horizontal Padding: 5 .

    It remains to add the last object in GtkTreeView - cellrenderertoggleSelected - a widget of type Toggle (Add Toggle Item). We correlate its Toggle State property with selected gboolean , with column number 3 from the data store: We



    also set Cell background color: # c0c0e5e5e7e7 .

    Lastly, you must sign the columns, i.e. set the Column property to Title. In the corresponding values: Name , Health , Power ,Selected :



    This completes the setup of GtkTreeView. Now the widget tree will look like this:



    Next, you need to register signal (event) handlers for some GtkTreeView widgets and for himself. We click on the cellrenderertextName widget and go to the Signals tab, look for the event there (I will still call the signals as events) edited - editing the text field. Using the drop-down list or manually write the name of the event handler on_cellrenderertextName_edited , as shown in the figure below:



    In the same way, for the cellrendererspinPower widget for the edited event, the on_cellrendererspinPower_edited handler- change the value using the "carousel". For the cellrenderertoggleSelected widget, we look for the toggled event - a change in the state of the switch and select the name of the on_cellrenderertoggleSelected_toggled handler . And now we click on our treeviewPlayers widget itself and look there in the Signals row_activated tab. We write or select the name of the on_treeviewPlayers_row_activated handler.
    Although you, in principle, can as you prefer call event handlers. The main thing is the same as in Glade to specify further in the code.

    Now you need to add a small dialog panel, with which you can quickly add new characters and cause other manipulations. I will not describe in detail the process of creating this menu, as the goal of the post is to talk about GtkTreeView and GtkListStore, I’ll just briefly tell you the basic steps and show what should happen in the end.

    First, for scrolledwindow1, set both the Resize and Shrink properties to Yes (Packing tab) and Width request to 370 (Common tab). For scrolledwindow2, the Resize property is No , and Shrink is Yes , and Width request is 250. Next, add the GtkViewport widget to scrolledwindow2, and the GtkVBox widget (vertical container), which consists of 8 cells, is already in it. The first four will be widgets GtkHBox (horizontal container), consisting of GtkLabel (signature) and controls: entryName (GtkEntry), spinbuttonHealth (GtkSpinButton), spinbuttonPower (GtkSpinButton) and colorbutFontColor (Gtk). I explain: it is necessary to add 4 GtkHBox, consisting of 2 two cells: one for the signature (left), the other for the control (right) listed above.
    The bottom four are buttons: butAdd, butDelete, butPrint, butQuit. For all widgets inside GtkVBox, I recommend setting Expand and Fill to No in the Packing tab (these properties are described in my previous post) SpinbuttonHealth and spinbuttonPower widgets must also be associated with the corresponding GtkAdjustment widgets. I called them adjHealth and adjPower. And the corresponding settings were established:



    Linking with spinbuttonHealth and spinbuttonPower occurs by selecting in their Adjustment properties created adjHealth and adjPower .

    All that remains to be done in Glade is to define handlers for the buttons: butAdd, butDelete, butPrint, butQuit. We click on each widget and in the Event tab for the clicked property, select on_butAdd_clicked , on_butDelete_clicked , on_butPrint_clicked , on_butQuit_clicked .

    The result should be the following:



    But in general, the whole window of our training application looks like this:



    Now we turn to writing code. All code will be contained in the Example1.cpp file, although you can name it as you like best.

    #include<stdlib.h>#include<gtk/gtk.h>#define UI_FILE "mainForm.glade"


    The structure for working with the repository, which was mentioned at the beginning:
    enum
    {
        NAME = 0,
        HEALTH,
        POWER,
        SELECTED,
        FONT_COLOR
    };
    


    The prototypes of event handlers, the names should be as we specified in the Signals tab for widgets in the Glade editor. Because If the C ++ compiler is used, then we indicate that they must communicate according to the binding order in C.
    extern"C"voidon_butQuit_clicked(GtkWidget *TopWindow, gpointer data);
    extern"C"voidon_butAdd_clicked(GtkWidget *window, gpointer data);
    extern"C"voidon_butDelete_clicked(GtkButton *remove, gpointer data);
    extern"C"voidon_butPrint_clicked(GtkWidget *button, gpointer data);
    extern"C"voidon_cellrendererspinPower_edited(GtkCellRendererText *render, gchar *path, gchar *new_text, gpointer data);
    extern"C"voidon_cellrenderertoggleSelected_toggled(GtkCellRendererToggle *render, gchar *path, gpointer data);
    extern"C"voidon_treeviewPlayers_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data);
    extern"C"voidon_cellrenderertextName_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer data);
    


    A structure containing pointers to widgets that were created in Glade and will be retrieved from GladeXML in the main function.
    structMainWindowObjects
    {
        GtkWindow      *topWindow;         
        GtkTreeView    *treeviewPlayers;
        GtkListStore   *liststorePlayers;
        GtkEntry       *entryName;
        GtkAdjustment  *adjHealth;
        GtkAdjustment  *adjPower;
        GtkColorButton *colorbutFontColor;
    } mainWindowObjects;
    


    In main, we get widgets from the GladeXML format. Using gtk_tree_selection_set_mode we set the ability to select multiple lines in GtkTreeView. We connect our event handlers using the gtk_builder_connect_signals function and at the same time pass pointers to widgets using the mainWindowObjects link. Thus, as you will see later, using the gpointer data pointer, you can access all widgets from the handler function.
    intmain(int argc, char** argv){
        GtkBuilder *builder;
        GError *error = NULL;
        gtk_init( &argc, &argv );
        builder = gtk_builder_new();
        if( ! gtk_builder_add_from_file( builder, UI_FILE, &error ) )
        {
    	g_warning( "%s\n", error->message );
    	g_free( error );
    	return( 1 );
        }
        mainWindowObjects.topWindow = GTK_WINDOW(gtk_builder_get_object(builder, "topWindow"));
        mainWindowObjects.treeviewPlayers = GTK_TREE_VIEW( gtk_builder_get_object( builder, "treeviewPlayers" ) );
        mainWindowObjects.liststorePlayers = GTK_LIST_STORE( gtk_builder_get_object(builder, "liststorePlayers") );
        mainWindowObjects.entryName = GTK_ENTRY( gtk_builder_get_object(builder, "entryName") );
        mainWindowObjects.adjHealth = GTK_ADJUSTMENT( gtk_builder_get_object(builder, "adjHealth") );
        mainWindowObjects.adjPower = GTK_ADJUSTMENT( gtk_builder_get_object(builder, "adjPower") );
        mainWindowObjects.colorbutFontColor = GTK_COLOR_BUTTON( gtk_builder_get_object(builder, "colorbutFontColor") );
        GtkTreeSelection *selection;
        selection = gtk_tree_view_get_selection( GTK_TREE_VIEW(mainWindowObjects.treeviewPlayers) );
        gtk_tree_selection_set_mode( selection, GTK_SELECTION_MULTIPLE );
        gtk_builder_connect_signals (builder, &mainWindowObjects);
        g_object_unref( G_OBJECT( builder ) );
        gtk_widget_show_all ( GTK_WIDGET (mainWindowObjects.topWindow) );
        gtk_main ();
    }
    


    Implementation of the handler for adding a new character. gtk_list_store_append - adds a new line to the model (storage) and returns iter - a link to it (or else it is called an iterator pointing to the line). And the gtk_list_store_set function sets the values ​​of the cells in the line pointed to by iter. Values ​​are specified by enumeration: NAME, HEALTH, etc. The sign of graduation is -1.
    voidon_butAdd_clicked(GtkWidget *button, gpointer data){
        MainWindowObjects* mwo = static_cast<MainWindowObjects*>( data );
        GtkTreeIter iter;
        GdkColor color;
        gtk_color_button_get_color( mwo->colorbutFontColor, &color );
        gtk_list_store_append(GTK_LIST_STORE( mwo->liststorePlayers ), &iter);
        gtk_list_store_set(GTK_LIST_STORE( mwo->liststorePlayers ), &iter, 
    		       NAME, gtk_entry_get_text(mwo->entryName),
                           HEALTH, static_cast<int>( gtk_adjustment_get_value(mwo->adjHealth) ),
                           POWER, static_cast<int>( gtk_adjustment_get_value(mwo->adjPower) ),
                           SELECTED, false,
                           FONT_COLOR, &color,
                           -1 );
    }
    


    An implementation of the event handler for the edit cell with the name. Using the gtk_tree_view_get_model function, we get the model (store) associated with our GtkTreeView. Using the gtk_tree_model_get_iter_from_string function, we get a link to a string from the path path (which is in the function signature, for this repository view, this path is just the line number that we changed), and then with the help of the familiar gtk_list_store_set we set a new value that is in new_text. In general, the signature of this handler (as well as the other handlers) is taken from the official documentation on Gtk +.
    Those. for each widget, you can find there the signature of the event (or whatever they say signal - the signature of the signal).
    voidon_cellrenderertextName_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer data){
        MainWindowObjects* mwo = static_cast<MainWindowObjects*>( data );
        if ( g_ascii_strcasecmp(new_text, "") != 0 )
        {
            GtkTreeIter iter;
            GtkTreeModel *model;
            model = gtk_tree_view_get_model (mwo->treeviewPlayers);
            if (gtk_tree_model_get_iter_from_string(model, &iter, path) )
                gtk_list_store_set(GTK_LIST_STORE (model), &iter, NAME, new_text, -1 );
        }
    }
    


    Implementing an editing event handler using the carousel button. It is almost the same as described above. Except that you need to convert the new value to int. For simplicity, I used the old atoi C function, although you could implement this using stringstream.
    voidon_cellrendererspinPower_edited(GtkCellRendererText *renderer, gchar *path, gchar *new_text, gpointer data){
        MainWindowObjects* mwo = static_cast<MainWindowObjects*>( data );
        if ( g_ascii_strcasecmp(new_text, "") != 0 )
        {
            GtkTreeIter iter;
            GtkTreeModel *model;
            model = gtk_tree_view_get_model (mwo->treeviewPlayers);
            if (gtk_tree_model_get_iter_from_string(model, &iter, path) )
                gtk_list_store_set(GTK_LIST_STORE (model), &iter, POWER, atoi(new_text), -1 );
        }
    }
    


    Implementation of a handler for clicking on a cell with a switch (flag) - 4th column. Using gtk_tree_model_get we get the current state of the switch and set the opposite:! Selected
    voidon_cellrenderertoggleSelected_toggled(GtkCellRendererToggle *render, gchar *path, gpointer data){
        MainWindowObjects* mwo = static_cast<MainWindowObjects*>( data );
        GtkTreeIter iter;
        GtkTreeModel *model;
        gboolean selected;
        model = gtk_tree_view_get_model ( mwo->treeviewPlayers );
        if (gtk_tree_model_get_iter_from_string(model, &iter, path) )
        {
            gtk_tree_model_get( model, &iter, 3, &selected, -1 );
            gtk_list_store_set( GTK_LIST_STORE (model), &iter, SELECTED, !selected, -1 );
        }
    }
    


    Implementation of the method of printing selected lines. Using the gtk_tree_model_get_iter_first function, we get a link to the first line and at the same time check whether the storage is empty (reader flag). Using the gtk_tree_model_get method, we get the cell values ​​of interest to us for the current row that iter is looking at. Go to the next line with gtk_tree_model_iter_next.
    voidon_butPrint_clicked(GtkWidget *button, gpointer data){
        MainWindowObjects* mwo = static_cast<MainWindowObjects*>( data );
        GtkTreeIter   iter;
        gboolean reader = gtk_tree_model_get_iter_first(GTK_TREE_MODEL( mwo->liststorePlayers ), &iter);
        g_print( "Selected rows:\n" );
        while ( reader )
        {
            gboolean selected;
            gtk_tree_model_get (GTK_TREE_MODEL( mwo->liststorePlayers ), &iter, 
    			SELECTED, &selected, -1);
            if ( selected )
            {
                gchar* name;
                gint health;
                gint power;
                gtk_tree_model_get (GTK_TREE_MODEL( mwo->liststorePlayers ), &iter, 
    				NAME, &name,
    				HEALTH, &health,
                                    POWER, &power,
                                    -1);
                g_print( "%s %d %d\n", name, health, power );
            }
            reader = gtk_tree_model_iter_next(GTK_TREE_MODEL( mwo->liststorePlayers ), &iter);
        }
    }
    


    Implementing a method that double-clicks a row in a GtkTreeView. Using the gtk_tree_model_get_iter function, we get iter from path, and then we get the data we are interested in using gtk_tree_model_get and display them in the console.
    voidon_treeviewPlayers_row_activated(GtkTreeView *treeview, GtkTreePath *path, GtkTreeViewColumn *col, gpointer data){
        GtkTreeModel *model;
        GtkTreeIter   iter;
        model = gtk_tree_view_get_model( treeview );
        if ( gtk_tree_model_get_iter(model, &iter, path) )
        {
            gchar* name;
            gint health;
            gint power;
            gtk_tree_model_get(model, &iter, 
    			   NAME, &name,
                               HEALTH, &health,
                               POWER, &power,
                               -1);
            g_print( "Current row: %s %d %d\n", name, health, power);
        }
    }
    


    This function is auxiliary to delete selected lines in GtkTreeView. gtk_list_store_remove - Removes this line from the list that iter refers to First we extract path with gtk_tree_row_reference_get_path, and then convert path to iter with gtk_tree_model_get_iter.
    staticvoidremove_row(GtkTreeRowReference *ref, GtkTreeModel *model){
        GtkTreeIter iter;
        GtkTreePath *path;
        path = gtk_tree_row_reference_get_path (ref);
        gtk_tree_model_get_iter (model, &iter, path);
        gtk_list_store_remove (GTK_LIST_STORE (model), &iter);
    }
    


    Using the gtk_tree_selection_get_selected_rows function, we get a list of selected lines, then use a while loop to go through each selected line and create a link based on the path using the gtk_tree_row_reference_new function and add this link to the references list using g_list_prepend.
    We call the remove_row function for each link using g_list_foreach. And in the end, similarly using g_list_foreach we free our lists.
    voidon_butDelete_clicked(GtkButton *remove, gpointer data){	
        MainWindowObjects* mwo = static_cast<MainWindowObjects*>( data );
        GtkTreeSelection *selection;
        GtkTreeRowReference *ref;
        GtkTreeModel *model;
        GList *rows, *ptr, *references = NULL;
        selection = gtk_tree_view_get_selection ( mwo->treeviewPlayers );
        model = gtk_tree_view_get_model ( mwo->treeviewPlayers );
        rows = gtk_tree_selection_get_selected_rows (selection, &model);
        ptr = rows;
        while (ptr != NULL)
        {
            ref = gtk_tree_row_reference_new (model, (GtkTreePath*) ptr->data);
            references = g_list_prepend (references, gtk_tree_row_reference_copy (ref));
            gtk_tree_row_reference_free (ref);
            ptr = ptr->next;
        }
        g_list_foreach ( references, (GFunc) remove_row, model );
        g_list_foreach ( references, (GFunc) gtk_tree_row_reference_free, NULL );
        g_list_foreach ( rows, (GFunc) gtk_tree_path_free, NULL );
        g_list_free ( references );
        g_list_free ( rows );
    }
    


    GTK + Application Closure Handler Implementation
    voidon_butQuit_clicked(GtkWidget *window, gpointer data){
        gtk_main_quit();
    }
    


    To compile, you must create a makefile:
    CC=g++
    LDLIBS=`pkg-config --libs gtk+-2.0 gmodule-2.0`
    CFLAGS=-Wall -g `pkg-config --cflags gtk+-2.0 gmodule-2.0`
    example1: example1.o
    	$(CC) $(LDLIBS) example1.o -o example1
    example1.o: example1.cpp
    	$(CC) $(CFLAGS) -c example1.cpp
    clean:
    	rm -f example1
    	rm -f *.o
    


    Now you can compile this example and try to “play around” with what we have done. I advise you to run from the distribution console of your Linux distribution. Try adding a few characters by choosing different colors for their name. Try to select several lines in the 4th column and click Print, then the selected ones will be printed in the console. Try changing the Power value using the “carousel” (double-click on it, to the left of the Progress bar'a). Try holding down the Ctrl or Shift key to select several added lines and delete them by pressing Delete.

    This example can be downloaded from here .

    Compilation takes place with the command:
    $ make
    


    Launch:
    $ ./example1
    


    I tried to describe as many details as possible (some may even be too much), but all this was done to quickly understand this topic.

    Also popular now: