how do I dynamically resize a pixbuf cellrenderer in a treeview?

末鹿安然 提交于 2021-02-20 19:33:22



I'm using a Gtk3 TreeView that looks like above. The model is a Gtk.TreeStore

  • Gtk.TreeStore(str, GdkPixbuf.Pixbuf)

For the picture I could add to the model the correctly sized images via:

  • pixbuf.scale_simple(48,48,GdkPixbuf.InterpType.BILINEAR)

However I'm also using the model elsewhere showing the pixbufs in a different manner and the pixbufs can also be a variety of sizes.

What I would like to do is force the size of the picture displayed at run-time. The question is - how do I do that?

I tried forcing the GtkCellRendererPixbuf to be a fixed size, but this just displays the correct size image - but only the portion of the image corresponding to the fixed-size

pixbuf = Gtk.CellRendererPixbuf()

I thought of using the set_cell_data_func of the TreeViewColumn:

col = Gtk.TreeViewColumn('', pixbuf, pixbuf=1)
col.set_cell_data_func(pixbuf, self._pixbuf_func, None)

def _pixbuf_func(self, col, cell, tree_model, tree_iter, data):
    cell.props.pixbuf = cell.props.pixbuf.scale_simple(48,48,GdkPixbuf.InterpType.BILINEAR)

This does do the dynamic resizing of the image at runtime - BUT in the terminal I get hundreds of errors such as this:

sys:1: RuntimeWarning: Expecting to marshal a borrowed reference for <Pixbuf object at 0x80acbe0 (GdkPixbuf at 0x87926d0)>, but nothing in Python is holding a reference to this object. See:

I also tried the alternative by resizing treemodel pixbuf instead of the cell.props.pixbuf but this also gives the same error as above.

cell.props.pixbuf = tree_model.get_value(tree_iter,1).scale_simple(48,48,GdkPixbuf.InterpType.BILINEAR)

So obviously this is not the correct way of doing this - so any thoughts how else to approach this? Any links to example code Gtk3 based C++/Python would be most welcome.

I'm using Gtk+3.6 / python 2.7


Old question, but sadly still relevant - this bug in Gtk still exists. Fortunately there's a pretty easy workaround. All you need to do is to keep a reference to the scaled pixbuf.

I've altered the _pixbuf_func function so that it accepts a dictionary in which it stores the small pixbufs. This gets rid of the annoying warning message and also prevents the pixbuf from being downscaled every single time _pixbuf_func is called.

def pixbuf_func(col, cell, tree_model, tree_iter, data):
    pixbuf= tree_model[tree_iter][1] # get the original pixbuf from the TreeStore. [1] is
                                     # the index of the pixbuf in the TreeStore.
        new_pixbuf= data[pixbuf] # if a downscaled pixbuf already exists, use it
    except KeyError:
        new_pixbuf= pixbuf.scale_simple(48,48,GdkPixbuf.InterpType.BILINEAR)
        data[pixbuf]= new_pixbuf # keep a reference to this pixbuf to prevent Gtk warning
                                 # messages
    cell.set_property('pixbuf', new_pixbuf)

renderer = Gtk.CellRendererPixbuf()
col = Gtk.TreeViewColumn('', renderer)
col.set_cell_data_func(renderer, pixbuf_func, {}) # pass a dict to keep references in

A problem with this solution is that you have to remove the stored Pixbufs from the dict whenever the contents of your TreeStore change, otherwise they'll stick around forever and your program will consume more memory than necessary.