Gtk treeview cell color change

In my GTK+3 application , i have a treeview table and i am using gtkcellrenderer for adjusting the rows Can anyone guide me how to change the color of a particular cell alone and not full column

Are you using the treeview with a GtkListStore or a GtkTreeStore? You can add a GdkRGBA field to the GtkListStore (or GtkTreeStore) and use gtk_tree_view_column_add_attribute to link the “cell-background-rgba” property of the cell to the data in the GtkListStore.

https://developer.gnome.org/gtk3/stable/GtkTreeViewColumn.html#gtk-tree-view-column-add-attribute
https://developer.gnome.org/gtk3/stable/GtkCellRenderer.html#GtkCellRenderer--cell-background-rgba

You may read the chapter 5 here: http://scentric.net/tutorial/treeview-tutorial.html

Hi Nishanth,

You can use GdkRGBA or HTML colors to change the color on individual cells in a treeview. Give the following a try and see if it helps.

Eric

   
//gcc -Wall cell_color1.c -o cell_color1 `pkg-config --cflags --libs gtk+-3.0`

#include<gtk/gtk.h>

enum
{
   ID,
   PROGRAM,
   COLOR1,
   COLOR2,
   COLUMNS
};

int main(int argc, char *argv[])
  {
    gtk_init(&argc, &argv);

    GtkWidget *window=gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "Select Cell");
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(window), 500, 500);
    gtk_container_set_border_width(GTK_CONTAINER(window), 20);
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

    GtkTreeIter iter;
    GtkListStore *store=gtk_list_store_new(COLUMNS, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 0, PROGRAM, "Gedit", COLOR1, "DarkCyan", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 1, PROGRAM, "Gimp", COLOR1,  "LightSlateGray", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 2, PROGRAM, "Inkscape", COLOR1, "DarkCyan", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 3, PROGRAM, "Firefox", COLOR1, "LightSlateGray", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 4, PROGRAM, "Calculator", COLOR1, "DarkCyan", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 5, PROGRAM, "Devhelp", COLOR1, "LightSlateGray", COLOR2, "cyan", -1);

    GtkWidget *tree=gtk_tree_view_new_with_model(GTK_TREE_MODEL(store));
    gtk_widget_set_hexpand(tree, TRUE);
    gtk_widget_set_vexpand(tree, TRUE);
    g_object_set(tree, "activate-on-single-click", TRUE, NULL);

    GtkTreeSelection *selection=gtk_tree_view_get_selection(GTK_TREE_VIEW(tree));
    gtk_tree_selection_set_mode(selection, GTK_SELECTION_SINGLE);

    GtkCellRenderer *renderer1=gtk_cell_renderer_text_new();
    g_object_set(renderer1, "editable", FALSE, NULL);

    GtkCellRenderer *renderer2=gtk_cell_renderer_text_new();
    g_object_set(renderer2, "editable", TRUE, NULL);
   
    //Bind the COLOR column to the "cell-background" property.
    GtkTreeViewColumn *column1=gtk_tree_view_column_new_with_attributes("ID", renderer1, "text", ID, "cell-background", COLOR1, NULL);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column1);    
    GtkTreeViewColumn *column2 = gtk_tree_view_column_new_with_attributes("Program", renderer2, "text", PROGRAM, "cell-background", COLOR2, NULL);
    gtk_tree_view_append_column(GTK_TREE_VIEW(tree), column2);
   
    GtkWidget *grid=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid), tree, 0, 0, 1, 1);

    gtk_container_add(GTK_CONTAINER(window), grid);

    gchar *css_string=g_strdup("treeview{background-color: rgba(0,255,255,1.0); font-size:30pt} treeview:selected{background-color: rgba(255,255,0,1.0); color: rgba(0,0,255,1.0);}");
    GError *css_error=NULL;
    GtkCssProvider *provider=gtk_css_provider_new();
    gtk_css_provider_load_from_data(provider, css_string, -1, &css_error);
    gtk_style_context_add_provider_for_screen(gdk_screen_get_default(), GTK_STYLE_PROVIDER(provider), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
    if(css_error!=NULL)
      {
        g_print("CSS loader error %s\n", css_error->message);
        g_error_free(css_error);
      }
    g_object_unref(provider);
    g_free(css_string);
   
    gtk_widget_show_all(window);

    gtk_main();
    return 0;   
  }
1 Like

Nice example.

C version works fine, I will consider making a Nim version again, as it contains a few still untested functions of the Nim bindings.

