Gtk: how to draw on top of GtkTreeView

I would like to draw an overlay on top of a GtkTreeView using cairo.

Here’s the problem: if I connect to the “draw” signal and…

  • return false, the widget’s default draw handler gets run and my overlay gets overwritten.
  • return true, only the overlay gets drawn and not the widget

How would I be able to draw my overlay AFTER the widget’s default draw handler has been run?

Thanks in advance.

I don’t know.

But there is the https://developer.gnome.org/gobject/stable/gobject-Signals.html#g-signal-connect-after, may that be useful for your case?

Hi Henk,

Like Stefan suggests, g_signal_connect_after() is the key to get it to work. A little while back I tried an overlay over a tree. Maybe it will help. Some tree reuse here.

Eric

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

#include<gtk/gtk.h>
#include<stdlib.h>

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

static gint row_g=0;
static const gint column_g=1;

static void select_cell(GtkTreeView *tree_view, GtkTreePath *path, GtkTreeViewColumn *column, gpointer user_data)
  {
    g_print("Get Path\n");
    gchar *string=gtk_tree_path_to_string(path);
    g_print("%s %s\n", string, gtk_tree_view_column_get_title(column));
    row_g=atoi(string);
    g_free(string);

    gtk_widget_queue_draw(GTK_WIDGET(tree_view));
  }
static gboolean draw_rectangle(GtkWidget *overlay, cairo_t *cr, GtkWidget *tree_view)
  {
    g_print("Draw Rectangle %i %i\n", row_g, column_g);
    
    GtkTreePath *path=gtk_tree_path_new_from_indices(row_g, -1);
    GtkTreeViewColumn *column=gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view), column_g);

    GdkRectangle rect;
    gint x=0;
    gint y=0;
    gtk_tree_view_convert_bin_window_to_widget_coords(GTK_TREE_VIEW(tree_view), 0, 0, &x, &y);

    cairo_save(cr);
    cairo_translate(cr, x, y);
    cairo_set_line_width(cr, 2.0);
    cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 1.0);
    
    gtk_tree_view_get_cell_area(GTK_TREE_VIEW(tree_view), path, column, &rect);
    cairo_rectangle(cr, rect.x+1, rect.y+1, rect.width-1, rect.height-1);
    cairo_stroke(cr);
    cairo_restore(cr);
        
    gtk_tree_path_free(path);      

    return FALSE;
  }
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), "Overlay Tree");
    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", COLOR, "SpringGreen", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 1, PROGRAM, "Gimp", COLOR,  "SpringGreen", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 2, PROGRAM, "Inkscape", COLOR, "SpringGreen", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 3, PROGRAM, "Firefox", COLOR, "SpringGreen", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 4, PROGRAM, "Calculator", COLOR, "SpringGreen", COLOR2, "cyan", -1);
    gtk_list_store_append(store, &iter);
    gtk_list_store_set(store, &iter, ID, 5, PROGRAM, "Devhelp", COLOR, "SpringGreen", 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);

    g_signal_connect(tree, "row-activated", G_CALLBACK(select_cell), 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", COLOR, 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);

    //For drawing the outline of the cell.
    GtkWidget *overlay=gtk_overlay_new();
    gtk_widget_set_hexpand(overlay, TRUE);
    gtk_widget_set_vexpand(overlay, TRUE);
    gtk_widget_set_app_paintable(overlay, TRUE);
    gtk_overlay_add_overlay(GTK_OVERLAY(overlay), tree);
    gtk_overlay_set_overlay_pass_through(GTK_OVERLAY(overlay), tree, TRUE);
    g_signal_connect_after(overlay, "draw", G_CALLBACK(draw_rectangle), tree);
   
    GtkWidget *grid=gtk_grid_new();
    gtk_grid_attach(GTK_GRID(grid), overlay, 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(0,255,255,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;   
  }
2 Likes

@StefanSalewski it works, thank you!
@cecashon even though I’m using Java for this project, I really appreciate the code sample, thanks very much.

OK, here is the Nim version:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.