cgtkgtk3treemodel

How to change data of a GtkTreeModel (within "edited" callback)


I'm catching the "edited" signal of my GtkCellRenderer:

GtkTreeModel * sortmodel; // contains a sorted model of GtkListStore

// ...

GtkCellRenderer * renderer;

// ...

g_object_set(renderer, "editable", TRUE, NULL);    
g_signal_connect(renderer, "edited",
                G_CALLBACK(onEdited_name), sortmodel);

I'd now like to change the content of the cell accordingly, but I don't find any function, that would change the content of a cell of a GtkTreeModel.

void onEdited_name(GtkCellRendererText *cell,
                        gchar * path_string,
                        gchar * new_text,
                        gpointer treemodel)
{
  GtkTreeModel * model = GTK_TREE_MODEL(treemodel);

  GtkTreeIter iter;
  gtk_tree_model_get_iter_from_string(model, &iter, path_string);  

  // TODO: set the value according to iter.
  // gtk_list_store_set will not work of course, because
  //  we're operating on a GtkTreeModel   
}  

This question is related to: Changing the content of a GTK Tree View


Solution

  • Your first code snippet is correct.

    1. You cannot change a value on a GtkTreeModel.
    2. You can only change a value on the "raw" model (the base model like GtkListStore or GtkTreeStore).

    Theory - Good to know

    Gtk hierarchy

    The following picture shows the GtkTreeModel hierarchy and what (important) functions they offer GtkTreeView hierarchy

    As you can see, if you want to change the values of cells, you need to differentiate what kind of model you're actually working on.

    GtkCellRenderer and the "edited" signal / callback

    One Renderer should only be "assigned" to one column. Otherwise you don't know which column the user tried to change.

    Change value of a GtkTreeModelSort of a GtkTreeStore

    See the example below for GtkListStore, and replace GtkListStore with GtkTreeStore. That should hopefully do the trick.

    Change value of a GtkTreeModelSort of a GtkListStore

    void 
    onEdited_name (GtkCellRendererText * cell,
                   gchar               * path_string,
                   gchar               * new_text,
                   gpointer              p_model_sorted)
    {       
        // we need to convert to GtkListStore, because GtkTreeModel does not
        //  provide an interface for cell content changing.
    
    
        // convert raw data to the actual type
        GtkTreeModelSort * model_sorted = GTK_TREE_MODEL_SORT(p_model_sorted);
    
        // get the iterator within the sorted model
        GtkTreeIter iter_sortedModel;
        gtk_tree_model_get_iter_from_string((GtkTreeModel*)model_sorted,
                      &iter_sortedModel, path_string);          
    
        // convert sorted model to raw model
        GtkListStore * model_raw;       
        model_raw = GTK_LIST_STORE(gtk_tree_model_sort_get_model(model_sorted));
    
        // convert the iterator to one of the raw model.
        // (Otherwise the wrong cell will change)
        GtkTreeIter iter_rawModel;
        gtk_tree_model_sort_convert_iter_to_child_iter(model_sorted, &iter_rawModel, &iter_sortedModel);
    
    
        gtk_list_store_set(model_raw, &iter_rawModel,
                                    LIST_COL_NAME, new_text, -1);
    } 
    

    Change value of a GtkListStore OR GtkTreeModelSort of GtkListStore

    Imagine you have two GtkTreeViews shown based on the same model. One is sorted, the other one not. This function will show you how to manage those.

    Note, that we now pass a GtkTreeView as gpointer, instead of GtkTreeModel.

    void onEdited_name(GtkCellRendererText *cell,
                            gchar * path_string,
                            gchar * new_text,
                            gpointer _treeview) // <--- GtkTreeView now!!!!
    {
        // we HAVE TO use GtkTreeView within gpointer!
        //  otherwise we could not differntiate the model type!
        GtkTreeView * treeview = GTK_TREE_VIEW(_treeview);
        GtkTreeModel * treeModel = gtk_tree_view_get_model(treeview);
    
        // we need to use GtkListStore, because GtkTreeModel does not
        //  provide an interface for cell changing.
        GtkListStore * model;   
        GtkTreeIter iter_rawModel;
    
        // check if we're working on the raw model or on a sorted version
        //  of it
        if(GTK_IS_LIST_STORE(treeModel)){
            // just use the model as is    
            model = GTK_LIST_STORE(treeModel);
    
            // retrieve the iterator for the cell, that should be changed
            gtk_tree_model_get_iter_from_string((GtkTreeModel*)model,
                                                &iter_rawModel, path_string);
    
        } else { // we're working on a sorted model   
            // We need to change to a usual model.
            GtkTreeModelSort * sortedModel = GTK_TREE_MODEL_SORT(treeModel);
            model = GTK_LIST_STORE(gtk_tree_model_sort_get_model(sortedModel));
    
            // get the iterator within the sorted model
            GtkTreeIter iter_sortedModel;
            gtk_tree_model_get_iter_from_string((GtkTreeModel*)sortedModel,
                                  &iter_sortedModel, path_string);  
    
            // convert the iterator to one of the raw model.
            // (Otherwise the wrong cell will change)
            gtk_tree_model_sort_convert_iter_to_child_iter(sortedModel, &iter_rawModel, &iter_sortedModel);
        }
    
    
        gtk_list_store_set(GTK_LIST_STORE(model), &iter_rawModel,
                    LIST_COL_NAME, new_text, -1);
    
    }   
    

    This is a fully functional example code for a sorted model