Search code examples
imagepython-3.xresizegtkintrospection

how to do automatic image resizing in Python3 with PyGI?


Although I have found partial and indirect answers to this question (see, e.g., this link), I am posting this here because putting together the bits and pieces of the puzzle took me a bit of time, and I thought someone else might find my efforts of use.

So, how to achieve a seamless resizing of images on buttons in GTK+ when the parent window is resized?


Solution

  • The solution offered for PyGTK in the link posted in the question does not work in Python-GI with GTK3, although the trick of using a ScrolledWindow in place of the usual Box was very useful.

    Here is my minimal working solution to getting an image on a button to resize with the container.

    from gi.repository import Gtk, Gdk, GdkPixbuf
    
    class ButtonWindow(Gtk.Window):
    
        def __init__(self):
            Gtk.Window.__init__(self, title="Button Demo")
            self.set_border_width(10)
            self.connect("delete-event", Gtk.main_quit)
            self.connect("check_resize", self.on_check_resize)
    
            self.box = Gtk.ScrolledWindow()
            self.box.set_policy(Gtk.PolicyType.ALWAYS,
                           Gtk.PolicyType.ALWAYS)
            self.add(self.box)
    
            self.click = Gtk.Button()
            self.box.add_with_viewport(self.click)
    
            self.pixbuf = GdkPixbuf.Pixbuf().new_from_file('gtk-logo-rgb.jpg')
            self.image = Gtk.Image().new_from_pixbuf(self.pixbuf)
            self.click.add(self.image)
    
        def resizeImage(self, x, y):
            print('Resizing Image to ('+str(x)+','+str(y)+')....')
            pixbuf = self.pixbuf.scale_simple(x, y,
                                              GdkPixbuf.InterpType.BILINEAR)
            self.image.set_from_pixbuf(pixbuf)
    
        def on_check_resize(self, window):
            print("Checking resize....")
    
            boxAllocation = self.box.get_allocation()
            self.click.set_allocation(boxAllocation)
            self.resizeImage(boxAllocation.width-10,
                             boxAllocation.height-10)
    
    win = ButtonWindow()
    win.show_all()
    Gtk.main()
    

    (The -10 on the width and height are to accommodate the inner borders and padding in the button. I tried fiddling with this to get a bigger image on the button, but the result did not look so nice.)

    The jpeg file used in this example can be downloaded from here.

    I welcome further suggestions on how to do this.