[Edit]

Indeed a few untested Nim functions :slight_smile:
So I guess Nim version will take me more than a few minutes – I may do it next weekend.

After a closer look at your code, I wonder about two points:

  1. Why use a grid with only one cell occupied. I think I saw you doing that in another example too, and I just removed that unneeded container that time.

  2. g_strdup() I can not imagine that it necessary here. You do not modify the string literal at all, so passing a string literal, which should live in a BSS data segment, should be fine. No need to allocate it on the heap. And I would guess, but I am not sure, a char* living on the stack should be ok too, as gtk_css_provider_load_from_data() should need the string only for the duration of the function call, but not any more when that function has terminated? What do you think?

Hi Stefan,

I have a tendency to start with a grid since it is common to start adding more widgets in test code. It isn’t needed here. The g_strdup isn’t needed either. I used it when creating different CSS strings for different versions of GTK. Might like it for readability on my netbooks small screen. I also left out a g_object_unref(store) which is probably good to have even though everything here is in main(). Usually you don’t need to keep track of reference counting. You might want to be reminded of when you should keep track.

Hopefully it works with Nim. I think that it is not uncommon to want to be able to color cells in a treeview.

Eric

I have just done the initial port to Nim – seems to work fine so far.

What I wonder about: The font size of your C code example as well as my Nim port is very large. First I thought you did it by intent, but I have seen no special code for selecting a large font. See this example picture:

Picture is generated by your original C version. Well, I have a 4k 27 inch display, but as all font sizes of other tools are fine, it should be fine for your example too. This is for gtk±3.24.10:3::gentoo, gnome-3.30.2:2.0::gentoo Wayland. Do you have an idea?

For the font size I was just trying to show some of the things that you can change in CSS that will change the treeview. It was intended. Also how the treeview selection can be changed there.

A 4k display sounds pretty nice. I still have a netbook that I put in the backpack and walk over to the library with. Displays are tricky. Recently I had some trouble matching points to pixels on a saved picture. I can do this on my display but it relies on Rsvg using a default value of 90 and my program saving the picture with this value. As long as the picture doesn’t get rasterized it shouldn’t matter much since the vector graphics can always be scaled. So you get a relative scale and with GTK you can still scale some things with CSS and have a relative scale work with a program. There are a lot of things you can do with CSS.

Eric

Ah yes, size is contained inside the css_string, I totally missed that.

For the 4k display – I have it since two years, was mostly working well with GTK/Gnome but not fully well. Before I was using the Gnome webbrowser, but that one was not working well for many web pages. I switched to Firefox, which scales all well. maybe it has improved now, I should try again.

OK, I have shipped the Nim version to github:

You previous example with big cairo images compiles and works also now.

One point I have observed in your original C code as well as in the Nim version: We can edit the program name strings in the listview, but when we hit enter the old original name appears again.

Hi Stefan,

For updating the row in the treeview you can use the “edited” callback of the text renderer. That would probably useful.

https://developer.gnome.org/gtk3/stable/GtkCellRendererText.html#GtkCellRendererText-edited

Eric

g_signal_connect(renderer2, "edited", G_CALLBACK(update_row), tree);
...
static void update_row(GtkCellRendererText *renderer, gchar *path, gchar *new_text, GtkWidget *tree)
  {
    GtkTreeIter iter;
    GValue value=G_VALUE_INIT;
    g_value_init(&value, G_TYPE_STRING);
    GtkTreeModel *store=gtk_tree_view_get_model(GTK_TREE_VIEW(tree));    
    g_value_set_static_string(&value, new_text);
    GtkTreePath *tree_path=gtk_tree_path_new_from_string(path);
    gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, tree_path);
    gtk_list_store_set_value(GTK_LIST_STORE(store), &iter, 1, &value);
    gtk_tree_path_free(tree_path);
    g_value_unset(&value);
  }

Ah yes, now I remember. I read that 10 years ago in the book of A. Krause :slight_smile:

I have added that code to the Nim example, so it is more complete.

I assume that

g_value_unset(&value);

in your C code is useless here, as value is located on the stack and we do not intent to reuse it inside of the function. It is created again fresh when that callback function is called again. Or do you think it is necessary to free any resources? It is not absolutely clear from API docs.

You are right. I looked in gvaluetypes.c and g_value_set_static_string() just copies the pointer over so you don’t need g_value_unset(). If you use g_value_set_string() then the string would be duplicated and you would need to use g_value_unset() to free the copy.

Eric