I l@ve RuBoard Previous Section Next Section

9.6 Embedding Inline GIFs Using Tkinter

Credit: Brent Burley

9.6.1 Problem

You need to embed GIF images inside your source code�for use in Tkinter buttons, labels, etc.�to make toolbars and the like without worrying about installing the right icon files.

9.6.2 Solution

A lively Tkinter GUI can include many small images. However, you probably shouldn't require that a small GIF file be present for each of these; ensuring the presence of many small files is a bother, and if they're missing, your GUI may be unusable or look wrong. Fortunately, you can construct Tkinter PhotoImage objects with inline data. It's easy to convert a GIF to inline form as Python source code:

import base64
print "icon='''\\\n" + base64.encodestring(open("icon.gif").read(  )) + "'''"

You can then split the result into lines of reasonable length:

icon='''R0lGODdhFQAVAPMAAAQ2PESapISCBASCBMTCxPxmNCQiJJya/ISChGRmzPz+/PxmzDQyZ
DQyZDQyZDQyZCwAAAAAFQAVAAAElJDISau9Vh2WMD0gqHHelJwnsXVloqDd2hrMm8pYYiSHYfMMRm
53ULlQHGFFx1MZCciUiVOsPmEkKNVp3UBhJ4Ohy1UxerSgJGZMMBbcBACQlVhRiHvaUsXHgywTdyc
LdxyB gm1vcTyIZW4MeU6NgQEBXEGRcQcIlwQIAwEHoioCAgWmCZ0Iq5+hA6wIpqislgGhthEAOw==
'''

and use it in Tkinter:

import Tkinter
root = Tkinter.Tk(  )
iconImage = Tkinter.PhotoImage(master=root, data=icon)
Tkinter.Button(image=iconImage).pack(  )

9.6.3 Discussion

The basic technique is to encode the GIF with the standard Python module base64 and store the results as a string literal in the Python code, which will be passed to Tkinter's PhotoImage. The current release of PhotoImage supports GIF and PPM, but inline data is supported only for GIF. You can use file='filename', instead of data=string, for either GIF or PPM.

You must keep a reference to the PhotoImage object yourself; it is not kept by the Tkinter widget. If you pass it to Button and forget it, you will become very frustrated! Here's an easy workaround for this minor annoyance:

def makeImageWidget(icondata, *args, **kwds):
    if args: klass = args.pop(0)
    else: klass = Tkinter.Button
    class Widget(klass):
        def _ _init_ _(self, image, *args, **kwds):
            kwds['image']=image
            klass._ _init_ _(self, args, kwds)
            self._ _image = image
    return Widget(Tkinter.PhotoImage(data=icondata), *args, **kwds)

Using this, the equivalent of the example in the recipe becomes:

makeImageWidget(icon).pack(  )

The master argument on PhotoImage is optional; it defaults to the default application window. If you create a new application window (by calling Tk again), you will need to create your images in that context and supply the master argument, so the makeImageWidget function would need to be updated to let you optionally pass the master argument to the PhotoImage constructor. However, most applications do not require this.

9.6.4 See Also

Information about Tkinter can be obtained from a variety of sources, such as Pythonware's An Introduction to Tkinter, by Fredrik Lundh (http://www.pythonware.com/library), New Mexico Tech's Tkinter reference (http://www.nmt.edu/tcc/help/lang/python/docs.html), and various books.

    I l@ve RuBoard Previous Section Next Section