2

I would like to to have a GTK TreeView with a background image as shown in the mockup below.

I have found methods for setting the background color of widgets, but there does not appear to be a method for setting a background pixbuf or other image format.

I'm using Python with PyGTK but an answer in any language with GTK bindings is acceptable.

Mockup of gtkTreeView with background image:

Mockup of GTK TreeView with background image

First Attempt

Based on Jong Bor's advice, I tried the following:

style = treeview.get_style().copy()
img_pixbuf = gtk.gdk.pixbuf_new_from_file(image_filename)
img_pixmap = img_pixbuf.render_pixmap_and_mask()[0]
for state in (gtk.STATE_NORMAL, gtk.STATE_ACTIVE, gtk.STATE_PRELIGHT,
              gtk.STATE_SELECTED, gtk.STATE_INSENSITIVE):
    style.bg_pixmap[state] = img_pixmap
treeview.set_style(style)

At first this didn't seem to have any effect, but upon selecting an item in my TreeView I observed the following:

Selected row showing part of the background image

Part of the background 'shows through' when a row is selected.

(Note that I'm using a background image based on my mockup, except that it has some blue color, for test purposes).

I then activated part of my GUI that clears the contents of the TreeView and redraws it, and observed this:

Tiled background visible

However as soon as I add something to the TreeView the background disappears, so I'm still not sure if this is going in the right direction.

Steven T. Snyder
  • 5,847
  • 4
  • 27
  • 58
  • Does calling treeview.show_all() after populating the treeview make the background visible? Also, a hackish suggestion: since selecting a row makes the background visible, do something like treeview.get_selection().select_all() to select all rows. – Jong Bor Lee Mar 22 '11 at 19:34
  • @Jong show_all() doesn't seem to have an effect. Also, select_all() wouldn't work to show the background unless the entire TreeView is full, and even then the interface would no longer work for the user. :-/ – Steven T. Snyder Mar 22 '11 at 21:33

2 Answers2

0

Using GTK3 and gtkmm it is possible to use CSS, but the image needs to available as a file or possibly a resources.

Here I assume that the treeview is subclassed:

class MyTreeView : public Gtk::TreeView { .. };

for you treeview set a name and then add a CSS style to it:

MyTreeView::MyTreeView () {

  set_name ("MyTreeView");
  auto css = Gtk::CssProvider::create ();
  auto sc  = get_style_context ();

  string path_to_img = "my-image.png";

  string css_data =
    ustring::compose (
                    "#MyTreeView  { background-image: url(\"%1\");"
                    "               background-repeat: no-repeat;"
                    "               background-position: 50%% 50%%;"
                    " }\n"
                    "#MyTreeView  .hide_bg { background-image: none; }",
                    path_to_img);

  try {
    css->load_from_data (css_data);
  } catch (Gtk::CssProviderError &e) {
    cout "error: attempted to set background image: " << path_to_img.c_str () << ": " << e.what () << endl;
  }

  auto screen = Gdk::Screen::get_default ();
  sc->add_provider_for_screen (screen, css, GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);

}

it seems that it is also possible to set the background of the row to transparent by adding:

background: none;

to the CSS.

The background image can then be hidden or shown using:

if (!hide) {
  auto sc = get_style_context ();
  if (!sc->has_class ("hide_bg")) sc->add_class ("hide_bg");
} else {
  auto sc = get_style_context ();
  if (sc->has_class ("hide_bg")) sc->remove_class ("hide_bg");
}

enter image description here

gauteh
  • 16,435
  • 4
  • 30
  • 34
0

I suspect that since each cell has a renderer which controls its appearance, you would have to somehow modify the treeview cell by cell.

Anyway, the following code might be worth a try (untested, incomplete code):

# Get the treeview's style
style = treeview.get_style().copy()

# Change the bg_pixmap attribute
#   It's an array with one pixbuf for every widget state, so
#   you probably want to replace each of the default 
#   pixmap's with your own image(s)
#   

style.bg_pixmap[0] = your_pixmap
style.bg_pixmap[1] = your_pixmap
style.bg_pixmap[2] = your_pixmap
style.bg_pixmap[3] = your_pixmap
style.bg_pixmap[4] = your_pixmap

# Set the modified style
treeview.set_style(style)

The bg_pixmap attribute is documented in the PyGTK reference.

I'm not sure of how the array positions map to widget states. If it is the same as in c++, it will be:

0 - STATE_NORMAL    
1 - STATE_ACTIVE    
2 - STATE_PRELIGHT  
3 - STATE_SELECTED  
4 - STATE_INSENSITIVE   
Jong Bor Lee
  • 3,805
  • 1
  • 24
  • 27
  • Thanks for the suggestion. Unfortunately I tried this method and it does not have any noticeable effect. I also tried setting the `bg_pixmap` values directly (instead of copying the style first and the setting it back on the widget) and it did not work either. I think the `bg_pixmap` only affects parts of the widget where window background is visible, but the `TreeView` widget covers the window background with its white fill. – Steven T. Snyder Mar 21 '11 at 21:54
  • Kind of expected that. I edited the answer before seeing your comment to suggest that it was a long shot indeed. Since every cell has a renderer which allows changing its appearance, a brute force approach would be to modify every cell's background. Unless someone with deeper knowledge on the inner workings of Gtk can shed some light on the problem... – Jong Bor Lee Mar 21 '11 at 22:02
  • On further investigation, I've found that setting the bg_pixmap attribute does have some effect. I set each value in the bg_pixmap array to the pixmap of my image and it causes the selection color of the a selected row to be part of my image. Sometimes the image will even show up tiled as the background, but only when the TreeView is empty. I'll add a screenshot to my question. – Steven T. Snyder Mar 22 '11 at 17:19