FAQ Index - Search - Recent Changes - Everything - Add entry

Last changed on Sat Apr 20 23:03:22 2013 CDT

(Entries marked with ** were changed within the last 24 hours; entries marked with * were changed within the last 7 days.)


1. General information and availability


2. Changes from 1.2 to 1.3/2.0


3. Signal handling


4. Themes, fonts and styles


5. Basic Objects: GObject, GtkWidget and other critters


6. Widget subclasses and user signals: GObject


7. Labels: GtkLabel


8. Images: GtkImage, GtkPixmap, GdkPixbuf


9. Buttons: GtkButtons


10. Windows: GtkWindows and GtkDialogs


11. Menus: Gtk*Menu and Gtk*MenuItem GtkToolbar


12. Simple Containers: GtkBoxes, GtkTable, GtkFixed, GtkAlignment


13. Lists and Trees: GtkList/TreeView


14. Editables: GtkEntry, GtkCombo, GtkText, GtkSpinButton, GtkTextView


16. GtkOptionMenu, GtkComboBox, GtkComboBoxEntry


17. GtkNoteBook


18. GtkDrawingArea


19. Other widgets


20. The GTK Mainloop and Threading


21. Win32 and PyGTK


22. libglade


23. Miscellaneous questions


24. Deprecated List Widgets: GtkList, GtkCList, GtkCTree and others


1. General information and availability

1.1. What is PyGTK?

PyGTK (a.k.a python-gtk or gtk-python) is a set of bindings to the GTK+ user interface toolkit for the Python language. The main site to look for more information on these bindings is [www.pygtk.org] . There, new releases, news, reference docs, tutorials, applications built on top of it and other information can be found.

Python is an interpreted language with a very clean syntax, high-level data structures, dynamic typing, object oriented characteristics and generally acceptable performance. For more information on Python see [www.python.org]

GTK+ is a graphical user interface toolkit, which includes user interface components (hereafter called by the usual name widgets) and a framework for handling events that are produced upon these components. For more information on GTK+ see [www.gtk.org]

A binding is code (usually a library) that allows you to access functions that were coded in another language. In our case, GTK+ was written in C, and applications written in C can use native GTK+. For a Python program to be able to create applications using the GTK+ framework, a special library has to be used. This library is PyGTK.

1.2. Where can I get PyGTK?

The reference site to track PyGTK releases and news is [www.pygtk.org] . The Downloads section has links to the proper sources for pygtk binaries and sourcecode. Anyhow, here there are some of those links:

PyGTK has a number of optional dependencies you must have installed before compiling if you want to use them. For PyGTK2:

For PyGTK0.6:

1.3. How do I get the very latest PyGTK source code [from git]

PyGTK is kept in gnome git; the module name for PyGTK is "pygtk". The module name for gnome-python is "gnome-python", so to check it out, type:

  git clone git://git.gnome.org/pygtk
and possibly:

  git clone git://git.gnome.org/gnome-python
  git clone git://git.gnome.org/gnome-python-desktop
  git clone git://git.gnome.org/gnome-python-extras
Please note that to use PyGTK you rely on recent code for GTK+ , GLib, atk, pango, Python. How recent exactly these dependencies need to be depends largely on the current target for the PyGTK development team. In general, CVS HEAD will use the latest CVS, but ask on the mailing list if problems arise.

1.4. What is the password to change and add FAQ entries?

Just email kiko@async.com.br , and I'll send you a message with the password. There are no special requirements or qualifications that you must have; basically, being willing and able to work on the FAQ entries is enough.

We only use the password to allow a minimum of control over FAQ changes, and you are of course invited to help maintain it.

1.5. How do I get support for PyGTK [mailing lists, IRC]?

[www.pygtk.org] is the reference site for the PyGTK bindings and there you can find more help and resources.

The standard way to get some support is to join the PyGTK mailing list. You can sign up using a webform at [www.daa.com.au] The mailing list is searchable via Gmane: [news.gmane.org]

We also run a channel for pygtk support on IRC. This channel is run on server irc.gnome.org and it's called #pygtk. Stop by and say hello once in a while.

If you want to check out existing bug reports for pygtk, you can use the query interface at [bugzilla.gnome.org] to query for bugs reported against the gnome-python module. I've added two links for easy queries here:

Open bugs (UNCONFIRMED, NEW or ASSIGNED): [bugzilla.gnome.org]

All bugs ever reported: [bugzilla.gnome.org]

Finally, there is an open wiki at [live.gnome.org]

1.6. Eeek, I found a bug in PyGTK. Where do I report it?

Okay, you found a bug. The standard procedure is:

a) Test against the latest git version of PyGTK, if you can. This helps catch errors that have already been fixed but haven't migrated into a release.

b) If you are unsure it's a bug, make a request discussing it on the mailing list, or present it to the IRC channel.

c) File a new bug on the pygtk product at GNOME Bugzilla [bugzilla.gnome.org] Remembering the bug number will help when referencing the bug through email. Bugs make remembering problems a lot easier by making sure problems are uniquely identified in a simple and focused way.

Remember, a great deal of help can be provided by a good bug report. Including a testcase will make fixing MUCH easier, and if that's impossible, listing the exact steps to reproduce will help too.

d) If you can, write some code to fix the bug and attach a patch in the unified diff format against current git ("git format-patch" will do the job) to the bug reported. After the patch has been reviewed and approved by someone on the PyGTK developer team, it can be checked in to git -- usually a member of the team will check it in for you if you don't have a git account on git.gnome.org. The next release will include the fix.

More information on bugzilla, the bug tracking tool GNOME uses, can be found in the Using Bugzilla section of the Bugzilla manual: [www.bugzilla.org]

1.7. Where are the reference manuals?

John Finlay has done amazing work in producing a reference manual for PyGTK2. The last html version of that manual (and a tarball) is always linked to from [www.pygtk.org] and it is the authoritative document on PyGTK itself.

The most complete functional reference for the underlying GTK+ and GDK libraries lives at [www.gtk.org] , and it covers the native C bindings. The mapping from the C API to Python is quite straightforward, and the reference is actually quite thorough.

The source code contains examples that are quite helpful (specially testgtk.py, which includes many widgets and features) in the examples/ directory. The gtk.py file itself is a worthy reference (praise to Python's readability there) and many times will solve a prototype, api or parameter question.

pygtk2 additionally includes docstrings for many of the classes and methods available, which you can inspect from an interactive session:

  >>> import gtk
  >>> help(gtk.Window)
  Help on class Window in module gtk:

  class Window(Bin)
   |  Object GtkWindow
   |  
   |  Signals from GtkWindow:
   |    set-focus (GtkWidget)
   |    frame-event (GdkEvent) -> gboolean
   |    activate-focus ()
   |    activate-default ()
   |    keys-changed ()
   [...]

1.8. I need PyGTK/libglade compiled for [insert Unix OS here]!

Very basically, grab source from links in questions 1.2 or 1.3, and do a

 cd /usr/src/pygtk-0.9.9 # we wish :-)
 ./configure
 make 
 make install
For Redhat 7.1, James Henstridge himself said:

You may as well compile it yourself. Just make sure you have the python2-devel RPM installed on your system, along with the -devel rpms for gtk+, glib, and the other modules you want to be able to use. Then run the following commands:

  PYTHON=/usr/bin/python2 ./configure --prefix=/usr
  make
  make install

1.9. Are there any PyGTK tutorials available?

The official tutorials are hosted at [www.pygtk.org] -- there are both HTML versions and tarballs for download. This entry lists a few articles published, but there is a list kept better up to date at [www.pygtk.org]

(People looking for a GObject tutorial should take a peek at FAQ 6.1.)

1.10. I have multiple copies of python but pygtk only works with one of them!

Python stores all its extension modules in a directory $(prefix)/lib/pythonX.Y where X.Y is the major and minor version of the release. This is to guard against changes to the Python C API between releases. As with all other extension modules, one version must be compiled for each python version.

If you built pygtk for one copy of python on your system (or if you are using packages from your distribution), it will probably not be available on the others.

You will probably need to build pygtk for the other python installations. To do this, set the PYTHON environment variable to the full path of the alternative python before running pygtk's configure script. For example to build pygtk for the python 2.x distributed with Red Hat 7.x, do the following:

  PYTHON=/usr/bin/python2 ./configure --prefix=/usr
  make
  make install

1.11. How do I extend PyGTK (or the art of wrapping)

In order to make a new wrapper for PyGObject/PyGTK, you can use this FAQ as a guideline or checklist. Don't miss out FAQ 6.3 which has a link to an online article, additionally.

Let's call the library "foo" (how original)

1) foo.defs.

   h2defs.py /usr/include/foo-1.0/*.h > foo.defs
2) foomodule.c

3) foo.override

4) Makefile.am

  AUTOMAKE_OPTIONS=1.5

  INCLUDES = $(PYTHON_INCLUDES) $(FOO_CFLAGS)

  # foo module
  pyexec_LTLIBRARIES = foomodule.la
  foomodule_la_LDFLAGS = -module -avoid-version -export-symbols-regex initfoo
  foomodule_la_LIBADD = $(FOO_LIBS)
  foomodule_la_SOURCES = foomodule.c
  nodist_foomodule_la_SOURCES = foo.c
  foo.c: foo.defs foo.override
  CLEANFILES = foo.c
  EXTRA_DIST = foo.override

  .defs.c:
        (cd $(srcdir)\
         && $(PYTHON) codegen/codegen.py \
            --override $*.override \
            --prefix py$* $*.defs) > gen-$*.c \
        && cp gen-$*.c $*.c \
        && rm -f gen-$*.c

 ---
 Should be enough for you to get started
5) configure.in

  PKG_CHECK_MODULES(FOO, foo >= 1.2,,)
  AC_SUBST(FOO_CFLAGS)
  AC_SUBST(FOO_LIBS)
Finally, copy autogen.sh and hopefully you'll have most functions wrapped.

Eventually you'll have to wrap a few functions by hand, functions that the code generator cannot handle. Mostly functions with inout params (**) and GSList/GList parameters.

1.12. Where can I find the API documentation ?

James Finlay has written an excellent API documentation for PyGTK and you'll be able to find them online at [www.pygtk.org] There are tarballs of the docs available at the same location.

1.13. Where can I get gnome-python?

All versions of gnome-python are available from [ftp.gnome.org]

1.14. How do I compile pygtk or gnome-python from SVN?

You need the GTK+ 2.x libraries, as you'd expect (see FAQ 21.2). There are three packages you want to build:

You should run

 ./autogen.sh
 make
 make install
in each of these, in that order. If you want to build from SVN, you might want to look at a build script. James recommends jhbuild (also in GNOME svn).

If you want to install them to a separate prefix, eg if you don't have write access to /usr/local, use --prefix as an argument to autogen.sh or configure, eg:

  ./configure --prefix /home/user/prefix
And then, don't forget to set PYTHONPATH before running the program, eg:

  export PYTHONPATH=/home/user/prefix/lib/python2.3/site-packages
Then you can finally run your program.

For additional information on how to use configure, see the INSTALL file which is included in the source tarball or subversion.

1.15. How do I tell what version of PyGTK I'm running?

Get your version of PyGTK:

  >>> import gtk
  >>> gtk.pygtk_version
  (2, 17, 0)
Get your version of GTK+:

  >>> import gtk
  >>> gtk.gtk_version
  (2, 20, 1)

1.16. I wrote a patch for PyGTK that fixes bug X, or implements feature Y, what do I do?

The best way to make sure your patch is reviewed and evaluated is to file a bug on Gnome's bugzilla server, specifying the gnome-python product, pygtk component. The link to file a new bug directly is here: [bugzilla.gnome.org]

Patches should be sent in the unified diff format (the -u flag). A good set of flags is -urNp -- look up man cvs if you're curious. It's a good idea to produce the patch against the CVS version -- see FAQ 1.3 for information on getting pygtk from CVS.

Patches sent to the mailing list may be reviewed and checked in, but they may also be deleted without reading when the maintainers are too busy. Use bugzilla to be on the safe side and make sure your work is not wasted.

1.17. How do I search Bugzilla for PyGTK bugs

Go to [bugzilla.gnome.org] and in the Product box select 'pygtk'. You may then specify the version, OS and any other relevant information.

If I am trying to do a general query, it helps to "select all" in these boxes by clicking on the first entry and then shift clicking on the last entry. You may also want to activate all the 'Status' entries to see resolved bugs, etc.

Once you have configured all these parameters, go to the Text information section, enter your search terms in the Description or Summary boxes, and click 'Submit Query'.

1.18. My programs configure says: No package 'pygtk-2.0' found

That's because the configure script can't find the installed version of pygtk-2.0.

If you build pygtk on your own, from source, then you need to write the following before running the configure script:

  export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig
Or, replace /usr/local with the prefix you installed pygtk to. /usr/local is however the default and most commonly used one.

If you did not install it from source then it means that you forgot to install the devel/dev package. For Red Hat based distributions (Fedora, SuSe, Mandrake etc) you need to install pygtk2-devel and for debian based distributions you need to install pythonX.Y-gtk2-dev, where X.Y stands for the python version you're using.

1.19. Is there a PyGTK for MacOS X?

There are two ways of running PyGTK on OS X.

One way is running it with native support, which is still in early stages of development and is not feature complete yet. There are currently (as of June 2008) no available binaries for GTK+ running natively under OSX, so you need to compile GTK+ yourself. For more information about the native port check out Imendio's page [developer.imendio.com] . The instructions here tell you how to build GTK+, but not PyGTK; after following the steps here you also must do "jhbuild build meta-gtk-osx-python".

The second way is using Apple's X11 server, which is closer to other Unix systems for portability, but won't integrate very well with the rest of the OS X desktop. If you are running Mac OS X 10.3 (Panther) or above X11 is available as an optional feature from the install CDs. In addition the X11 server can be downloaded from [www.apple.com] . Unfortunately Apple doesn't have an obvious link to the older versions for Mac OS X 10.2, but VersionTracker has a link: [www.versiontracker.com]

You can get the gtk libraries under OS X via darwinports from [darwinports.opendarwin.org]

Daniel Macks and Ben Hines <bhines at alumni dot ucsd dot edu> have also put work into making packages available via Fink on the unstable tree: GNOME at [fink.sourceforge.net] and pygtk 2 specifically at [fink.sourceforge.net] . As of June 2008, Fink does not have pygtk available for Python 2.5 or OS X 10.5 (Leopard).

1.20. Can I use PyGTK to build closed-source applications?

PyGTK is licensed under the LGPL license so it's perfectly legal to build non-open-sourced applications; two examples of closed source applications that are built using PyGTK are WingIDE and Point2Play. Note however that the fact that the program will be written in Python does present challenges in distributing the software and restricting access to source code. Some information on this topic can be found at [www.experts-exchange.com] -- but also note that information on decompiling python bytecode can be found at [www.crazy-compilers.com]

1.21. Does PyGTK have timers?

The answer is yes! The function you are looking for is gobject.timeout_add() (or gobject.timeout_add_seconds() for longer periods).

See [nkour.blogspot.com] for a very easy example on how to use timers in PyGTK


2. Changes from 1.2 to 1.3/2.0

2.1. How do I install PyGTK-2 and PyGTK-0 side by side in the same system?

It used to be that if you installed PyGTK-2 and PyGTK-0.x in a same version of Python, the applications that required PyGTK-0.x would stop working. This happened because Python would import PyGTK-2 preferentially, and the names of the modules are the same: 'gtk'.

(There are three different ways detailed to solve this problem, but I will not recommend methods 2 and 3 unless you are unable to upgrade to a version that supports method 1).

For PyGTK >= 0.6.10, gnome-python >= 1.4.3 or pygtk2 >= 1.99.13 ONLY! (See faq 2.5)

(Note that RedHat 8.0 ships versions PRIOR to these, you will need to either upgrade the system packages, or use method 2 if you want to install PyGTK-0 and PyGTK-2 together on RH8.)

James has added to pygtk a mechanism that allows installation of both pygtk and pygtk2 to work side by side. This method should be transparent - you can install both versions and simply require one or the other for each program you need (the default being the one you install last), as per faq 2.4. It is implemented by using a pygtk.pth file that indicates which is the default (which one `import gtk' uses) version.

Note that pygtk.pth only works if you use the *default python install path* - if you specify a --prefix to configure it will not work and you will *have to use method 2*!

You can install the two conflicting versions to a different prefix. When configuring pygtk2, use something like:

 ./configure --prefix=/usr/local/gtk2/
All pygtk2 files will be installed in this case to

 /usr/local/gtk2/lib/pythonX.Y/site-packages/
With X.Y replaced by the major and minor numbers in your python version. You will then need to adjust PYTHONPATH (or sys.path) to look at the correct version for the program you want to run. If it requires pygtk2, you could use something like:

 export PYTHONPATH=/usr/local/gtk2/lib/pythonX.Y/site-packages/:$PYTHONPATH

You can change PyGTK-2.x's module name to something else. Thomas Leonard has released a patched version that renames the module name to gtk2, available publically at [west.dl.sourceforge.net] See [rox.sourceforge.net] for more information. To use this version, change the first line of your PyGTK-2 programs from

 import gtk
to

 import gtk2 as gtk
This module is not up to date, however, and this is the least recommended method.

2.2. What are the major changes in PyGTK-2 for GTK+ 2.2?

The new PyGTK-2 is not fully compatible with the old one. There are a few things you will need to do to convert your app:

 - GtkText (replaced by GtkTextBuffer/GtkTextView)
 - GtkTree and GtkTreeItem (replaced by GtkTreeView and GtkTreeModel)

Overall, PyGTK-2 should be a much nicer PyGTK to program with. If you are working on new code, it would be best to use PyGTK-2 instead of 0.6.x.

What's more, there is even some documentation for PyGTK-2, available at [www.gnome.org]

2.3. Is there a checklist of changes to migrate an application from PyGTK-0 to PyGTK-2?

Well, the start of one, thanks to LordVan ([www.lordvan.com] )

  import pygtk
  pygtk.require('2.0')
  import gtk
 * use import gtk instead
 * from gtk import *
 * s/mainloop/gtk.mainloop/g # and other functions calls like 'mainquit'
 * s/Gtk/gtk./g
 * s/Gtk//g
 -         win = GtkWindow(title="Foo bar baz")
 +         win = gtk.Window()
 +         win.set_title("Foo bar baz")
 -         label = GtkLabel(label="Foobar")
 +         label = gtk.Label("Foobar")
 -         self.text = GtkText()
 +         self.textbuffer = gtk.TextBuffer(None)
 +         self.text = gtk.TextView()
 +         self.text.set_buffer(self.textbuffer)

 -         self.text.insert_defaults( use_var )
 +         self.textbuffer.insert_at_cursor( use_var,len(use_var) )

  entry = gtk.Entry()
  font_desc = pango.FontDescription('monospace')
  entry.modify_font(font_desc)

  entry = gtk.Entry()
  entry.realize()
  win = entry.window

  drawingarea.window.draw_point()

 gc.set_clip_rectangle((x, y, width, height))

 option_menu=tree.get_widget("optionmenu1")
 sometext=option_menu.get_children()[0].get()

2.4. If I installed PyGTK-0 and PyGTK-2 in parallel (using pygtk.pth) how do I indicate which one my script should use?

The new versions of PyGTK (see faq 2.1) provide a pygtk module in which you can call a method require() that allows you to request one version or the other:

 pygtk.require("1.2") # for pygtk-0
and

 pygtk.require("2.0") # for pygtk2
Note that you should do this before importing the gtk or gnome modules:

 # To require 2.0 
 import pygtk
 pygtk.require("2.0")
 import gtk, gtk.glade, gnome, gnome.ui
or:

 # To require 1.2
 import pygtk
 pygtk.require("1.2")
 import gtk, libglade, gnome, gnome.ui
If this simply doesn't work, please visit FAQ 2.6 for the nitty-gritty.

2.5. Which versions of PyGTK support parallel install using the pygtk.pth method?

James Henstridge and Johan Dahlin implemented parallel install support in versions:

 - pygtk-0.6.10
 - gnome-python-1.4.3
 - pygtk2-1.99.13
So any version equal to or later than that is fine. Note that 0.6.10 and 1.4.3 had bugs in it, and you should upgrade to 0.6.11 and 1.4.4 if possible.

Note that these versions are more recent than the version shipped in RedHat 8.0, so RH8.0 does NOT support parallel install using method 1 described in faq 2.4.

2.6. FAQ 2.4 sucks and doesn't work. Truthfuly, how do I require a specific version of PyGTK (or When do I need to use pygtk.require())?

It depends (doesn't that always suck?).

If you installed pygtk to a non-standard directory (i.e., not in your python installation's site-packages directory), you will need to manually set pythonpath accordingly, and take care of python versions youself (checking pygtk_version, for instance). If you installed it into a standard directory, read below.

We have now a concept of a `default pygtk version'. This is the version that you get if you do a simple 'import gtk' in Python. Precisely which is the default version varies:

To *make sure* you get the right version, you can use:

  import pygtk
  pygtk.require("1.2") # or 2.0 etc
Which I recommend for maximum cross-site functionality. HOWEVER, not all versions of pygtk offer the pygtk module (again, see faq 2.5). So to do the right thing, you need to wrap that in a try/except clause, and use a check for the previous versions. Something like the following should work if you want to make sure you have version 1.2:

 # Make sure we have version 1.2. Swap for 2.0 as necessary.

 def get_gtk():
   print """You need to get version 0.6 of PyGTK for this to work. You 
            can get source code from http://ftp.gnome.org/pub/gimp/gtk/python/v1.2/ """
   raise SystemExit

 try:
   import pygtk
   pygtk.require("1.2")
 except ImportError:
   try:
     import gtk   
   except ImportError:
     get_pygtk()
   if not hasattr(gtk, "GtkWindow"): # renamed in version 2.0
     get_pygtk()
 except AssertionError:
   get_pygtk()

  import gtk # we KNOW this is 1.2 at this point
  [...]
[The whole pygtk.pth handling has shown itself to be something of a mess, unfortunately, and a separate gtk2 namespace might have saved us some trouble, IMHO. - Kiko]

2.7. What happened to the GTK and GDK constants/symbols?

The GTK_* constants have been mapped to gtk.* constants, and the GDK_* constants to gtk.gdk.*. The one caveat is that python identifiers can't start with a number. As is done in a few other Python extension modules, pygtk will prefix these constants with an underscore.

So GDK_2BUTTON_PRESS is wrapped as gtk.gdk._2BUTTON_PRESS, while GDK_BUTTON_PRESS is gtk.gdk.BUTTON_PRESS (no underscore).

One exception is the keysyms constants. They are accesed through gtk.keysyms.KEY. To see the legal values of KEY just do a

    import gtk
    print dir(gtk.keysyms)

Robert Park explained the C enumeration naming rule in PyGObject inspection as of v2.26 [1]:

... the file /usr/share/gir-1.0/Gtk-2.0.gir holds all the answers. It's the introspection data in XML format, so it's mostly human readable.

For example, I needed to know the new name for the constant Gtk.TREE_VIEW_COLUMN_AUTOSIZE, so I searched through the .gir file, and eventually found this:

    <enumeration name="TreeViewColumnSizing"
                 glib:type-name="GtkTreeViewColumnSizing"
                 glib:get-type="gtk_tree_view_column_sizing_get_type"
                 c:type="GtkTreeViewColumnSizing">
      <member name="grow_only"
              value="0"
              c:identifier="GTK_TREE_VIEW_COLUMN_GROW_ONLY"
              glib:nick="grow-only"/>
      <member name="autosize"
              value="1"
              c:identifier="GTK_TREE_VIEW_COLUMN_AUTOSIZE"
              glib:nick="autosize"/>
      <member name="fixed"
              value="2"
              c:identifier="GTK_TREE_VIEW_COLUMN_FIXED"
              glib:nick="fixed"/>
    </enumeration>
The new name of the constant is going to be "Gtk" plus the enumeration name "TreeViewColumnSizing", plus the member name "autosize" in ALL CAPS, separated by periods. So: Gtk.TreeViewColumnSizing.AUTOSIZE

On Debian, Gtk-2.0.gir can be found in the package gir-repository-dev.

More hints on PyGobject porting can be found in the pygi-convert script mentioned in PyGObject Introspection Porting page [live.gnome.org] .

[1]: [www.mail-archive.com]

2.8. For some users import libglade (or GDK) is working and for some users it's not

It's possible that at the top of your script you have #!/usr/bin/env python as the script interpreter line. This searches the path for python, instead of hardcoding it to particular place, which is useful. However, some systems have been found with multiple versions of Python, one of which works with GTK1 and one of which only works with GTK2.

Figure out which one is working for your users, and change their script interpreter or path to use that one.

2.9. FAQ 2.4, 2.6 and etc etc all suck. Python still doesn't find the version of pygtk I want.

Well, if all else fails:

 strace -eopen python <scriptname.py>
will let you know where python is looking for the pygtk files. Knowing that, you can tweak PYTHONPATH, --prefix, require() and other assorted nasties to get your versioning correct.

Don't write to the mailing list complaining, because we all know it's hard to make it work. You'll have to debug yourself. Next time complain when a solution that brings endless hassle to installers is implemented!

2.10. How do I get my 1.2 gladefiles to work with 2.0?

James Henstridge says:

There is a program included with libglade 2.0.x called libglade-convert that will do a pretty good job at converting the interface file to the new format. You should be able to edit the file in glade 1.1 after that.

Dave notes that you will probably have to redo all your dialog boxes, since they are going to be converted without some of the GTK 2 things, such as the correct active area interface and GTK 2 button images. You'll also have to redo your trees and lists to conform with GTK 2. A moderately sized project will take around 8 hours to do this to. Even if you don't "make install" libglade 2.0.x, you can use the Python file included (but renamed) in the distribution.


3. Signal handling

3.1. When I connect to a signal, my handler gets called but reports "XXX takes no arguments (1 given)"

Signal callbacks have specific signatures. This means that when a signal is emitted, it will send to the callback function a number of parameters. The first parameter is the widget which generated the event, and the rest vary depending on what signal is being emitted.

To handle a callback, your function signature, therefore, must take this into account. Often you don't even want to use any of the arguments, just trigger an action on a certain signal; an easy way to do this is using a variable argument list (*args) and ignoring them in your method:

  def on_win_delete(*args):
    print "Deleted, and who cares why"

  w = gtk.Window()
  w.connect("delete-event", on_win_delete)
If you are attaching to a method, be sure to provide the usual self in the method definition, and specifying self.on_foo_signal as the function to attach to.

3.2. How do I detect that a mouse or keyboard event has been triggered?

Q: I'm interested in writing a program similar to an x screen saver. It watches for user keystrokes, every time it receives one, it restarts a timer. How can I detect whenever the user hits a key or moves the mouse?

The correct way is to hook to some of the basic event signals and then act upon receiving them. The signals you want to look for are:

 - mouse motion
 - key presses
 - button presses
However, many widgets don't have their event masks properly set, so they will ignore these events. The following example shows how it should be done for a GtkWindow, adding the necessary event masks, and then hooking to the signals. Note that you would have to alter the wakeup function to handle the timer operations you would need for a screensaver.

 def wakeup(widget, event):
     print "Event number %d woke me up" % event.type

 w = gtk.Window()

 w.add_events(gtk.gdk.KEY_PRESS_MASK |
              gtk.gdk.POINTER_MOTION_MASK |
              gtk.gdk.BUTTON_PRESS_MASK | 
              gtk.gdk.SCROLL_MASK)

 w.connect("motion-notify-event", wakeup)
 w.connect("key-press-event", wakeup)
 w.connect("button-press-event", wakeup)
 w.connect("scroll-event", wakeup)

 w.show()

 gtk.main()
Note that mouse "scroll-wheel" events are implemented as button clicks in the Xorg X11R6 server (button 4 for scroll up, button 5 for scroll down).

3.3. I connected to some signals but nothing happens. Why?

There are a couple of issues here.

The first is that some GTK+ widgets do not by nature receive events of any nature - GtkLabel comes to mind as an example. (The technical reason behind this is that they do not have their own X window, but use the one belonging to their parent widget. An X window is not the same as a GTK+ window, mind you; X windows on Unix systems are wrapped by GDK's GdkWindow, which is a lower-level creature). These widgets are listed at [www.moeraki.com] , and discussed further in gtkmm's tutorial: [www.gtkmm.org] . If you want to receive events for one of these widgets, you should add a GtkEventBox around it, and listen for events on that box.

 l = gtk.Label("I want events.")
 e = gtk.EventBox()
 e.add(l)
 e.add_events(gtk.gdk.POINTER_MOTION_MASK)
 e.connect("motion-notify-event", handle_event)
Additionally, to receive signals, the widget's event mask must be set accordingly. In the answer to FAQ 3.2, for instance, we had to adjust it to receive pointer motion events (among others) - if we didn't, motion_notify_event would never be emitted.

The event masks are defined in the gdk module; they are constants whose name ends in "_MASK". They map directly to X11 masks, and there is a reference to what each X11 mask is at [tronche.com]

The functions that adjust the masks are:

 widget.set_events() 
and

 widget.add_events()
the second one only adding to the widgets mask, the first one in effect replacing the original mask (* though I believe the "factory supplied" mask is not replaced, but added to, even in the case of set_events()).

In the specific case of the key_press_event, the GTK+ event queue treats this signal specially to manage the widget keyboard focus.When it sees key events targetted at any subwindow within the toplevel, they are redirected to the toplevel GtkWindow. The key_press_event handler for the toplevel window checks to see if the key event corresponds to an accelerator/mnemonic (and activates the appropriate widget if so), or passes the key event on to the widget with focus. In short: if you want a global keyhandler, attach it to your application's GtkWindow(s).

Finally, understanding how the signal propagation system works is also helpful when you run into a tricky situation - you should check out FAQ 3.11 which has more information on this.

3.4. I've fiddled with the mask but nothing happened. Why?

One common error is to confuse gdk event TYPEs with MASKs. The type number indicates precisely which gdk event was generated, but it is not directly related to the event mask:

<jamesh_> yeah. A number of the masks cover multiple events and some events are selected by different masks

All event mask constants end with _MASK, and that is a good rule to remember. When doing add_events, you do NOT want (see, no _MASK!):

 widget.add_events(gtk.gdk.MOTION_NOTIFY | gtk.gdk.BUTTON_PRESS)
This is the correct command:

 widget.add_events(gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_PRESS_MASK)
(This example is particularly tricky because using BUTTON_PRESS will actually enable the pointer motion mask; this happens because the of the numeric constants used. Remember _MASK.)

3.5. Which widgets are unable to receive events or be styled?

In question 3.3, I said that certain widgets didn't have associated X windows, and for that reason were unable to handle events or be styled and coloured. These widgets are (add a Gtk in front if they look unfamiliar):

 Alignment
 AspectFrame
 Arrow
 Bin
 HBox
 VBox
 Frame
 Image
 Label
 Pixmap
 ScrolledWindow
 HSeparator
 VSeparator
 Table

3.6. I attach a callback to a signal, but I keep getting an error: "TypeError: object of type X is not callable"

When connecting an event handler, you must provide the function name. A common mistake is to pass a call instead of the name. In other words, you should not add parenthesis after the function name.

 #
 # WRONG
 button = gtk.Button(label="Quit")
 button.connect("clicked", gtk.main_quit())
As you can see, gtk.main_quit() is a call, not the function name. The correct way to do it would be:

 # RIGHT
 button = gtk.Button(label="Quit")
 button.connect("clicked", gtk.main_quit)
Always remember to use gtk.main_quit() instead of gtk.mainquit() since the last one is deprecated.

3.7. How can I force updates to the application windows during a long callback or other internal operation?

If you have a long-running callback or internal operation that tries to modify the application windows incrementally during its execution, you will notice that this doesn't happen; the windows of your app freeze for the duration.

This is by design: all gtk events (including window refreshing and updates) are handled in the mainloop, and while your application or callback code is running the mainloop can't handle window update events. Therefore nothing will happen in the application windows.

The trick here is to realize where your operation can take a while to return, or where it is dynamically changing the window contents, and add a code fragment like this wherever you want an update forced out:

 while gtk.events_pending():
   gtk.main_iteration(False)
This tells gtk to process any window events that have been left pending. If your handler has a long loop, for instance, inserting this snippet as part of the loop will avoid it hanging the window till the callback has finished.

More eloquently, in the words of the great Malcolm Tredinnick, 'this requires using what should be called "Secret Technique #1 For Making Your Application Look Responsive"(tm):

If you want to avoid freezes in your application while you are doing large amounts of work in the background, remember to call gtk.mainiteration() from time to time.'

Of course, if your callback has a single instruction that takes a long time to process, this isn't an option. There is no easy alternative to solve this problem, as far as I can see. Doug Quale remarks on how this applies even to idle_add()ed functions:

Idle functions are scheduled when gtk+ doesn't have any other work to perform, but gtk+ doesn't preempt them. Each idle function will run to completion once it's started.

Note that running a mainiteration inside an idle, io (input_add) or timeout handler is generally considered `a bad idea' because it doesn't work very well. If you really need to do so, check FAQ 20.1.

Moreover if during the computation you want to lock the GUI (no operation can be performed) without making all the widget insensitive you can use the other secret technique called "Yeti"... [1]

 import gtk
 from time import sleep

 def response(widget, response_id):
     if response_id != gtk.RESPONSE_APPLY:
         gtk.main_quit()
     else:
         i=0
         n=1000

         progress = dialog.get_data("progress")
         progress.set_text("Calculating....")
         progress.grab_add()

         while i < n:
             sleep(0.005)
             progress.set_fraction(i/(n - 1.0))
             i += 1

             while gtk.events_pending():
                 gtk.main_iteration_do(False)

         progress.set_fraction(0.0)
         progress.set_text("")
         progress.grab_remove()

 dialog = gtk.Dialog("Modal Trick", None, 0, (gtk.STOCK_EXECUTE,  gtk.RESPONSE_APPLY, 
                         gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))

 dialog.connect("response", response)
 dialog.connect("destroy", gtk.main_quit)

 box = dialog.get_child()

 widget = gtk.CheckButton("Check me!")
 box.pack_start(widget, False, False, 0)

 widget = gtk.Entry()
 box.pack_start(widget, False, False, 0)

 adj = gtk.Adjustment(0.0, 0.0, 100.0, 1.0, 10.0, 0.0)
 widget = gtk.HScale(adj)
 box.pack_start(widget, False, False, 0)

 widget = gtk.ProgressBar()
 box.pack_start(widget, False, False, 0)

 dialog.set_data("progress", widget)

 dialog.show_all()
 gtk.main()
This way the GUI does not freeze and you cannot interact with widgets, if you like you can unlock one widget (e.g. you want to give the chance to block the long process) using gtk.grab_add() on that widget.

[1] [mail.gnome.org]

3.8. I want my callback to execute, but not the default callback (or, how to I stop GTK from doing the default action when doing X)?

Many times, you are customizing behaviour of a widget, or changing a policy in GTK, and the default action it does it not what you want. To get around this, we rely on a fundamental point in GTK: that GTK, as well as applications, mainly uses signals to get things done in the interface.

The process to disable a default action is:

An example of this usage was reported by Graham Ashton. He had customized a keypress handler for a window, but every time the user triggered the Alt-arrow combination he was handling, the focus moved around between the widgets in the interface (as is the default behaviour).

The solution was simply calling window.emit_stop_by_name("key_press_event") and returning True.

3.9. When creating a new signal, how do I define one of the signal arguments as Python data?

[ pygtk 2.0 ]

When you add your signal using gobject.signal_new(), use gobject.TYPE_PYOBJECT as the type for the argument being passed in:

    gobject.signal_new("signal", ClassName,
                       gobject.SIGNAL_RUN_LAST,
                       gobject.TYPE_NONE,
                       (gobject.TYPE_PYOBJECT,))
And then you can emit the signal with Python objects:

    mydict = {}
    mydict["foo"] = "bar"
    class_instance.emit("signal", mydict)
And get them when you connect on the other side:

    def signal_cb(instance, mydict):
        print mydict["foo"]

    class_instance.connect("signal", signal_cb)

3.10. How do I specify user data to a signal?

Easy:

 widget.connect("my_signal", handler, userdata [, ...])
As you can see, you can pass as many items as userdata; the function will receive the same number of user data arguments.

3.11. How do signals and events propagate in GTK+?

Though there is a section on this in the GTK+ tutorial at [www.gtk.org] it doesn't clearly describe the difference in propagation behaviour between simple signals, events and keyboard events. James offers a more complete answer:

A single signal emission will only call handlers attached to the object it was emitted on. The propagation of events up the heirachy is acheived by emitting the signal a number of times.

For events such as the button presses and motion events, the event is delivered first to the widget the event occurred in. It will emit the appropriate event signal. If the event signal returns false (indicating that the event hasn't been handled), then a signal will be emitted on the parent. This continues all the way up to the toplevel if no one handles the event.

Keyboard events are handled differently. When your window receives a keyboard event, it is first dispatched to the toplevel window, which will check if it matches any keyboard shortcuts. If the key press doesn't match a shortcut, then the event is dispatched to the child widget that currently has focus.

3.12. Why does handling expose events break drag-n-drop?

If you are calling

  queue_draw_area(x_beg, y_beg, x_end, y_end) 
in your expose_event handler, don't. It seems to break event propagation which causes drag and drop to not work any more.

3.13. How do I pass extra data to a signal handler?

The signal connection methods connect() and connect_after() take an optional third parameter that can be used to supply extra data to a signal handler callback. Any Python object can be passed so you can use a list, tuple or dictionary if you want to pass multiple extra values. Since the signal handler function will receive the widget that emitted the signal as its first parameter, often it's convenient to pass a second related widget as the extra data.

Suppose you have a dialog with an entry widget. If you want the dialog response handler to do something with the entry value, you could connect to the response signal like this

     dialog.connect('response', on_dialog_response, entry)
This lets you easily access methods of the entry widget in the signal handler, perhaps to get the text in the entry

     def on_dialog_response(widget, response, entry):
         if response == gtk.RESPONSE.ACCEPT:
             print 'Accepting', entry.get_text()
Something that might trip you up especially if you are new to Python programming is that you probably don't want to try to pass the entry text to the signal handler like this

    # probably wrong!
    dialog.connect('response', on_dialog_response, entry.get_text())
The get_text() method is executed when the signal is connected so this would pass a constant value as the extra data. Usually you will want the signal handler to see the current state of the entry widget.

3.14. How to construct my own "fake" gtk.gdk.Event?

It's very easy. Let's go create a keypress event that is the same as if the user has pressed Ctrl+Enter:

 event = gtk.gdk.Event(gtk.gdk.KEY_PRESS)
 event.keyval = gtk.keysyms.Return
 event.state = gtk.gdk.CONTROL_MASK
 event.time = 0 # assign current time

 widget_that_should_accept_signal.emit('key_press_event', event)
the last line "passes" the signal to the widget we want to handle this fake event.

3.15. How do I pass data to a signal handler in Glade?

In theory, you should fill in the Object column when specifying a callback to connect to the signal. In GtkBuilder mode, you may only specify objects that Glade knows about. This is sufficient for implementing such things as the encapsulation pattern demonstrated elsewhere in this FAQ, used to provide a callback everything it needs to function in, for example, a cell renderer callback, by passing the TreeModel as user data.

In practice, don't even try. Pygtk 2 and Glade are both too buggy to attempt this. Manually connect any signals that need user data.


4. Themes, fonts and styles

4.1. How do I change font properties on gtk.Labels and other widgets?

Easy:

 label = gtk.Label("MyLabel")
 label.modify_font(pango.FontDescription("sans 48"))
This method applies to all widgets that use text, so you can change the text of gtk.Entry and other widgets in the same manner.

Note that, some widgets are only containers for others, like gtk.Button. For those you'd have to get the child widget. For a gtk.Button do this:

  if button.get_use_stock():
     label = button.child.get_children()[1]
  elif isinstance(button.child, gtk.Label):
     label = button.child
  else:
     raise ValueError("button does not have a label")

4.2. Why don't my style changes apply only to the widget I requested it from?

Ricardo Lenzi writes:

get_style() returns an object what aways have the current style of widget. If you want to save an static style, use get_style().copy() instead:

 style = widget.get_style().copy()
This has some pretty odd effects. If you are creating a window with many gtk.Label's, for instance, and you alter the actual style object (not a copy() if it), all widgets will eventually change style (when they are redrawn by GTK+).

4.3. My user defined styles get overridden by the default theme!

Christian Storgaard said:

I have succesfully changed the bg colour of some buttons in my program by the use of styles. But..

As soon as my beautiful greenish colour has been painted onto the buttons, my default pixmap theme paints it over with it's gradient grey.

How do I stop this?!

I know I can stop it by choosing a different engine (like notif), but I want to use the default engine... See the prob?

XXX: NEEDS ANSWER

4.4. How do I change the background color of my application's dialog?

XXX: Use a gtkrc theme, or specify a style.

4.5. How do I use the style object?

Each widget has an associates style object that can be manipulted. The basic method is get_style(), which returns a GtkStyle object, and the associated set_style(style_object).

The style is shared between widgets of the same type (XXX: is this true?). To change the style of only one widget in your application, the style object offers a copy() method, which returns a new copy of the GdkStyle, which can me changed and set_style() back to the desired widget.

All attributes of a style can be get and set independently by direct access. The most important attributes of style are the colours (see faq 4.6):

And the font and bg_pixmap attributes.

4.6. How do I change the colour of a widget (or how do I get a GdkColor)?

Important! See also FAQ 4.16.

There is some confusion about GdkColor and how it is created. There are both the GdkColor() class and colour_alloc() that seem to do the right thing, but they are both duds (as far as I can tell).

The right way of creating a colour is getting the colormap from the widget and using it to allocate a new colour using the GtkColorMap's alloc method:

 e = gtk.Entry()
 map = e.get_colormap()
 colour = map.alloc_color("red") # light red
This way you end up with a red GdkColor in the variable colour. Apart from the X11 rgb.txt names, you can also use hex triplets:

 colour = map.alloc_color("#FF9999") # light red
See FAQ 4.8 for more information on alloc_color.

The next step is understanding how to manipulate GtkStyle's colour attributes, which are actually dictionaries: each attribute maps a number of different gtk constants that indicate states:

So, to change the default border of our entry above to red:

 style = e.get_style().copy()
 style.bg[gtk.STATE_NORMAL] = colour
 e.set_style(style)
Final hint: the default colour for a GtkEntry background is gray84.

4.7. How do I get a Graphics Context, or GdkGC?

Use the new_gc() method of GdkWindow (not GtkWindow, notice):

 gdkwin = widget.window
 gc = gdkwin.new_gc()
The widget must be realized. Then you are free to set the gc's background/foreground, etc. More information on the GdkGC is available at [www.moeraki.com]

4.8. How does the alloc() method to the GdkColormap work?

gdk.Colormap.alloc_color can take a number of formats:

 cmap = widget.get_colormap()
 color = cmap.alloc_color("#FFCCAA")
 color = cmap.alloc_color("red")
 color = cmap.alloc_color(0, 0, 65535)
Note that the third format uses a tuple to specify the individual values for Red, Green and Blue (RGB), each item being an integer from 0 to 65535 (corresponding, therefore, to 0x0-0xFF).

Complete reference documentation on GdkColormap is available at [pygtk.org]

4.9. How do I use pango instead of GdkFont for font handling in a GtkDrawingArea?

Create a font description with pango. You will then need a pango layout for the text you want to display. You have to tell the layout which font description to use and draw it with the draw_layout() method instead of the draw_text() method.

 import pango

 # create a font description
 font_desc = pango.FontDescription('Serif 12')

 # create a layout for your drawing area
 layout = darea.create_pango_layout('hello pango!')

 # tell the layout which font description to use
 layout.set_font_description(font_desc)

 # draw the text with the draw_layout method
 darea.window.draw_layout(gc, x, y, layout)
You can find out about the size of the text by using the get_pixel_size() method from your pango layout object. e.g.:

 # get the pixel size of a layout
 text_width, text_height = layout.get_pixel_size()

4.10. How can I use Unicode (or other format) strings in my PyGTK application, or, why do I get a UTF-8 warning when using a string?

If your string is a Python unicode (u"some string") object, you needn't do anything else, PyGTK will happily use it.

If, however, your string is an str ("some string") object, PyGTK requires it to be in UTF-8. Otherwise you will see a warning like this:

 WARNING **: Invalid UTF8 string passed to pango_layout_set_text()
and your text will be displayed incorrectly.

Luckily, fixing this is trivial in Python by converting the str into a unicode object:

 unistr = unicode('your iso 8859-15 text', 'iso8859-15')
 # or: 'your iso 8859-15 text'.decode('iso8859-15')

 label = gtk.Label(unistr)
If you have no clue about the character encoding used, you can still convert it while silently ignoring errors:

 unistr = unicode('text with an unknown encoding', errors='replace')
This will replace any unknown character by the official Unicode replacement character (U+FFFD).

4.11. How can I create a new pango context()

Q: How can I create a new, or copy an existing, pango context? I am currently using the context returned by widget.get_pango_context(), but I can't work out how to make a new one. If I use the one attached to the widget I have to restore everything after every use.

A: widget.create_pango_context() should give you a new one.

Note that pango.Context() doesn't work: PangoContext is really an abstract interface. There are currently context implementations for core X fonts (already removed from the HEAD branch), Xft, Win32 and freetype. Widget.create_pango_context() will create a context appropriate for use with that widget, so you don't need to worry about these details.

4.12. How do I get antialiased fonts in GTK+?

The original core font rendering engine in XFree86 didn't support AA fonts. However, for GTK+ 2.0 onwards, the Xft font rendering backend can be used to render antialiased fonts. To select it using GTK+2.0, use:

 export GDK_USE_XFT=1 
It's on by default on 2.2 onwards, and in 2.4 the core engine is no longer used by GTK+.

Note that the Xft backend is much better at producing scaled versions of the fonts. The reason is that the core X font system, when you use scalable fonts, will render the entire set of glyphs as bitmaps at the requested size when you open the font (which isn't fast or a good use of memory -- it quite large for big point sizes or fonts with large coverage, such as with Asian fonts).

4.13. Does PyGTK support TrueType fonts?

If your X server does, the answer is yes. X requires the freetype module be loaded to be able to handle TTF fonts, but all post-4.0 servers include the module by default.

Note that the way the font is rendered is handled by the rendering backend; see FAQ 4.12 for more information.

4.14. What units does pango use to define sizes and widths?

Pango uses a constant called pango.SCALE to convert between pixels and pango's native unit. You can use pango.PIXELS() to convert from the native unit back to pixels, or just divide.

4.15. Can I find out how long (wide) a string is in a certain font?

In PyGTK2, you can use pango calls to find out how wide a string will be, using the pango context of the widget that contains (or that will contain) your text:

   context = widget.get_pango_context()
   metrics = context.get_metrics('font name, 12')
   width = pango.PIXELS(metrics.get_approximate_char_width() * n_chars)
(See FAQ 4.14 to understand how PIXELS() works)

For a monospaced font, this should be quite accurate. You can then use widget.set_size_request() if you would like to set that width as the minimum width for the widget/view.

In PyGTK-0.6, you can ask the font directly how long a given string is going to be, as well as how high. Retrieve the font object from the style, and then query it with the string in question:

  font = widget.get_style().font

  h = font.height(my_string)
  w = font.width(my_string)
The methods return pixel counts. You can then set the size manually to any function of those parameters. For instance, to make a widget twice as wide and as high as the string you measured with, use:

  widget.set_usize(w*2, h*2)
[Credit: Andrew Reid <Andrew-dot-Reid-at-nist-dot-gov>]

4.16. How do I change the background and colour of an Editable (GtkEntry, GtkTextView and friends)?

You must change the 'base' and 'text' parts of the widget's style. You can also edit the 'foreground' property. Some useful shorthand methods to change those style properties inherited from gtk.Widget are:

  widget.modify_fg(state, color)
  widget.modify_bg(state, color)
  widget.modify_base(state, color)
  widget.modify_text(state, color)
Windowless widgets such as gtk.Label, gtk.Button, gtk.Paned, gtk.Frame, etc, (see FAQ 3.5) despite inheriting from gtk.Widget don't allow changing its background and base color as those properties don't exist for them. If you want to get them you need to insert the widget inside a gtk.EventBox which adds this properties. Example:

    import gtk

    window = gtk.Window(gtk.WINDOW_TOPLEVEL)
    window.connect("destroy", gtk.mainquit)

    label = gtk.Label("one, two, testing...")
    eb = gtk.EventBox()
    eb.add(label)
    eb.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse("blue"))
    window.add(eb)

    window.show_all()
    gtk.main()

4.17. Why does FontSelection's set_font_name return False?

It needs to be added to a window before the font lists are populated.

  >>> w = gtk.Window()
  >>> f = gtk.FontSelection()
  >>> f.get_font_name()
  'Sans 10'
  >>> f.set_font_name('Sans 12')
  False
  >>> w.add(f)
  >>> f.set_font_name('Sans 12')
  True
Once added to the window, the result will indeed be True.

4.18. How do I change GtkMenubar.shadow_type (or other style properties)?

GtkMenubar.shadow-type and other style properties are read only. The only way you can change it is by passing in new rc strings. Something like this should do it:

    style "menubar-style" { 
        GtkMenuBar::shadow_type = etched-in 
    }

    class "GtkMenuBar" style "menubar-style"
In this case, possible shadow_types are:

  none, in, out, etched-in, etched-out
In general to find out what you can parse you have to check the enum, eg: [pygtk.org] s

Which can be passed on to gtk.rc_parse_string (or put in a file and then passed to gtk.rc_parse).

4.19. Can I pass strings of unicode instance to gtk or do I need to convert them to utf8?

No you don't have do manually convert your strings in utf8. PyGTK will do this for you.

    label.set_text(u'abc')
So the above is indeed valid and not only to labels but to any widget.


5. Basic Objects: GObject, GtkWidget and other critters

5.1. I want to understand this "data" object that is used in the set_*_data() and get_*_data() calls.

The GObject methods set_data() and get_data() allow you to attach an arbitrary reference to a GObject (or any derived class) instance keyed by a string. In other words, you can attach any number of references to any GObject and retrieve them with the strings you set() them with. This is a very helpful but often overlooked feature of GTK+, and it can come in handy.

For example, you can attach to a GtkLabel the instance it represents and a list of of versions using the following code:

 l = gtk.Label()
 l.set_data("object-name", some_object)
and then retrieve the data using:

 >>> some_object = l.get_data("object-name")
There are also related methods associated with the CList/CTree, set/get_row_data(), and GnomeIconList's set/get_icon_data(). These methods don't index on string, but instead on position in their internal arrays.

5.2. How do I check if a widget is currently sensitive?

In pygtk, you get properties by calling the get_property() method:

  if widget.get_property('sensitive') == 0:
    print "I'm insensitive!"
Note: In ancient versions of pygtk (0.6.x) you could access them using a dictionary interface, this was removed in the 2.x series.

More recently (since PyGTK 2.8) the following method can be used:

  if not widget.props.sensitive:
    print "I'm insensitive!"
More info here: [live.gnome.org]

5.3. Where is get_state() in PyGTK 0.6.x?

James Henstridge points out that there is no get_state() function in gtk 1.2.

And therefore no way to wrap it in pygtk. There are actually a number of state constants defined in gtk:

 gtk.STATE_ACTIVE
 gtk.STATE_NORMAL
 gtk.STATE_SELECTED
 gtk.STATE_INSENSITIVE
 gtk.STATE_PRELIGHT     
but they are to be used with set_state(). In pygtk2, get_state() is implemented and wrapped.

5.4. How do I catch right-click, middle-click and double-click on my widget?

All widgets that receive events (see FAQ 3.3) can attach to button_press_event to 'listen' for button presses. It may be necessary to alter the event mask for certain widgets (gtk.Window, for instance):

 window.add_events(gtk.gdk.BUTTON_PRESS_MASK)
You can easily capture a specific button press pattern by checking event.button and comparing event.type with the constants defined in gtk.gdk for multiple button presses. To do this, connect a handler like this one to "button_press_event" on your widget:

 def button_clicked(widget, event):
     # which button was clicked?
     if event.button == 1:
         print "left click"
     elif event.button == 2:
         print "middle click"
     elif event.button == 3:
         print "right click"

     # was it a multiple click?
     if event.type == gtk.gdk.BUTTON_PRESS:
         print "single click"
     elif event.type == gtk.gdk._2BUTTON_PRESS:
         print "double click"
     elif event.type == gtk.gdk._3BUTTON_PRESS:
         print "triple click. ouch, you hurt your user."
Note that it seems that, at least in PyGTK 0.6.x (confirm for 2.x), spawning a modal dialog when handling a double-click event causes a strange focus bug. I've experienced this personally, but this message confirms the problem: [mail.gnome.org] To work around it, I changed the modality using idle_add(win.set_modal, 1) before calling mainloop, but it's a very ugly fix.

5.5. How do I capture keypresses, and how do I perform a certain action depending on the key pressed?

You can capture the generic key_press_event in any widget that has the key press mask set or in the top level window that the widget is displayed in. Key events are sent to the top level window before they are sent to the child widget that currently is the focus widget. As a basic example:

 def on_key_press_event(widget, event):
   keyname = gtk.gdk.keyval_name(event.keyval)
   print "Key %s (%d) was pressed" % (keyname, event.keyval)

 w = gtk.Window()
 w.connect('key_press_event', on_key_press_event)
If you want to block a specific key from being catched by a widget, just return True in the key_press_event signal handler.

Which will print out the key pressed for that window. To use a specific handler for each key pressed, you can set something up like this:

  def on_key_press(self, widget, event):
    keyname = gtk.gdk.keyval_name(event.keyval)
    func = getattr(self, 'keypress_' + keyname, None)
    if func:
      return func()

  def keypress_A(self):
    print "A was pressed!"

  def keypress_B(self):
    print "B was pressed!"
To capture Control, Alt and Shift combinations, you need to use the gtk.gdk symbols CONTROL_MASK, MOD[1-5]_MASK and SHIFT_MASK and do a binary AND to event.state:

 def on_key_press(widget, event):
   keyname = gtk.gdk.keyval_name(event.keyval)
   print "Key %s (%d) was pressed" % (keyname, event.keyval)
   if event.state & gtk.gdk.CONTROL_MASK:
     print "Control was being held down"
   if event.state & gtk.gdk.MOD1_MASK:
     print "Alt was being held down"
   if event.state & gtk.gdk.SHIFT_MASK:
     print "Shift was being held down"

 w = gtk.Window()
 w.connect('key_press_event', on_key_press)

5.6. How do I change the cursor for a certain widget?

Changing the cursor is remarkably easy in pygtk:

To change it for a button,

 def realize_cb(widget):
   b.window.set_cursor(watch)

 b = gtk.Button()
 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 b.connect("realize", realize_cb)
And to change it back to normal:

 b.window.set_cursor(None)
To make an invisible cursor (aka hide the cursor), you can use this code:

 pix_data = """/* XPM */
 static char * invisible_xpm[] = {
 "1 1 1 1",
 "       c None",
 " "};"""
 color = gtk.gdk.Color()
 pix = gtk.gdk.pixmap_create_from_data(None, pix_data, 1, 1, 1, color, color)
 invisible = gtk.gdk.Cursor(pix, pix, color, color, 0, 0)

 b.window.set_cursor(invisible)
To change it for a label, which lacks its own gdk.Window, for instance:

 boat = gtk.gdk.Cursor(gtk.gdk.BOAT)

 b = gtk.EventBox()
 l = gtk.Label()
 b.add(l)
 b.window.set_cursor(boat)
Note that the widget may already define a cursor: for instance, GtkEntry defines an I-bar for the cursor. X allows you to set a cursor on each gdk.Window, and if a window doesn't have a cursor associated with it, it gets the parent window's cursor.

To change the cursor for all the widgets, you'd need to recurse into all child widgets and set_cursor() on their gdk.Windows.

However, there is an other way, that can be implemented using some gdk.Window functions. For details, read: [www.daa.com.au]

It is also worth noticing that some widgets are composed of multiple X windows. gtk.Entry is an example -- see FAQ 14.3 (you can use the gdk.Window's children() method to get its child windows). Another example is TextView, described in FAQ 14.15.

The constants for icons defined in gtk.gdk are:

 X_CURSOR            ARROW                BASED_ARROW_DOWN
 BASED_ARROW_UP      BOAT                 BOGOSITY
 BOTTOM_LEFT_CORNER  BOTTOM_RIGHT_CORNER  BOTTOM_SIDE
 BOTTOM_TEE          BOX_SPIRAL           CENTER_PTR
 CIRCLE              CLOCK                COFFEE_MUG
 CROSS               CROSS_REVERSE        CROSSHAIR
 DIAMOND_CROSS       DOT                  DOTBOX
 DOUBLE_ARROW        DRAFT_LARGE          DRAFT_SMALL
 DRAPED_BOX          EXCHANGE             FLEUR
 GOBBLER             GUMBY                HAND1
 HAND2               HEART                ICON
 IRON_CROSS          LEFT_PTR             LEFT_SIDE
 LEFT_TEE            LEFTBUTTON           LL_ANGLE
 LR_ANGLE            MAN                  MIDDLEBUTTON
 MOUSE               PENCIL               PIRATE
 PLUS                QUESTION_ARROW       RIGHT_PTR
 RIGHT_SIDE          RIGHT_TEE            RIGHTBUTTON
 RTL_LOGO            SAILBOAT             SB_DOWN_ARROW
 SB_H_DOUBLE_ARROW   SB_LEFT_ARROW        SB_RIGHT_ARROW
 SB_UP_ARROW         SB_V_DOUBLE_ARROW    SHUTTLE
 SIZING              SPIDER               SPRAYCAN
 STAR                TARGET               TCROSS
 TOP_LEFT_ARROW      TOP_LEFT_CORNER      TOP_RIGHT_CORNER
 TOP_SIDE            TOP_TEE              TREK
 UL_ANGLE            UMBRELLA             UR_ANGLE
 WATCH               XTERM                CURSOR_IS_PIXMAP
Also if you plan to do anything time consuming and want to use the watch cursor you have to be careful that you don't starve the gui thread before it can change the cursor, e.g.

 ## This Will Not Work ##
 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 gtk_window.set_cursor(watch)
 time.sleep(10)             # your time consuming operation here
 gtk_window.set_cursor(None)
instead call the time consuming in an idle callback (or in a different thread if you absolutely have to)...

 def idle_cb(gtk_window):
    time.sleep(10)             # your time consuming operation here
    gtk_window.set_cursor(None)

 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 gtk_window.set_cursor(watch)
 gobject.idle_add(idle_cb, gtk_window)

5.7. How can I tell my program that the cursor should jump to a specific widget?

If you have the name of the widget, simply call grab_focus() on it:

 entry = gtk.Entry()
 [...]
 entry.grab_focus()

5.8. What signal is triggered when I change a widget's sensitivity?

The state_changed signal is emitted, and the callback receives an extra parameter which is the previous state of the widget (this is apparently undocumented).

5.9. How do I find out the size of a widget?

Use the GtkWidget's allocation attribute, which contains a geometry tuple. Note that the widget must be shown (you may get around calling only realize on that specific widget when using libglade):

  >>> win = gtk.Window()
  >>> win.realize() # or win.show()
  >>> rect = win.allocation
Would return a gdk.Rectangle, which can be accessed by using:

  >>> rect.width, rect.height, rect.x and rect.y
or just convert it to a four sized tuple:

  >>> t = tuple(rect)
Meaning the widget is at the top left of the window, and is 158x22 pixels in size (the default size of a gtk.Entry, by the way)

To find out how high or wide a widget is (or would be) based on a string size and a font, see FAQ 5.16

5.10. How do I focus a widget? How do I focus it before its toplevel window is shown?

Use the widget's grab_focus() method. Note that the widget must be added to a window or dialog before calling grab_focus, since (perhaps a bit unexpectedly) the focused widget is a property of a *toplevel window* and not its child widgets. In other words:

 e = gtk.Entry()
 e.show()
 e.grab_focus()
 w = gtk.Window()
 w.add(e) # oh-oh, added after grab_focus()
 w.show()
would NOT work, but

 e = gtk.Entry()
 w = gtk.Window()
 w.add(e)
 e.grab_focus() # called after add
 w.show_all() # no need for e.show() in this case
will work as expected (using idle_add() to call grab_focus() is naughty and we know that python hackers are never naughty :-P ).

5.11. My callback is getting a gtk.gdk.Event object, but I need an EventExpose!

Event is in fact a GdkEventExpose, it's just called gtk.gdk.Event to make things a bit easier for the code generator.Everything except the region member in the GdkEventExpose struct is wrapped. So you can access the event's area, for instance:

 event.area.x

5.12. How do I check if a widget is mapped? And realized? And visible? [...]

All gtkWidget's have a number of flags that indicate their state. PyGTK offers a method that can be used together with a number of gtk symbols to retrieve this state from the widget.

In PyGTK the method is called flags(), and it doesn't take arguments, so you must perform the binary AND yourself:

 # To check if `widget' is mapped:
 if widget.flags() & gtk.MAPPED:
    print "MAPPED!"
There are a number of flags you can test for. The following are defined in the gtk namespace:

 # gtk.Object
 DESTROYED
 FLOATING
 CONNECTED
 CONSTRUCTED

 # gtk.Widget
 TOPLEVEL
 NO_WINDOW
 REALIZED
 MAPPED
 VISIBLE
 SENSITIVE
 PARENT_SENSITIVE
 CAN_FOCUS
 HAS_FOCUS
 CAN_DEFAULT
 HAS_DEFAULT
 HAS_GRAB
 RC_STYLE
 COMPOSITE_CHILD
 BASIC
 APP_PAINTABLE
 RECEIVES_DEFAULT

5.13. While calling get_property(), I get an "invalid property id" warning. Why?

When using get_property(), you need to make sure the property you are using is not set as write-only. An example of such a property is GtkContainer::child, which isn't readable. The warning when trying to read it is something like:

  (:2640): Gtk-WARNING **: ../../gtk/gtkcontainer.c:874: invalid property
           id 3 for "child" of type `GParamObject' in `GtkButton'
Pretty much all instances of write-only properties in GTK are ones that set some other property, but take a different format. For instance, setting the "markup" property on a gtk.CellRendererText object is equivalent to setting the "text" and "attributes" properties to appropriate values, however "markup" is not readable.

The GtkContainer "child" property looks more like a convenience. Setting the property adds the widget to the container. However, GtkContainer can have multiple children, so it isn't clear what should be returned when reading it.

5.14. How can I discover what properties and signals a GObject supports?

A GObject can support properties, which are used every now and them. They are quite useful for C programmers, since you don't need to do anything extra to make them available to language bindings. For gtk.Widget objects, they usually represent an internal state of some kind, for example the text of a widget, the padding of the border, etc.

There are several methods to find out what properties and signals are supported in a GObject. First of all, you have the two introspection methods, so for properties use this:

  >>> gobject.list_properties(obj)
and for signals:

  >>> gobject.signal_list_names(obj)
Where obj is an instance or a type, which has the disadvantage of not showing a description or other detailed information, but can be used by programs, like gui builders or others. A better method for programmers is the help() method.

  >>> help(obj)
Where obj also is an instance or a type, it gives you more detailed information.

If the type is in gobject, atk, pango, gdk or gtk, the reference manual is preferred, check it out here:

[www.pygtk.org]

5.15. How do I access one of these properties in a GObject?

Use the get_property method:

  >>> w = gtk.Window()
  >>> w.set_title('My Window')
  >>> w.show_all()
  >>> print w.get_property('modal')
  False
  >>> print w.get_property('title')
  'My Window'

5.16. What's the difference between a property and an attribute?

In the Pygtk reference documentation there are a section for properties and another one for attributes for most of the widgets.

A property is a GObject property and can be read and write with the GObject.get_property (propname) and GObject.set_property (propname, value) methods.

An attribute is a mapping to the C struct of the GObject and can be read from and (sometimes) written to directly. For example:

 adj = gtk.Adjustment(value=0, lower=0, upper=100, step_incr=1, page_incr=10, page_size=10)
 adj.value = 4.0
Since PyGTK 2.8, GObject properties are now mapped as attributes of a special 'props' attribute (gnome bug #81879), so the following also works:
 adj.props.value = 4.0

5.17. Do I need to handle reference counting for GObjects? What about for other objects in PyGTK/gnome-python?

At the Python level, all reference counting should be taken care of by PyGTK and gnome-python themselves; there is no need to ref()/unref() GObjects in python code. If you encounter a reference counting problem, most likely it is a bug in the code, with the following exception:

Note that while gnome-vfs objects are not based on GObject, and implement their own reference counting, it's the same from the point of view of Python code: nothing needs to be done. A significant difference in gnome-vfs objects is that they do not allow the programmer to add new attributes or subclass them. Also, they don't have reference cycles, so they are deallocated without help from the garbage collector.

Bonobo objects are GObject based, but they require manual reference counting. There are well defined rules for ownership semantics in remote calls: [developer.gnome.org] . However, for in-process bonobo API calls, there are no rules, and you have to be very careful with the ownership of the references obtained on a per API function basis. Unfortunately the API itself is underdocumented, so...

5.18. Focusing a widget after when selecting an item from Treeview

The problem with selecting a widget when you click on a gtk.Treeview is that gtk.Treeview steals the focus back.

The solution is to add a timeout. This is how we do it:

    # Connect Treeview with cursor-changed signal
    treeview.connect("cursor-changed", self.timeoutFocus, focusme)

    # The callback function: 
    # focusme is the widget that will be focused
    def timeoutFocus(self,widget, focusme):
       gobject.timeout_add(10, lambda: focusme.grab_focus())
and that's all folks!

5.19. How can I listen to events from the scroll wheel on my mouse?

To listen for events that your scroll wheel sends you need to connect to the signal 'scroll-event'. The event structure has a direction attribute which will be one of:

  gtk.gdk.SCROLL_UP, 
  gtk.gdk.SCROLL_DOWN, 
  gtk.gdk.SCROLL_LEFT, 
  gtk.gdk.SCROLL_RIGHT
Example:

  def on_button_scroll_event(button, event):
    if event.direction == gtk.gdk.SCROLL_UP:
       print "You scrolled up"

  b = gtk.Button()
  b.connect('scroll-event', on_button_scroll_event)

5.20. How do I move focus between widgets?

Two cases:

1) you want to move focus to particular widget:

widget.grab_focus()

2) move focus from a widget to the next widget, as if user pressed Tab key:

widget.get_toplevel().child_focus(gtk.DIR_TAB_FORWARD)

You can use other gtk.DIR_* constants, they correspond to moving focus wit h other keys; gtk.DIR_TAB_BACKWARD corresponds to Shift-Tab.


6. Widget subclasses and user signals: GObject

6.1. What is the canonical reference on widget (and GObject) subclassing and property overriding?

Lorenzo Gil Sanchez wrote a killer document that explains the good, bad and ugly of subclassing GObject and defining your own signals and properties. It's currently available at [www.pygtk.org]

6.2. When subclassing a widget (or a GObject), why are the additional signals I define not usable?

When subclassing a GObject, make sure to call the constructor

  gtk.DrawingArea.__init__(self)
Note, that the old syntax (__gobject_init__) is deprecated and should not be used. Note, that gobject.GObject.__init__ should only be called if you subclass the actual gobject.GObject class.

If you get a "signal XXX cannot be used for action emissions" message, it's also likely that you missed adding gobject.SIGNAL_ACTIONS to the signal flags in the signal definition.

Read more about GObject subclassing in Lorenzo's tutorial at [www.sicem.biz]

6.3. How do I wrap a GObject in Python?

If you'd like to use a GObject-derived class in your python programs, or just plain want to understand better how the pygtk2 wrapper works, Ross Burton wrote an excellent tutorial for IBM Developerworks that's available at [www-106.ibm.com]

It takes you throught the steps of generating the wrapper, customizing and compiling it, and then using it from Python. See also FAQ 1.11 for a walkthrough of the process.

6.4. How can I draw on top of a subclassed widget?

Note, this is only accurate for PyGTK 2.6 or later.

First, subclass the type properly and make sure the constructor is chained to properly:

 class MyButton(gtk.Button):
    def __init__(self):
      gtk.Button.__init__(self)
Secondly, override the expose-event virtual method, it will be called as soon as the widget is asked to redraw it self

    def do_expose_event(self, event):
The first thing we want to do here, is to call the gtk.Button code, to draw something which looks like a button. It's simple, just chain up to the expose_event of the button itself:

     retval = gtk.Button.do_expose_event(self, event)
At this point, the button is drawn. Now you can make your own "drawings" on top of the widget.

    self.window.draw_ ....()
Finally return the same return value as we got from the parents call

    return retval
Don't forget to register the type:

 gobject.type_register(MyButton)

23.33. Using metaclasses in GObject subclasses.

When subclassing from a gtk.Object and a class which uses a metaclass this error will appear:

   TypeError: Error when calling the metaclass bases
       metaclass conflict: the metaclass of a derived class must be a  (non-strict) subclass of the metaclasses of all its bases
In order to correct this you have to do the following:

 class Foo:
     __metaclass__ = MetaFoo

 # This will throw an error
 class Bar(Foo, gtk.Object):
     pass

 # This will not throw an error
 class GMetaFoo(MetaFoo, gobject.GObjectMeta):
     pass

 class Bar(Foo, gtk.Object):
     __metaclass__ = GMetaFoo
So, you must create a new metaclass that extends both the metaclass gobject.GObjectMeta and the metaclass used in the other class.


7. Labels: GtkLabel

7.1. How can I use mnemonics for my GtkLabel?

Matt Wilson says:

 label = gtk.Label('_Change the above color') 
 label.set_property("use-underline", gtk.TRUE)

7.2. Where is GtkLabel.get_text()?

I don't know why the API is inconsistent, but the GtkLabel provides the method get() instead of get_text().

 l = gtk.Label("foobar")
 print l.get() # prints "foobar"
In PyGTK-2 you can use get_text() method:

 >>> l = gtk.Label("foobar")
 >>> print l.get_text()
 foobar
 >>> 
and also get() method still works:

 >>> print l.get()
 foobar

7.3. How do I make a GtkLabel font larger or bold?

If you are using pygtk-0, you need to load a different font (using the XLFD and load_font()) and set that font to your label:

 bold =  "-adobe-helvetica-bold-r-normal-*-*-120-*-*-p-*-iso8859-1"
 big  =  "-adobe-helvetica-medium-r-normal-*-*-180-*-*-p-*-iso8859-1"

 s = label.get_style().copy()
 font = gtk.load_font(bold) # or big if you want big.
 s.font = font
 label.set_style(s)
If you are using pygtk-2, this is much easier, using pango. You can do things like:

 label.set_use_markup(gtk.TRUE)
 # weights
 label.set_markup('normal text, <b>bold text</b>, <i>italic text</i>')
 # size; 38000 = 38pt (use pt size * 1000)
 label.set_markup('<span size="38000">big text</span>, normal text')
or even:

 label = gtk.Label("<b>N</b>ame")
 label.set_use_markup(True)
See [developer.gnome.org] for more information on pango's span attributes.

7.4. How do I left, center, right, top, bottom, middle align a GtkLabel?

The GtkLabel has a justification attribute, but it only applies to *multi-line* labels. To change the position of a single-line label you should change it's alignment.

Use the label's set_alignment feature, which already does everything for you:

 l = gtk.Label("Text goes here")
 l.set_alignment(xalign=1, yalign=0.5) 
If you are using Glade, the labels already come with presets of xalign=0.5, yalign=0.5, and they can be changed in the widget tab of the properties dialog.

7.5. How do I change a Label's background color, or why doesn't my Label receive any signals?

As GtkLabels don't have their own X window (see FAQ 3.3 and FAQ 3.5) they use their parent's window to draw on and receive events. That means it's not possible for GtkLabel to have a different background property or to handle events separately from those of the parent window.

This also happens to other windowless widgets.

If you want to provide such features to a label (or windowless widgets) you need to add the label to a gtk.EventBox in order to assign it a window and thus have some more properties (such as background) and the ability to catch its own signals.

You can even nest gtk.EventBoxes, with some border width, to get colored frames.

See FAQ 4.16 for an example

7.6. How do I render a label in a button or menuitem with an underscore in its label?

Normally an underscore in a button label (set using something like the following)

 gtk.Button("_New order")
will underline the character "N", and will set an accelerator for the N key. If you want to literally print an underscore, use either double underscores:

 gtk.Button("Foo__bar")
or set_use_underline(0):

 button = gtk.Button("Foo_bar")
 button.set_use_underline(0)
The same approach works as expected for menuitems. There is GTK+ documentation covering this at [developer.gnome.org]

(The question remains of why would you want to do such a thing.)

7.7. I set my labels to use_markup in glade-2. Why don't they markup the contents I set?

Marking up the contents of a label is a bit tricky. There are two things to wrap your head around:

 label.set_property("use-markup", False)
 label.set_property("label", "foo")
while label.set_markup("<i>bar</i>") is roughly equivalent to:
 label.set_property("use-markup", True)
 label.set_property("label", "<i>bar</i>")

7.8. How can I change the appearance of a label without using pango markup?

You can set the "attributes" property of gtk.Label:

here is a little example:

 import gtk
 import pango
 w = gtk.Window()
 w.connect("destroy", lambda w: gtk.main_quit())
 l = gtk.Label("some VERY_BOLD ITALIC text")
 k = gtk.Label("some normal text")
 PLIST = pango.AttrList()
 BOLD = pango.AttrWeight(pango.WEIGHT_HEAVY, 0, -1)
 ITALIC = pango.AttrStyle(pango.STYLE_ITALIC, 0, -1)
 PLIST.insert(BOLD)
 PLIST.insert(ITALIC)
 l.set_property("attributes", PLIST)
 v = gtk.VBox()
 v.pack_start(l)
 v.pack_start(k)
 w.add(v)
 w.show_all()
 gtk.main()
You first create a pango.AttrList filled by all the attributes you want to change, then you apply it on the "attributes" property.


8. Images: GtkImage, GtkPixmap, GdkPixbuf

8.1. How do I load an image from a filename into my application UI?

Follow the sample program:

 w = gtk.Window()
 w.connect("destroy", gtk.main_quit)
 image = gtk.Image()
 image.set_from_file("logo.xpm")
 w.add(image) 
 w.show_all()
 gtk.main()
If you want to change the current image of a GtkPixmap use:

 image.set_from_file("logo2.xpm")

8.2. What about loading other image formats besides XPM, like JPEG or PNG?

In PyGTK2 the gtk.Image widget supports multiple formats. You can simply use:

 w = gtk.Window()
 image = gtk.Image()
 image.set_from_file(filename)
 w.add(image)
 w.show_all()
In PyGTK-0 you need to use gdkpixbuf to load non-xpm image formats. gdkpixbuf is a separate module, and you use it create a GdkPixbuf, which can be converted into a GdkPixmap, which can be in turn converted to a GtkPixmap (with its mask if transparent). An example follows:

 import gtk
 import gdkpixbuf

 w=gtk.GtkWindow()

 img=gdkpixbuf.new_from_file("images/logo.gif")
 gdkpix, mask = img.render_pixmap_and_mask() # Create a GdkPixmap object
 gtkpix = gtk.GtkPixmap(gdkpix, mask)
 w.add(gtkpix)
 w.show_all()
 gtk.mainloop()
Note that you can also use GdkPixbufs in PyGTK2. They are useful for manipulating images in-memory; for instance, for scaling and blitting imagedata (with an alpha channel). In that case, to load it into a GtkImage widget, you'd use something like:

 pixbuf = gtk.gdk.pixbuf_new_from_file(imagefilename)
 image = gtk.Image()
 image.set_from_pixbuf(pixbuf) 
to get the same results.

8.3. How do I convert a Numeric array to a Pixbuf object?

If you don't want to resort to PIL, PyGTK-2 can be compiled with Numeric support. You can then create a Pixbuf by modifying the array returned by accessing the 'pixel_array' attribute of an existing pixbuf.

Assuming that you have a (n,m,3) or (n,m,4) shape 'b' type array of RGB or RGBA values called 'data', you would do this:

 w,h = data.shape[:2]
 hasalpha = data.shape[3] == 4
 p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, hasalpha, 8, w, h)
 p.pixel_array[:] = data # see below
Special note: the pixel_array attribute of the Pixbuf is read-only in the sense that you can't do 'p.pixel_array = data'. But it's not immutable, so you can still change it's contents, which is what the [:] slice assignment above does.

Note however that modifying the pixel data of some GdkPixbufs will cause a segfault (ones that are backed by a const string, such as the stock icons). Pixbufs you create yourself are safe to modify.

(There was a bug which could cause crashes; see [bugzilla.gnome.org] for details -- it was fixed in CVS HEAD in Aug 2003)

(Tim Evans)

8.4. Is there a resource leak? Why do I run out of memory using Pixbuf?

The answer is "Interesting GC behaviour" in Python. Apparently finalizers are not necessarily called as soon as an object goes out of scope. My guess is that the python memory manager doesn't directly know about the storage allocated for the image buffer (since it's allocated by the gdk) and that it therefore doesn't know how fast memory is being consumed. The solution is to call gc.collect() at some appropriate place.

For example, I had some code that looked like this:

  for image_path in images:
     pb = gtk.gdk.pixbuf_new_from_file(image_path)
     pb = pb.scale_simple(thumb_width, thumb_height, gtk.gdk.INTERP_BILINEAR)
     thumb_list_model.set_value(thumb_list_model.append(None), 0, pb)
This chewed up an unacceptably large amount of memory for any reasonable image set. Changing the code to look like this fixed the problem:

  import gc

  for image_path in images:
     pb = gtk.gdk.pixbuf_new_from_file(image_path)
     pb = pb.scale_simple(thumb_width, thumb_height, gtk.gdk.INTERP_BILINEAR)
     thumb_list_model.set_value(thumb_list_model.append(None), 0, pb)
     del pb
     gc.collect()

8.5. How do I to display an image from data (using a drawable or Image widget)?

The examples below assume you have the height, width and imagedata attributes available in the local scope.

The first example uses any gdk.Drawable's draw_rgb_image() method:

  # 0,0 are the coordinates for the top left corner; this 
  # renders an image flush at this corner.
  drawable.draw_rgb_image(gc, 0, 0, width, height, gtk.gdk.RGB_DITHER_NONE, imagedata)         
Note that draw_rgb_image() has an optional rowstride argument. This argument is the length of *one row* of data in your buffer. See [www.pygtk.org] for more information.

(Ionutz Borcoman)

The next example creates a pixbuf from an Image using the gtk.gdk.pixbuf_new_from_data method. image can be any PIL Image object using RGB or RGBA mode.

 image = Image.open('foo.png')
 IS_RGBA = image.mode=='RGBA'
 gtk.gdk.pixbuf_new_from_data(
            image.tostring(), # data
            gtk.gdk.COLORSPACE_RGB, # color mode
            IS_RGBA, # has alpha
            8, # bits
            image.size[0], # width
            image.size[1], # height
            (IS_RGBA and 4 or 3) * image.size[0] # rowstride
            ) 
Note that you need to specify rowstride for this method. Setting rowstride to 3 * width should work for an RGB image. Setting it to 4 * width should work for an RGBA image.

(Tom Hinkle)

The next example uses Numeric (which allows for further image manipulation), and will will work with RGB and RGBA images:

  import Numeric, gtk

  data = Numeric.fromstring(imagedata, 'b')
  data.shape = (height, width, -1)
  p = gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, i.mode == 'RGBA', 8, w, h)
  p.pixel_array[:] = data

  im = gtk.Image()
  im.set_from_pixbuf(p)
(Tim Evans)

8.6. How do I resize a gtk.Image?

You can use GdkPixbuf's scale_simple method (exemplified below for the my.jpg file, scaling to 150x150 px):

  im = gtk.Image()
  pixbuf = gtk.gdk.pixbuf_new_from_file("my.jpg")
  scaled_buf = pixbuf.scale_simple(150,150,gtk.gdk.INTERP_BILINEAR)
  im.set_from_pixbuf(scaled_buf)
  im.show()
(Jeff Bowden)

8.7. What if I want to add a PIL image to a drawable?

You can use the size property and tostring() method of the PIL Image object to obtain the width, height and binary contents of the image. Then use any of the the solutions in FAQ 8.5; the example below renders on an Image from a gdk.Pixmap, but any drawable could be used in place of the Pixmap:

  import PIL.Image, Numeric, gtk

  i = PIL.Image.open('foo.png')
  w, h = i.size
  imagestr = i.tostring()

  im = gtk.Image()
  pixmap = gtk.gdk.Pixmap(self.im.window, width, height, depth)

  gc = self.im.style.fg_gc[gtk.STATE_NORMAL]
  # 0,0 are the coordinates for the top left corner; this
  # renders an image with no border.
  pixmap.draw_rgb_image(gc, x, y, w, h, gtk.gdk.RGB_DITHER_NONE, buff)

  im.set_from_pixmap(pixmap, None)
To convert back from a GTK+ image type to a PIL Image, see FAQ 8.14.

A simpler method using a StringIO object is described by Sebastian Wilhelmi, see [www.daa.com.au]

 import StringIO
 import PIL.Image
 import gtk

 def image_to_pixbuf(image):
     fd = StringIO.StringIO()
     image.save(fd, "ppm")
     contents = fd.getvalue()
     fd.close()
     loader = gtk.gdk.PixbufLoader("pnm")
     loader.write(contents, len(contents))
     pixbuf = loader.get_pixbuf()
     loader.close()
     return pixbuf

 image = PIL.Image.open("example.png")
 pixbuf = image_to_pixbuf(image)
 image = gtk.Image()
 image.set_from_pixbuf(pixbuf)

8.8. Does somebody know what all these image/pixmap classes are?

GTK and GDK offer a number of classes that support drawing images.

8.9. How do I flip an image horizontally or vertically?

There is no ready-made API for this; you can flip a GdkPixbuf by manipulating its buffer. This may be a performance problem if done exclusively through Python (though manipulating it using Numeric is a faster alternative). Another alternative is using PIL, which is easily used in combination with PyGTK.

David Hugh-Jones submitted an [unoptimized] example function that flips a pixbuf:

  def flip_pixbuf(pb):
    bps = pb.get_bits_per_sample()
    rs = pb.get_rowstride()
    pix = pb.get_pixels()

    newpix = ""
    x = rs
    pixstride = pb.get_n_channels() * bps/8 

    while x <= len(pix):
        newrow = ""
        y = pixstride
        row = pix[x - rs: x]

        while y <= len(row):
            sample = row[y - pixstride: y]
            newrow = sample + newrow
            y += pixstride

        newpix += newrow
        x += rs

    return gtk.gdk.pixbuf_new_from_data(newpix,
                                        pb.get_colorspace(),
                                        pb.get_has_alpha(), 
                                        bps,
                                        pb.get_width(),
                                        pb.get_height(), 
                                        rs)
In PyGTK-0, when GdkImlib was compiled in, it was a matter of using flip_image_horizonal() and flip_image_vertical().

8.10. Is it possible to use SVG icons and images in PyGTK?

Yes; PyGTK supports svg icons very well via GdkPixbuf. The following example will open a simple widgetless window and render an SVG image (from the file 'my_imagefile.svg') as its icon the top left corner:

  w = gtk.Window()
  pixbuf = gtk.gdk.pixbuf_new_from_file('my_imagefile.svg')
  w.set_icon(pixbuf)
Apart from setting icons, you can use all functionality available to GdkPixbufs.

(Dennis Craven)

You can also do:

  img = gtk.Image()
  img.set_from_file('my_imagefile.svg')

8.11. How do I get a Pixbuf of a stock icon?

GtkWidget has a render_icon() method that comes in handy here:

    pixbuf = dialog.render_icon(gtk.STOCK_FIND, gtk.ICON_SIZE_MENU)
    dialog.set_icon(pixbuf)
(Doug Quale)

8.12. How do I register stock icons from an image file?

If you want to register a filename with the stock_id 'my-image', do something like this:

  factory = gtk.IconFactory()
  pixbuf = gtk.gdk.pixbuf_new_from_file(filename)
  iconset = gtk.IconSet(pixbuf)
  factory.add('my-image', iconset)
  factory.add_default()
David M. Cook provides us with a way of registering more than one icon at a time and load from a file those that are found not to be stock icons, which is useful to many applications:

  def register_iconsets(icon_info):
      iconfactory = gtk.IconFactory()
      stock_ids = gtk.stock_list_ids()
      for stock_id, file in icon_info:
          # only load image files when our stock_id is not present
          if stock_id not in stock_ids:
              pixbuf = gtk.gdk.pixbuf_new_from_file(file)
              iconset = gtk.IconSet(pixbuf)
              iconfactory.add(stock_id, iconset)
      iconfactory.add_default()

  register_iconsets([('gnome-stock-mic', 'gnome-stock-mic.png'),
                     ('gnome-stock-midi', 'stock_midi.png')])

8.13. How can I use an image as background in a gtk.Window?

iconsdir = './icons'
imagename = 'image.png'

win = gtk.Window()
path = os.path.join(iconsdir, imagename)
pixbuf = gtk.gdk.pixbuf_new_from_file(path)
pixmap, mask = pixbuf.render_pixmap_and_mask()
width, height = pixmap.get_size()
del pixbuf

win.resize(width, height)
win.shape_combine_mask(mask, 0, 0)  # make it transparent, not necessary
win.window.set_back_pixmap(pixmap, gtk.FALSE)
del pixmap

win.invalidate_rect( rect, False )

8.14. How do I convert a pixbuf to a PIL Image?

Use the pixbuf's get_pixels() in conjunction with Image's fromstring(): (the Image's frombuffer() works too, doesnt seem to matter much)

  import gtk
  import Image

  def pixbuf2Image(pb):
    assert(pb.get_colorspace() == gtk.gdk.COLORSPACE_RGB)
    dimensions = pb.get_width(), pb.get_height()
    stride = pb.get_rowstride()
    pixels = pb.get_pixels()
    mode = pb.get_has_alpha() and "RGBA" or "RGB"
    return Image.frombuffer(mode, dimensions, pixels,
                            "raw", mode, stride, 1)

  pb = gtk.gdk.pixbuf_new_from_file("foo.jpg")
  im = pixbuf2Image(pb)
  im.save("welldone.jpg", "JPEG", quality=80)
(Johan Dahlin, Danny M)

8.15. How can I get the data of a gtk.Image and save it in an external file?

it's very easy

    pixbuf = img.get_pixbuf()
    pixbuf.save(filename, "jpeg", {"quality":"100"})
where img is a gtk.Image() of course

8.16. How to show data that I already own from outside, in a gtk.Image?

In certain situations it is possible that data is already in a program, e.g. loaded from a URL, partially loaded from a large file or loaded from EXIF data. In this case it is possible to load this data into a Pixbuf without writing it to a file first, using a PixbufLoader (documentation at [www.pygtk.org] ) which exists specifically for this purpose.

Some example code:

    import urlib
    f = urllib.urlopen(url_to_image)
    data = f.read()
    pbl = gtk.gdk.PixbufLoader()
    pbl.write(data)
    pbuf = pbl.get_pixbuf()
    pbl.close()
    img.set_from_pixbuf(pbuf)
where img is an instance of gtk.Image

8.17. How to make a colorful image grayscale without using PIL?

the hint is to use pixbuf's saturate_and_pixelate method with the right arguments.

 import gtk

 pixbuf = gtk.gdk.pixbuf_new_from_file('image.png')
 pixbuf2 = pixbuf.copy()
 pixbuf.saturate_and_pixelate(pixbuf2, 0.0, False)

 pixbuf2.save('image_grayscale.png', 'png')
thanks to federico

8.18. How blend (composite) two images together?

You should use the method 'composite' of gtk.gdk.Pixbuf. It takes a bunch of parameters. The first parameter is both the second pixbuf to composite with the first one, and also the destination where the resulting image will be stored (the original pixbuf image data is destroyed in the process). The last parameter is a transparency level, from 0 to 255, where 127 means to blend the images 50% from each source.

Obligatory example:

 pixbuf = gtk.gdk.pixbuf_new_from_file("foo.png")
 pixbuf2 = gtk.gdk.pixbuf_new_from_file("bar.png")
 pixbuf.composite(pixbuf2, 0, 0, pixbuf.props.width, pixbuf.props.height, 0, 0, 1.0, 1.0, gtk.gdk.INTERP_HYPER, 127)

 ## now pixbuf2 contains the result of the compositing operation
 pixbuf2.save("zbr.png", 'png')
Beware that the destination image has to be at least as large as the first image. Otherwise you might get a cryptic warning like:

  python foo.py foo.py:7: GtkWarning?: gdk_pixbuf_composite: assertion `dest_x >= 0 && dest_x + dest_width <= dest->width' failed
You can also do this using just cairo: (PyGTK 2.8+)

 import cairo

 s1 = cairo.ImageSurface.create_from_png('foo.png')
 s2 = cairo.ImageSurface.create_from_png('bar.png')

 ctx = cairo.Context(s1)
 ctx.set_source_surface(s2, 0, 0)
 ctx.paint()

 s1.write_to_png('result.png')

8.19. How can I make a stock icon the default icon?

If one of the stock icons[1] matches your application, you can make this the default icon (e.g. used by the window manager).

  window = gtk.Window()
  icon = window.render_icon(gtk.STOCK_FIND, gtk.ICON_SIZE_DIALOG)
  gtk.window_set_default_icon(icon)
[1] [www.pygtk.org]

8.20. How do I draw a text [or something else] on a gtk.gdk.pixbuf?

It's just to copy the data of the pixbuf to a pixmap, draw what you want and do the way back with the gtk.gdk.Pixbuf.get_from_drawable method:

  #create a pixmap with the data of the pixbuf
  pixmap,_ = pixbuf.render_pixmap_and_mask()
  gc = pixmap.new_gc()

  p = widget.create_pango_layout('text')
  p.set_font_description(pango.fontdescription('Sans 12'))

  pixmap.draw_layout(gc, x, y, p)
  #draw whatever you want in the pixmap

  pixbuf.get_from_drawable(pixmap, pixmap.get_colormap(), 0, 0, 0, 0, -1, -1)

8.21. How can I use an image as background in a widget?

[Check FAQ 8.13 if the widget whose background you want to change is a gtk.Window]

import gtk

IMG = 'image.png'
pixbuf = gtk.gdk.pixbuf_new_from_file(IMG)


def expose(widget, ev):
    widget.window.draw_pixbuf(widget.style.bg_gc[gtk.STATE_NORMAL], pixbuf, 0, 0, 0, 0)
    if widget.get_child() != None:
        widget.propagate_expose(widget.get_child(), ev)
    return True


win = gtk.Window()
win.set_size_request(768, 32) # adjust to your image dimensions
win.connect("delete-event", gtk.main_quit)

evbox = gtk.EventBox()
evbox.connect('expose_event', expose)

hbox = gtk.HBox(False, 10)
l1 = gtk.Label("tururu 1")
hbox.pack_start(l1, True, True, 0)
l2 = gtk.Label("tururu 2")
hbox.pack_start(l2, True, True, 0)
l3 = gtk.Label("tururu 3")
hbox.pack_start(l3, True, True, 0)
evbox.add(hbox)
win.add(evbox)

win.show_all()
gtk.main()


9. Buttons: GtkButtons

9.1. How does one group radio buttons to allow only one concurrent button to be depressed?

gtk.RadioButton() has a group parameter that defaults to None. The first button in the group is the group parameter for the remaining buttons. So you would do something like:

 w = gtk.Window()
 v = gtk.VBox()
 b1 = gtk.RadioButton(label="Cows")
 b2 = gtk.RadioButton(label="Dogs", group=b1)
 b3 = gtk.RadioButton(label="Mountains", group=b1)
 v.add(b1)
 v.add(b2)
 v.add(b3)
 w.add(v)
 w.show_all()
For PyGTK-1 remember to add "Gtk" on widgets names (gtk.GtkWindow)

9.2. How do I create buttons that contain a pixmap?

The key to answering this is noticing that the GtkButton widget is actually a container, and you can place anything you like in it. So you could do something like:

 w = gtk.GtkWindow()
 button = gtk.GtkButton()
 label = gtk.GtkLabel('foobar')
 pix,mask = gtk.create_pixmap_from_xpm(w,None,'icon.xpm')
 pixmap = gtk.GtkPixmap(pix,mask)
 box = gtk.GtkHBox()
 button.add(box)
 box.add(pixmap)
 box.add(label)
And the button would contain a label and image like:

 (( \o/ foobar ))
Bonus answer: if you are trying to do this in glade, and you don't want one of the stock GTK pixmap buttons, you'll need to use the toolbar control, and add a button to it. You can then control if it presents images or not.

9.3. PyGTK 0.6.x: The stock pixmap buttons in glade, but they don't show in my buttons? (pygtk0.x)

If you choose to use the stock pixmap buttons in your glade file, you should realize they are provided by gnome, and that gtk has no stock pixmaps to be used. If you would like to use pixmap buttons, you need to enable gnome support, and XXX: hope for the best, as this is untested. :)

9.4. Why is a handler connected to a GtkRadioButton being called twice?

The GtkRadioButton is a bit wierd, because it triggers the clicked signal both when it's selected and when it's unselected (i.e. it is triggered when there is a state transition in it).

In practical terms, this means that if there is a currently selected item (item A) in a radiobutton group and you select another one (item B), a signal clicked will be generated for item A and for item B.

Inside the handler, you can use radiobutton.active to check its state: if it is TRUE, it's been selected, and vice-versa.

9.5. How do I render a stock button with a different label?

You could try Jan Weil's suggestion:

  gtk.stock_add([(gtk.STOCK_SAVE_AS, "Rename", 0, 0, "")])
See [www.moeraki.com] for more info.

Alternatively, if you don't want to override the default stock object, you can get the label child of the stock button and set the text directly. Thanks to Christian Reis for the suggestion!

  button = gtk.Button(stock=gtk.STOCK_CANCEL)
  button.show()

  alignment = button.get_children()[0]
  hbox = alignment.get_children()[0]
  image, label = hbox.get_children()
  label.set_text('Hide')
Doug Quale shames us all by providing a way for you to register your own stock icons, reusing images from existing stock items -- you get accelerators and themeability for free. His code creates three items, create, alter and drop, which use the new, properties and delete icons respectively:

  items = [('pg-create', '_Create', 0, 0, None),
           ('pg-alter', '_Alter', 0, 0, None),
           ('pg-drop', '_Drop', 0, 0, None),]

  # We're too lazy to make our own icons, 
  # so we use regular stock icons.
  aliases = [('pg-create', gtk.STOCK_NEW),
             ('pg-alter', gtk.STOCK_PROPERTIES),
             ('pg-drop', gtk.STOCK_DELETE),]

  gtk.stock_add(items)
  factory = gtk.IconFactory()
  factory.add_default()
  style= window.get_style()
  for new_stock, alias in aliases:
      icon_set = style.lookup_icon_set(alias)
      factory.add(new_stock, icon_set)

  # Create the relabeled buttons
  b_create = gtk.Button(stock='pg-create')
  b_alter = gtk.Button(stock='pg-alter')  
  b_drop = gtk.Button(stock='pg-drop')  
Note that the items that were copied froms are still available unchanged.

9.6. How do I add tooltips to a ToolButton in a Toolbar?

Just use the set_tooltips() method of the Toolbar, and then set_tooltip on the button itself:

  tooltips = gtk.Tooltips()
  [...]

  toolbar = gtk.Toolbar()
  toolbar.set_tooltips(True)
  [...]

  toolbutton = gtk.ToolButton()
  toolbutton.set_tooltip(tooltips, "hi")
(Danny Milosavljevic)

9.7. How do I add a stock icon to a ToggleButton?

If you want to add a stock item to a toggle button, first create a gtk.Image() and use the image_new_from_stock() method to set the stock item and the icon size:

  img = gtk.image_new_from_stock(gtk.STOCK_MEDIA_RECORD,  gtk.ICON_SIZE_BUTTON)
Next, create the stock button. Due to a bug in Gtk, make sure that you specify an empty string. If you don't add an empty string, you will scratch your head until your hair falls out:

  self.recButton = gtk.ToggleButton("")
Finally, set the 'image' property to the image:

  self.recButton.set_property("image", img)
(Jono Bacon)

9.8. How do I change the text color of a gtk button?

After alot of searching i found it , i dont know if there is a better way to do this but:

 self.Button = gtk.Button('Name')
 image,label =  self.Button.get_children()[0].get_children()[0].get_children()
 label.modify_fg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#FFFFFF'))


10. Windows: GtkWindows and GtkDialogs

10.1. How do I get a GdkWindow from a GtkWindow?

For some things (focus grabs are the example at hand) it is necessary to get the GdkWindow related to your GtkWindow.

 >>> w = gtk.GtkWindow()
 >>> w.realize()
 >>> w.get_window()
 <GdkWindow at 838ec70>

 w = gtk.Window()
 w.realize()
 w.window

10.2. Where are GtkDialogFlags defined?

Where are GtkDialogFlags defined? I can find them in gtk-types.defs, but I don't know how to access them.

Matt Wilson said They are:

 gtk.DIALOG_MODAL	          If set, the dialog grabs all keyboard events
 gtk.DIALOG_DESTROY_WITH_PARENT	  If set, the dialog is destroyed when its parent is.
 gtk.DIALOG_NO_SEPARATOR	  If set, there is no separator bar above the buttons.

10.3. How do I get my windows to show up where I want?

The short answer is: you don't; in X11, the window manager usually decides where the window is going to show up. However, you can provide hints so it has an idea of where the best place might be. Matt Wilson says:

 The window manager is responsible for placing the window on the screen
 when mapped if it isn't given an exact position.  For dialog boxes, 
 make sure you're passing in the parent window when creating the dialog
 box.  Then GTK will set up the correct hints that would make window
 managers treat the dialog window as a child of its parent.  How the
 window manager decides to treat the placement is configurable in some
 window managers...
If you would like to specify that a dialog is a `sub-window' of a window, for instance, you can use the following commands:

 w = gtk.Window()
 # ...
 d = gtk.Dialog()
 d.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
 d.set_transient_for(w)
When d is displayed, the window manager will know it is a transient for the parent window. By calling set_position it will [usually] be placed centered upon the parent.

(Note that some X11 servers such as Xming appear not to honour these placement settings.)

To do this with a dialog defined in a glade file, you'll need to do something like:

 d = glade_tree.get_widget(dialog_name)
 d.set_position(gtk.WIN_POS_CENTER_ON_PARENT)
 d.set_transient_for(parent_window)
If you want to specify positioning further -- to get a centered dialog, for instance -- you can use other options to the GtkWindow.set_position() method, which is described at [www.pygtk.org]

You can also save and restore the window position and size. Save the position with:

    (x, y) = w.get_position()
    (w, h) = w.get_size()
Later restoring it with:

    w = gtk.Window()
    w.move(x, y)
    w.resize(w, h)

10.4. How do I make a dialog block the whole application, so the user is forced to answer it?

This is called a modal dialog. Modal dialogs in general are unpleasant things, since they force a question upon the user. Ideally, the application should offer choices to the user non-obtrusively, instead of making demands upon him.

Having said that, there are times where a modal dialog is either necessary or an easy solution. Any window of the application can be set as modal; this will force it to be dismissed before the normal flow of the application is restored. FIXME: window.hide() removes modality?

To make a dialog modal, simply use:

 import gtk
 w = gtk.GtkWindow()
 w.set_modal(gtk.TRUE)
In pygtk2, you can also use:

 w = gtk.Dialog()
 ret = w.run()
 w.hide()
where the return value will stop the dialog's contents from being destroyed, see FAQ 10.6. The gtk.Dialog.run() method will just start a recursive loop and wait until the dialog emits a "respond" signal. So it is still your responsibility to emit that signals somehow:

 def on dialog_w_okbutton_clicked(*args):
     w.response(response_id)
This response_id will be returned by the gtk.Dialog.run() method.

10.5. I click on the close button (X) to close my gtk.Window. It disappears, but the program seems to hang!

If you create a gtk.Window and close it using the window manager (WM) --- in other words, by clicking on a close or X button on the window decorations, or using some other way the WM provides --- the window by default is destroyed. However, the 'gtk.main()' which you invoked to actually display the window is still running. To have the program quit when you close your window, you should connect 'gtk.main_quit()' to its 'delete-event' signal.

 win = gtk.Window()
 win.connect("delete-event", gtk.main_quit) # no parenthesis; you pass functions to connect

10.6. How do I avoid having my gtk.Window instance destroyed when I click on the window's close button? (or, When I redisplay my window, all my child widgets are missing and I get a bunch of Gtk-Critical errors!)

As you saw in FAQ 10.5, closing a window using the window manager, by default, causes it to be destroyed. In that example, we connected to 'delete-event' to break the mainloop when this happened, but at other times you may want to customize further the behaviour you get.

You can avoid the window's destruction by attaching a callback handler to the 'delete-event' handler in the GtkWindow and having it return 'True':

 win = gtk.Window()

 def on_delete_event(widget, event):
   print "Delete was called but I won't die!"
   return True

 win.connect("delete-event",on_delete_event)
A common thing to do is call the 'hide()' method in the handler.

The 'return True' part indicates that the default handler is _not_ to be called, and therefore the window will not be destroyed.

The actual process of event propagation is not simple to grasp and is better described at [www.gtk.org] .

It is important to note that you should not attach to 'destroy-event', as it cannot be overridden (it occurs server-side, and no client callback is triggered). Your window will always be destroyed, and your handler will not be called at all.

For gtk.Dialog its easier: just test the response id from running the dialogue against gtk.RESPONSE_DELETE_EVENT. It will match in time to be able to prevent the widget be destroyed, and there is no need to connect a signal.

For the specific case of GnomeAbout, see FAQ 10.13.

10.7. How do I change the window manager's icon for a PyGTK Window?

In both PyGTK-0 and PyGTK-2 you can use the set_icon() method of gtk.Window. If you're using glade2, additionally, you can set the icon from the properties dialog for the window.

here an example:

 w = gtk.Window()
 icon = w.render_icon(gtk.STOCK_DIALOG_INFO, gtk.ICON_SIZE_BUTTON)
 w.set_icon(icon)
 w.show()
 gtk.main()
This will work also on win32.

10.8. How do I get the GtkWindow's title?

Just call the get_title() method of the window:

 >>> w = gtk.Window()
 >>> w.set_title('foo')
 >>> print w.get_title()
 foo

10.9. How do I change the buttons on a MessageDialog?

PyGTK2: If you want one of the standard collections (Yes/No, Ok/Cancel...) then you can use one of the constants defined for GtkButtonsType [www.pygtk.org] in the gtk.MessageDialog constructor as the fourth argument to the constructor. The constructor format is:

  gtk.MessageDialog(parent, options, type, buttons, message)
If none of the standard choices are appropriate, simply use gtk.BUTTONS_NONE and call gtk.Dialog.add_button(), a little example:

 message = gtk.MessageDialog(None, gtk.DIALOG_MODAL, gtk.MESSAGE_INFO, gtk.BUTTONS_NONE, "message here")
 message.add_button(gtk.STOCK_QUIT, gtk.RESPONSE_CLOSE)
 resp = message.run()
 if resp == gtk.RESPONSE_CLOSE:
    message.destroy()
PyGTK0.x doesn't have a MessageDialog, and to manipulate a Dialog's buttons you need to rummage through dialog.action_area.

10.10. How do I scroll a ScrolledWindow to the position of a given child widget?

One common request is to get a ScrolledWindow to adjust to display one of the widgets it contains -- frequently you'd like to adjust the scrollbar to display the widget that receives focus. This is possible by using the set_value method of the ScrolledWindow's adjustment object in conjunction with the child widget's `focus_in_event' signal. An (untested) example follows:

 def focus_in(widget, event, adj):
   alloc = widget.get_allocation()        
   if alloc.y < adj.value or alloc.y > adj.value + adj.page_size:
     adj.set_value(min(alloc.y, adj.upper-adj.page_size))

 scrolled_window = gtk.ScrolledWindow()
 adj = scrolled_window.get_vadjustment()
 # ... create child widget
 child.connect('focus_in_event', focus_in, adj)
This should make the scrollbar adjust automatically whenever child receives focus.

10.11. How do GtkDialogs work?

To start off, an example and text by George Young:

 dialog = gtk.Dialog('Window Title',
                     parent_window,  # the window that spawned this dialog
                     gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,                       
                     ("Play Now", 77, gtk.STOCK_CLOSE, gtk.RESPONSE_CLOSE))
 dialog.vbox.pack_start(gtk.Label('Do you want to play a game?'))
 dialog.show_all()
 result = dialog.run()
 if result == 77:
    play_the_game()
 elif result == gtk.RESPONSE_CLOSE:
    user_just_closed_dialog()
 dia.destroy()
Buttons are specified in the creation of the dialog. Buttons can be standard gtk buttons with cute images like STOCK_CLOSE, or your own strings, e.g. "Play Now". Buttons are specified as a list of (button_appearance, response_integer) pairs. When a button is pressed, the run() member returns the corresponding response value.

The upper part of a Dialog has a gtk.VBox where you can pack your own widgets, e.g. the Label shown above, or a scrolledwindow containing a gtk.TreeStore (which could display a list or a tree). The buttons live in dia.action_area, a gtk.HBox where you can also manually put your own buttons or whatever.

MODAL_DIALOG means you app is locked until a response is made. DIALOG_DESTROY_WITH_PARENT tells the window manager to lose/open/destroy this dialog with your app window -- you usually want this.

Canned response values are:

 GTK_RESPONSE_NONE
 GTK_RESPONSE_REJECT
 GTK_RESPONSE_ACCEPT
 GTK_RESPONSE_DELETE_EVENT
 GTK_RESPONSE_OK
 GTK_RESPONSE_CANCEL
 GTK_RESPONSE_CLOSE
 GTK_RESPONSE_YES
 GTK_RESPONSE_NO
 GTK_RESPONSE_APPLY
 GTK_RESPONSE_HELP
[from pygtk-1.99.16/gtk/gtk-types.defs]

Many canned "stock" button icons are available from ADD to ZOOM_OUT; if you have the gtk source installed, you can use the gtk-demo program which offers a nice "Stock Item and Icon Browse" window.

There is a tutorial page relevant at [www.pygtk.org] and a reference page for GtkDialog at [www.pygtk.org]

For PyGTK2, there is a good example in the examples/pygtk-demo/demos/ subdirectory in your tarball.

10.12. How do I make ENTER in an entry box activate the OK signal

It is sometimes useful to be able to hit ENTER in an entry box and have it simulate clicking OK and closing the dialog. The two key steps are calling 'entry.set_activates_default(gtk.TRUE)' on the entry widget and then telling the dialog what the default action is, as in 'dlg.set_default_response(gtk.RESPONSE_OK)'. Here's a complete example:

  dlg = gtk.Dialog('Marker Label')
  dlg.show()

  entry = gtk.Entry()
  entry.show()
  entry.set_activates_default(gtk.TRUE)
  dlg.vbox.pack_start(entry)

  dlg.add_button(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL)
  dlg.add_button(gtk.STOCK_OK, gtk.RESPONSE_OK)
  dlg.set_default_response(gtk.RESPONSE_OK)
  response = dlg.run()

  if response == gtk.RESPONSE_OK:
      label = entry.get_text()
      print label
  dlg.destroy()

10.13. When closing the GnomeAbout box (or other GtkDialog subclasses), I get crashes and weird callback behaviour. What up with that?

Normally, when handling closed signals on a window, you should follow the advice in FAQ 10.6. However, for GnomeAbout, things aren't so simple.

Jon Willeke took the time to point out that in the case of GnomeAbout, to avoid having a window be destroyed when you close it, you need to also connect to the "response" handler. Malcolm Tredinnick offered a more detailed explanation of how this works:

A GtkDialog box has two main signals it implements: 'close' and 'response'. It also inherits the 'delete-event' signal from the GtkWidget class which also has a role to play here.

The 'response' signal is emitted pretty much whenever any action happens that causes the dialog box to finish running. The response signal emission will contain a "response ID" which can be user-defined or any one of the gtk.RESPONSE_* constants in pyGTK. The standard values correspond to things like one of the standard buttons being pushed or the window being destroyed. You can act differently based on the response ID.

The 'delete' signal is emitted whenever the corresponding GtkWidget is deleted in a "strange" (for want of a better word) way. The main case here is when the user closes the window via the window manager (Alt-F4, or clicking on the 'X' button in a typical window manager, for example). In that case, you also get a 'response' signal, so generally you just ignore the 'delete' signal (return gtk.TRUE as has been mentioned elsewhere).

For your standard GtkDialog widget, the only way the 'close' signal is emitted is when the Escape key is pressed. Widgets deriving from GtkDialog may have other buttons that are hooked up to emit 'close', but by default it is only bound to the Escape key (try it and see for the About dialog -- you can close it with Escape and it emits the predicted signal).

Colin Fox posted a summary of the signals he had to connect and the methods he needed to define to make things work as expected:

  def __init__(self, *args):
      # ...
      self.connect("response", on_aboutbox_response)
      self.connect("close", on_aboutbox_close)
      self.connect("delete_event", on_aboutbox_close)

  def on_aboutbox_response(self, dialog, response, *args):
      # system-defined GtkDialog responses are always negative, in which    
      # case we want to hide it
      if response < 0:
        dialog.hide()
        dialog.emit_stop_by_name('response')

  def on_aboutbox_close(self, widget, event=None):
      self.aboutbox.hide()
      return gtk.TRUE
In short, to keep the dialog from destroying itself or crashing you need to define a "delete-event" handler that returns True and define a "response" handler that stops emission of the signal, and, if you want the Escape key to work as expected, you also need to connect to the close signal.

It remains to be seen why you have to emit_stop_by_name() in the response handler -- it might be a GTK+ bug, but nobody alive seems to know the answer.

10.14. I created a modal dialog, but clicking on the main window covers it!

Short answer -- use:

  dialog.set_transient_for(main_window)
See FAQ 10.3 for details.

10.15. How do I get the position of my window in absolute terms (IOW, relative to the root X window)

Use the get_root_origin() method.

The get_position() method returns the position of the window relative to its parent window.

10.16. How do I start up a window maximized?

Just call maximize() on the window before you enter the main loop.

  win = gtk.Window()
  win.maximize()
  win.show()
  gtk.main()

10.17. How do I run a dialog without running another main loop?

GtkDialog.run by default starts another mainloop, and when you entered your input in the dialog you'll get a response returned to the application and the nested main loop is exited.

However, in some cases (for example when integrating with twisted) you do not want to use a nested mainloop, but rather reuse the current one.

So, here is a non blocking version version of GtkDialog.run that reuses the current mainloop:

 def dialog_response_cb(dialog, response_id):
   dialog.destroy()

   if response_id == gtk.RESPONSE_OK:
     print 'OK clicked'

 def dialog_run(dialog):
   if not dialog.modal:
     dialog.set_modal(True)
   dialog.connect('response', dialog_response_cb)
   dialog.show()
Perhaps it would be nicer to subclass GtkDialog and implement a run_nonblocked method, but that is beyond this FAQ entry and left as an exercise for the reader.

10.18. Changing a Window's background color

Thanks to Gian Mario Tagliaretti on the PyGTK mailing list:

   import pygtk
   pygtk.require('2.0')
   import gtk

   class FirstWin:
       def __init__(self):
           self.win = gtk.Window(gtk.WINDOW_TOPLEVEL)
           color = gtk.gdk.color_parse('#234fdb')
           self.win.modify_bg(gtk.STATE_NORMAL, color)
           #  To change the color again, just modify it again
           self.win.show()

       def main(self):
           gtk.main()

   if __name__ == "__main__":
       first = FirstWin()
       first.main()

10.19. How do I get XID for a GtkWindow? And for the root window?

Easy! Just get the "xid" attribute of its GdkWindow:

  >>> win = gtk.Window()
  >>> print win.window
  None
But it's None! You'd have to wait until the window is visible, or actually until it's realized, see the reference for more information about realize. So, to force a realization of a window, just call the realize() method:

  >>> win.realize()
Now we're ready to go, just fetch the xid:

  >>> print win.window.xid
  58720259L
And now, to do it for the root window, do this:

  >>> root = gtk.gdk.screen_get_default().get_root_window()
  >>> print root.xid
  72L
(Gustavo Carneiro)

10.20. How can I make my window appear in the center of the screen?

To tell the window manager to put the window in the center on the screen you can set a certain window manager hint, there is a convenience method in gtk.Window called set_position which allows you to do this in an easy way:

   window.set_position(gtk.WIN_POS_CENTER)
There are several other hints, to retreive a complete list, please visit the gtk.Window section in the reference manual: [www.pygtk.org]

10.21. How to hide a window when clicking the close button (instead of destroying it)

Let's say you have a gtk.Window called window.

  def hide_window(window, event):
    window.hide()
    return True

  window.connect('delete-event', hide_window)
The important bit is the return True in the callback, that prevents the window from being destroyed !

A more compact version would read:

   window.connect('delete-event', lambda w, e: w.hide() or True)

10.22. How can I find out when my GtkWindow is minimized?

Easy.

Connect to the window-state-event signal of the window and check if the window was iconified:

 def window_state_event_cb(window, event):
   if event.changed_mask & gtk.gdk.WINDOW_STATE_ICONIFIED:
      if event.new_window_state & gtk.gdk.WINDOW_STATE_ICONIFIED:
         print 'Window was minimized!'
      else:
         print 'Window was unminimized!'

 window = gtk.Window()
 window.connect('window-state-event', window_state_event_cb)
event.new_window_state can be one of the following:

 gtk.gdk.WINDOW_STATE_WITHDRAWN
 gtk.gdk.WINDOW_STATE_ICONIFIED
 gtk.gdk.WINDOW_STATE_MAXIMIZED 
 gtk.gdk.WINDOW_STATE_STICKY
also there is an undocumented state:

 gtk.gdk.WINDOW_STATE_FULLSCREEN
Example of use: [test.maemo.org]

10.23. How can I find out if a gtk.Window is visible?

To check if a gtk.Window is visible you can use the visible property inherited from gtk.Widget.

 self.window = gtk.Window()
 self.window.show()
 self.window.get_property("visible")

10.24. How do I create a shaped window?

Natan Zohar contributed this code for building a window shaped as a rounded rectangle. The heart of it is the GtkWindow.shape_combine_mask() method:

  import math

  import cairo
  import gtk
  from gtk import gdk

  class ShapedWindow(gtk.Window):
      def __init__(self):
          gtk.Window.__init__(self)
          self.connect('size-allocate', self._on_size_allocate)
          self.set_decorated(False)

      def _on_size_allocate(self, win, allocation):
          w,h = allocation.width, allocation.height
          bitmap = gtk.gdk.Pixmap(None, w, h, 1)
          cr = bitmap.cairo_create()

          # Clear the bitmap
          cr.set_source_rgb(0.0, 0.0, 0.0)
          cr.set_operator(cairo.OPERATOR_CLEAR)
          cr.paint()

          # Draw our shape into the bitmap using cairo
          cr.set_source_rgb(1.0, 1.0, 1.0)
          cr.set_operator(cairo.OPERATOR_SOURCE)
          cr.arc(w / 2, h / 2, min(h, w) / 2, 0, 2 * math.pi)
          cr.fill()

          # Set the window shape
          win.shape_combine_mask(bitmap, 0, 0)

10.25. How do I raise a window that is minimized or covered?

Just call show on the GDKWindow associated to the GTKWindow:

  topwin = gtk.Window(gtk.WINDOW_TOPLEVEL)
  topwin.show()

  # Time passes: User may have covered topwin by other 
  # desktop windows or minimized it via window-manager.
  gdkwin = topwin.window
  gdkwin.show()
(Yotam Medini)

10.26. Creating dialogs using the Glade file

1. Create a Dialog in the Glade editor.

2. Add buttons to the action area from Glade. The response id (last entry in glade properties of the button) will be the return value when the Dialog is called using the run command.

eg :

#getting the glade file

 dialog_glade = gtk.glade.XML("main.glade", "main_dialog")
#getting the dialog window from the glade file
 dialog = dialog_glade.get_widget("main_dialog")
#running the dialog.
 dialog.output = dialog.run()
#return value of the above command is the response id of the button pressed.
 if dialog.output == 1
   print "Button 1 pressed"

10.27. How can I focus an external window?

On X11, this is quite easy using the wnck module:

 import gtk
 import wnck

 screen = wnck.screen_get_default()

 while gtk.events_pending():
   gtk.main_iteration()

 for window in screen.get_windows()
    # select a window depending on WindowID, title, icon etc
    if not window.get_name().startswith('XChat:')
       continue
    window.activate(gtk.get_current_event_time())
Thanks to Jussi Kukkonen for the suggestion.

10.28. How do I make a ScrolledWindow take the size of its child?

Though the scope of a ScrolledWindow is exactly to contain widgets bigger than it, there may be cases in which one wants to show as much as possible of the content, and use scrolling bars only when necessary.

The official answer is "don't". Thinking gtk-ishly, you should just

1) guess reasonable defaults,

1a) possibly using gtk.Window.maximize(), or gtk.Window.fullscreen(),

2) in following executions, remember the last window size the user choose.

A more hackish answer is: use

  scrolledwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
only when necessary. Notice that detecting when it is necessary may be really not trivial.

An even dirtier hack to just resize the scrolled window to the size of the child is the following:

  previous_policy = scrolledwindow.get_policy()
  # Disable scrolling:
  scrolledwindow.set_policy(gtk.POLICY_NEVER, gtk.POLICY_NEVER)
  # See what changed:
  desired = scrolledwindow.size_request()
  toplevel = scrolledwindow.get_toplevel()
  new_size = toplevel.size_request()
  # Reenable scrolling:
  scrolledwindow.set_policy(*previous_policy)
This code can be used in two ways:

1) you got "desired", just call a set_size_request(*desired) on the scrolledwindow. But after that the user won't be able to shrink it.

2) you got "new_size", just call a toplevel.resize(*new_size). Notice that for this to do what you desire, the toplevel should not contain other widgets that expand/fill available space.

Also notice that in both cases (but this is particularly important if the user can't resize) this may overflow the screen border, so you may want to check that (with other dirty hacks).


11. Menus: Gtk*Menu and Gtk*MenuItem GtkToolbar

11.1. How do I turn off tearoff menus in libglade?

That is a good question. <jamesh> and <andersca> have both tried to convince me that it is a matter of turning off a preference in ~/.gnome/Gnome:

 [UI_GnomeApp]
 Menubar_detachable=false
 Menus_have_tearoff=false
None of these seem to work for me.

Johan has suggested I turn off Gnome support in the glade files. That doesn't work either.

I currently think this is a problem with libglade itself. Pure PyGTK apps don't have tearoff menus by default (see testgtk.py for an example).

11.2. How do I pop up a menu with a button click?

You need to attach a callback to "button_press_event" and catch its event object (which is the second parameter). This handler should be something like:

 def popup(widget, event):
   popup_menu.popup(None, None, None, event.button, event.time)
this results in a menu that is floating and you have to call popup_menu.destroy() or reuse the popup_menu.

You are also advised to call popup_menu.attach_to_widget() or at least .set_screen() so your application does not suffer in multiple screens environments.

Callling attach_to_widget() also means that your menu will be destroyed when widget that is being attached to, is destroyed. Popdown that happens by GTK does NOT destroy the menu, so if you want this behaviour, connect to 'deactivate' signal and in callback do widget.destroy()

Don't ask me what the None's are supposed to be. The API dox say:

 GtkWidget *parent_menu_shell,
 GtkWidget *parent_menu_item,
 GtkMenuPositionFunc func,
 gpointer data, 
 guint button,
 guint32 activate_time
But gtk.py does:

 def popup(self, pms, pmi, func, button, time)
So data is probably gone. Everybody uses None, why not you?

11.3. How do I find out if a GtkCheckMenuItem is selected (active)?

GtkCheckMenuItem has an "active" attribute, as GtkToggleButton and GtkCheckButton do. So:

 m = menu.get_menu()
 items = m.children()
 # assuming all items are checkitems
 for i in items:
  if i.active:
    print "Item %i is active"

11.4. I create a menubar with ItemFactory, but it disappears

I had a problem with my menubar not showing. The solution I found was to hold on to a reference to the ItemFactory.

e.g.

   self.item_factory = gtk.ItemFactory(gtk.MenuBar, "<main>", accel_group)
This seems to be a garbage collection problem.

Storing a reference to the ItemFactory where I could retrieve it later prevents the garbage collector from tidying it up. A global variable would work too, but of course "global vars are bad".

11.5. When specifying items to an ItemFactory, I pass the extra argument for the image but I can't see anything!

You have to remember to set the proper type for the menu element: <StockItem> if you are using a stock image ID, <ImageItem> if you are using a pixbuf image.

For example, using a stock image, assuming popup_stop is the callback function:

 factory = gtk.ItemFactory(gtk.Menu, '<foo_popup'>)
 items = (("/_Stop", None, popup_stop, 0, "<StockItem>",  gtk.STOCK_CANCEL),)
 factory.create_items(items)

11.6. How do I specify and save accelerators for my menu?

For most GTK+ applications, the user can change menu item accelerators by hovering on them with the mouse pointer and pressing a key combination on the keyboard (that can be switched on/off in .gtkrc-2.0 and gtk themes via gtk-can-change-accels = 0/1 though)

You can save the specified accelerators using gtk.accel_map_save(filename) and gtk.accel_map_load(filename). The stored file uses the accelpaths to associate the stored entry with the menu entry, so be sure to set language independent accelpaths for the menus and menu entries (and include some text prefix to make the windows distinguishable since accel_map_* functions work in app global scope).

XXX: providing a default set of accelerators for an application

11.7. How to i put a custom icon and custom label in a gtk.ImageMenuItem

first example:

 item = gtk.ImageMenuItem('Foo')
 img = gtk.Image()
 img.set_from_file('data/myimage.png')
 item.set_image(img)
second example:

 item = gtk.ImageMenuItem('Foo')
 img = gtk.image_new_from_stock(gtk.STOCK_REFRESH, gtk.ICON_SIZE_MENU)
 item.set_image(img)

11.8. How can I make the label for an action created using ui_manager appear beside rather than below the icon?

By default, labels for actions created with ui_manager appear below the icon. To change the appearance to show the label to the right of the icon, change the property "is_important" for the action to True and then use Toolbar.set_style(gtk.TOOLBAR_BOTH_HORIZ).

    ui_string="""<ui>
                 <toolbar name='tb'>
                   <toolitem action='Add'/>
                   <toolitem action='Delete'/>
                 </toolbar>
             </ui>"""

    actions=[('Add', 'gtk-add', '_Add', '<control>A',
              'Add record', addRec),
             ('Delete', 'gtk-delete', '_Delete', '<control>D',
              'Delete this record', delRec)]
    actiongrp=gtk.ActionGroup('Actions')
    actiongrp.add_actions(actions)
    actiongrp.get_action("Add").set_property("is_important", True)
    actiongrp.get_action("Delete").set_property("is_important", True)

    ui = gtk.UIManager()
    ui.insert_action_group(actiongrp, 0)
    ui.add_ui_from_string(ui_string)

    tb = ui.get_widget('/tb')
    tb.set_style(gtk.TOOLBAR_BOTH_HORIZ)

11.9. How can I insert space in a toolbar created with ui_manager to spread out groups of action buttons?

By default, action buttons in a toolbar created with gtk.ui_manager are packed left to right. By adding '<separator expand = "true"/>', subsequently added icons are pushed to the right. Adding multiple separators with expand set to true allows groups of actions to be spread out. For example to create something like this . . .

[Next][Prev]..............[Save][Cancel]...............[Delete]

do the following:

  <toolbar name='tb'>
    <toolitem action='Next'/>
    <toolitem action='Prev'/>
    <separator expand="true"/>
    <toolitem action='Save'/>
    <toolitem action='Cancel'/>
    <separator expand="true"/>
    <toolitem action='Delete'/>
  </toolbar>

11.10. How can I display the tooltip of the currently selected menuitem in a statusbar?

This is quite tricky, you need to get all proxies which are the widgets the actions represent and listen for events when they are selected.

You can do something like this;

 uimgr = gtk.UIManager()

 def on_menu_item__select(menuitem, tooltip):
     statusbar.push(-1, tooltip)

 def on_menu_item__deselect(menuitem, tooltip)
     statusbar.pop()

 def on_uimanager__connect_proxy(uimgr, action, widget):
     tooltip = action.get_property('tooltip')
     if isinstance(widget, gtk.MenuItem) and tooltip:
         cid = widget.connect(
          'select', on_menu_item__select, tooltip)
         cid2 = widget.connect(
          'deselect', on_menu_item__deselect)
     widget.set_data('app::connect-ids', (cid, cid2))

 def on_uimanager__disconnect_proxy(uimgr, action, widget):
     cids = widget.get_data('app::connect-ids) or ()
     for name, cid in cids:
         widget.disconnect(cid)

 uimgr.connect('connect-proxy', on_uimanager__connect_proxy)
 uimgr.connect('disconnect-proxy', on_uimanager__disconnect_proxy)
For a more complete example check this mailing list post; [www.daa.com.au]


12. Simple Containers: GtkBoxes, GtkTable, GtkFixed, GtkAlignment

12.1. What are the parameters to GtkAlignment.set()

This confused me for a while too, because Glade may trick you into thinking that they aren't what they are. Here it is:

 align.set(xalign, yalign, xscale, yscale)
Where the parameters are:

If you pack a GtkAlignment into a container, be careful to set the scale attributes to 1 or the alignment will not expand to take up the whole space in the parent widget (instead, an empty space will be left in the outer container, and get_allocation() will return bogus values for the GtkAlignment).

12.2. How does packing work (or how do I get my widget to stay the size I want)

You'll often find when working with containers that the size (and aspect ratio) of your widget isn't quite what you would expect. That's an intentional consequence of the GTK+ box model: the size of the widget is determined by packing: if its container offers it (or not) the possibility to expand and fill space available to it in the interface.

This is often confusing, and a good idea would be to play around a bit with gazpacho or glade to get a feeling for the box model. Essentially, the idea is based on a few key concepts:

                                        Border
    .----------------------------------/---.
    | Window                          H    |
    | .----------------------------------. |
    | | Entry                            | |   
    | '----------------------------------' |
    |                                      |
    '--------------------------------------

    .---------------------------------------------------------.
    | Window                                                  |
    | .--------------------. .------------------------------. |
    | | Entry1             | | Entry2                       | |
    | | packed w/ expand=0 | | packed w/ expand=1           | |
    | '--------------------' '------------------------------' |
    |                                                         |
    '---------------------------------------------------------'
How much each one actually gets is determined by:

This is important to understand when assembling your interfaces, and is the most peculiar thing about GTK+ programming to a newbie; although the packing-based widget geometry is more complex to understand initially than MS-style fixed layouts, it is infinitely superior, because GTK+ windows actually resize properly.

Spend some time experimenting with the "packing" tab in gazpacho/glade and some composite interfaces: it will teach you a lot in very short time.

[*] A cute analogy; in reality fill, expansion, requested sizes, widget expansion semantics, container packing semantics, electron spins and lunar cycles are computed to determine how much space each widget wins.


13. Lists and Trees: GtkList/TreeView

13.1. Is there a nice tutorial on using GtkTreeView and GtkTreeModel?

The pyGTK tutorial has an interesting section on TreeViews. Check last version in [www.pygtk.org]

13.2. How do the TreeStore and ListStore sequence APIs behave? [PyGTK2]

GtkTreeStore and GtkListStore implement the __getitem__/__setitem__ API. You pass in a tree path as a key and get a "row object" as the value. The row object basically combines a pointer to the tree model and a GtkTreeIter for the row. It in turn looks like a sequence -- one item per column in the model. You can get and set columns in the row through this interface. The best way to explain this is with some examples:

    liststore = gtk.ListStore(str, str, int)   # create list store  
    treestore = gtk.TreeStore(int, str, str)   # and a tree store
    ...   # fill in some rows
    row = liststore[42]   # get the row object for the 42nd row in the list
    print row[2]   # print 3rd column in row
    print liststore[42][2]   # or the two operations can be combined

    # print first column of first child of the second top level node
    print treestore[1,0][0]

    # assignment works too
    liststore[42][2] = 42 

    # you can also assign to the entire row in one go
    treestore[1,0] = (5, 'foo', 'bar')

    # or delete rows
    del liststore[42]
If you have a GtkTreeIter for a row, you can also get the corresponding row object for it with "store[iter]". As well as looking like a sequence, row objects have the following attributes:

    * next: next sibling row object
    * parent: parent row object
    * model: the GtkTreeModel for this row
    * path: the tree path of this row.
    * iter: a GtkTreeIter pointing at this row.
Iteration: tree and list stores implement the Python iteration API. This means that you can easily do things like print the value of the first column for every row in a list store:

    for row in liststore:
        print row[0]
For tree stores, this only iterates over the toplevel of the tree. Each row object has an iterchildren() method that can be used to iterate over the child rows if desired (if you directly iterate over the row, you will get the columns).

Extra optional argument on append/prepend/insert methods: I added an additional optional argument to the insert, insert_before, insert_after, prepend and append methods. If passed, the additional argument is interpreted as a sequence of values of the columns in the new row. For instance:

    liststore.append(('foo', 'bar', 42))
This makes the list store feel a lot more like the standard Python list objects.

13.3. How do GtkTreePaths work? [PyGTK2]

There is no special wrapper for GtkTreePaths in PyGTK. Since a tree path is really just an ordered list of indices, we represent them as tuples of integers. In places where a GtkTreePath must be passed to GTK, the following Python types will be accepted:

By accepting integers as length-one tree paths, the user can just pass in integers for GtkListStore methods, and think of them as row numbers. They don't even need to think about paths.

13.4. How do I define columns for a TreeView using TreeViewColumn?

First thing you should do is create a gtk.CellRenderer for the cells of the column you wish to add. There several gtk.CellRenderer subtypes, each one specialized for rendering a specific data type. More info on cell renderers is available at [www.moeraki.com] .

Then, you add a column to your tree view. You can instantiate a TreeViewColumn manually:

 col = gtk.TreeViewColumn(title, renderer, property1=column1, ...)
 treeview.insert_column(col, position)
 # note that treeview.append_column() exists too
or by using the TreeView's insert_column_with_attributes() API:

 gtk.TreeView.insert_column_with_attributes(position, title, renderer,
                                            property1=column1, ....)
The parameters are:

Notice that the order and number of columns in a tree view is unrelated to the columns in a tree model. It is not unusual to store extra application data in a hidden column in the tree model. It is only the property=column parameters that truly make the connection between the tree model and the tree view.

And now a simple example:

 COLUMN_NAME = 2              # the third model column holds 'name';
                              # column numbers start at zero, mind you
 renderer = gtk.CellRendererText()
 treeview.insert_column_with_attributes(-1, 'Name', renderer,
                                        text=COLUMN_NAME)
In this example, a text renderer is created. Then a column is added to the treeview, the 'text' attribute of the renderer indicating that the cell contents should be taken from the third column (COLUMN_NAME) of the tree model, in the corresponding row.

(Answer contributed by Gustavo Carneiro)

13.5. How do I create my own custom TreeModel.

By subclassing GenericTreeModel and implementing the "on_*" methods (e.g. on_get_iter(path) ) of GenericTreeModel. A simple example, treemodel.py, implementing all the required methods of the TreeModel, is included in the pygtk distribution in the examples/pygtk-demos/demos directory: [git.gnome.org]

Some other examples making use of GenericTreeModel:

13.6. How do I put icons in a TreeView?

You should use a gtk.CellRendererPixbuf as your column renderer. Here is an example that shows a stock icon and a label in two columns:

 (COL_PIXBUF, COL_STRING) = range(2)
 model = gtk.ListStore(gtk.gdk.Pixbuf, str)
 treeview = gtk.TreeView(model)
 model.append([gtk.gdk.pixbuf_new_from_file('icon.png'), 'This is a string'])

 renderer = gtk.CellRendererPixbuf()
 column = gtk.TreeViewColumn('Icon', cell, pixbuf=COL_PIXBUF)
 treeview.append_column(column)

 renderer = gtk.CellRendererText()
 column = gtk.TreeViewColumn('Text', cell, text=COL_STRING)
 treeview.append_column(column)
Note, that in this example you'll need an filename called icon.png in the current directory. If you wish to use a stock icon, use the render_icon method which you can find on every widget.

Advanced usage, if you want to be able to sgiw the icon and the string in the same column, you'd have to replace the last 6 lines in the above example with the following code:

  column = gtk.TreeViewColumn()
  column.set_title('Icons & Text')
  treeview.append_column(column)

  rendererer = gtk.CellRendererPixbuf()
  column.pack_start(renderer, expand=False)
  column.add_attribute(renderer, 'pixbuf', COL_PIXBUF)

  renderer = gtk.CellRendererText()
  column.pack_start(renderer, expand=True)
  column.add_attribute(renderer, 'text', COL_STRING)

13.7. How do I get all the selections in my TreeView.

Until gtk_tree_selection_get_selected_rows is wrapped (see [bugzilla.gnome.org] ) one can use this bit of code due to Martin H.:

 selected = []
 selection = treeview.get_selection()
 selection.selected_foreach(lambda model, path, iter, 
                            sel=selected: sel.append(path))
As of at least v2.4 gtk_tree_selection_get_selected_rows is wrapped. The above now becomes:
 selection = treeview.get_selection()
 model, selected = selection.get_selected_rows()

13.8. How do I delete the selected rows in a TreeView?

Grzegorz Adam Hankiewicz offered the following snippet, tested only with single selection TreeViews (for multiple selections, see FAQ 13.25):

   selection = self.list_view.get_selection() 
   model, iter, = selection.get_selected()
   if iter:
      path = model.get_path(iter)
      model.remove(iter)
      # now that we removed the selection, play nice with 
      # the user and select the next item
      selection.select_path(path)

      # well, if there was no selection that meant the user
      # removed the last entry, so we try to select the 
      # last item
      if not selection.path_is_selected(path):
         row = path[0]-1
         # test case for empty lists
         if row >= 0:
            selection.select_path((row,))
Note that using selected_foreach doesn't seem to work correctly (I think this is becasue you're not allowed to change the selection, or change the model, inside a foreach, but IMBW).

13.9. Is there a way to mass-specify columns in ListStore?

If you determine at runtime how many columns a ListStore should have, you can create a list with the column types and then pass them on to the ListStore using *columnlist. You can do list arithmetic to make multiple columns of the same type, too. Example:

 # 4 columns, 1-3 string, 4 int.
 columns = [gobject.TYPE_STRING]*3 + [gobject.TYPE_INT]
 gtk.ListStore(*columns)

13.10. How do I make a GtkTreeView with editable cells?

This can be done two different ways:

1) Set the "editable" property to True for all the cells in a column:

 renderer = gtk.CellRendererText()
 renderer.connect('edited', cell_edited_callback)
 renderer.set_property('editable', True)
 treeview.insert_column_with_attributes(-1, 'Editable String', renderer, text=0)
or

2) Set the "editable" property to True for individual cells:

The first thing you have to do is include a column of type boolean. It will specify if a row is editable or not.

 model = gtk.TreeStore(str, int, bool)

 iter = model.append()
 model.set_value(iter, 0, 'foo')
 model.set_value(iter, 1, 34)
 model.set_value(iter, 2, True)
Next thing is create the TreeView, Columns and Renderers:

 treeView = gtk.TreeView(model)

 renderer = gtk.CellRendererText()
 column = gtk.TreeViewColumn('column 1', renderer, text=0, editable=2)
 treeView.append_column(column)

 renderer = gtk.CellRendererText()
 column = gtk.TreeViewColumn('column 2', renderer, text=1, editable=2)
 treeView.append_column(column)
And that's all. The important thing is the creation of the column. The values of the properties 'text' and 'editable' are column indexes of the model. So in the first column we are saying that the text property of the renderer should use the index 0 of the model and should use the value of the index 2 for the editable property (which we set it to gtk.TRUE when we added the row)

The process is similar for ToggleButtons, but the property names are different and you need to set up a callback for the toggle signal to make the changes persistent. So let's create a simple model:

 model = gtk.ListStore(bool, bool)
 model.append(row=(True, True))
 model.append(row=(False, False))
This time the first value of the model holds the real data and we use the second boolean type for the 'activatable' status. Let's create the TreeView and the column:

 treeview = gtk.TreeView(model)
 renderer = gtk.CellRendererToggle()
 renderer.connect('toggled', toggled_callback, model)
 column = gtk.TreeViewColumn('test', renderer, active=0, activatable=1)
 treeview.append_column(column)
As you can see we need to setup the toggle_callback, which looks like this:

 def toggled_callback(cell, path, model=None):
     iter = model.get_iter(path)
     model.set_value(iter, 0, not cell.get_active())
This last step is important because otherwise the TreeView won't update the screen and it will look like a non activatable column.

    renderer.connect('toggled', toggled_callback, model, 1)
and update the callbacks declaration to:
 def toggled_callback(cell, path, model=None, col_num=0):

13.11. What signal is emitted when a user selects/clicks on a row in a GtkTreeView?

The TreeView has no "select/unselect_row" signals that the good ole CList did. You can however attach to the TreeView selection's "changed" signal:

 def on_selection_changed(selection, ...): 
     model, paths = selection.get_selected_rows()
     if paths:
        # do the thing!

 self.treeView = gtk.TreeView(mymodel)
 selection = self.treeView.get_selection()
 selection.connect('changed', on_selection_changed)
For more information on the GtkTreeSelection object, see the C docs for GTK+: [developer.gnome.org]

(Lorenzo Gil Sanchez, David Cook)

13.12. How do I change the color of the alternate row shading on the TreeView widget?

James Henstridge: These settings can be changed in the gtkrc file. Note however that the settings are intended for theme authors. If you set them explicitly for your app, then your app would not fit in with the rest of the apps on the desktop (the user might have specifically picked their theme because they like that shade of grey).

The gtkrc directives would look something like this:

    style "mystyle" {
        GtkTreeView::even_row_color = "xxxx"
        GtkTreeView::odd_row_color = "yyyy"
    }
You could use this to create a custom theme if you don't like how trees display on your desktop.

13.13. How do I create a lazy TreeView?

A "lazy" TreeView is one in which child rows are not actually appended to the TreeStore row until the user clicks on the expander for that row. The trick is to get the expander to show up without having to add any actual child rows.

An easy way to do this is to append a "blank" child row to each row that you know will have children. Schematically:

 if hasChildren(iter):
     store.append(iter)
Here hasChildren is some function that determines if the iter will actually have children based on the data it contains.

Then in the "row-expanded" handler, check for a NULL value in a column you are sure will never be NULL for actual data:

 def on_row_expanded(view, iter, path):
     store = view.get_model()
     child = store.iter_children(iter)
     if store.get_value(child, 0) is None:
         # append actual rows at iter
Alternatively, you could set some marker value like -1 in a particular column.

13.14. How do I show different images when a TreeView item is expanded and collapsed.

James Henstridge pointed out the pixbuf_expander_closed and pixbuf_expander_closed column properties, which Doug Quale cooked into an example (derived in part from the one in FAQ 13.6):

  class silly_list(gtk.TreeView):
    def __init__(self):
        gtk.TreeView.__init__(self)
        self.init_model()
        self.init_view_columns()

    def init_model(self):       
        store = gtk.TreeStore(gtk.gdk.Pixbuf, gtk.gdk.Pixbuf, str)
        # Fill the model with some silly sample data.             
        add_pixbuf = self.get_icon_pixbuf(gtk.STOCK_ADD)
        remove_pixbuf = self.get_icon_pixbuf(gtk.STOCK_REMOVE)
        for p in xrange(10):
            parent = store.append(None, (add_pixbuf, remove_pixbuf,
                                         'Parent %s' % p))
            for c in xrange(5):
                store.append(parent, (None, None, 'Child %s' % c))
        self.set_model(store)

    def get_icon_pixbuf(self, stock):
        return self.render_icon(stock,
                                size=gtk.ICON_SIZE_MENU,
                                detail=None)

    def init_view_columns(self):            
        col = gtk.TreeViewColumn()
        col.set_title('Silly Example')
        render_pixbuf = gtk.CellRendererPixbuf()
        col.pack_start(render_pixbuf, expand=False)
        col.add_attribute(render_pixbuf, 'pixbuf-expander-closed', 0)
        col.add_attribute(render_pixbuf, 'pixbuf-expander-open', 1)
        render_text = gtk.CellRendererText()
        col.pack_start(render_text, expand=True)
        col.add_attribute(render_text, 'text', 2)
        self.append_column(col)
Note: Doug also offered an example which uses the row-expanded and row-collapsed signals, which can be used when more complex behaviour is desired. The following changes should be made in this case:

    def __init__(self):
       # same as above
       self.connect('row-expanded', self.on_row_expanded)
       self.connect('row-collapsed', self.on_row_collapsed)

    def set_row_icon(self, treeiter, stock):
        store = self.get_model()
        store.set(treeiter, 0, self.get_icon_pixbuf(stock))

    def on_row_expanded(self, treeiter, path):
        self.set_row_icon(treeiter, gtk.STOCK_REMOVE)
    on_row_expanded = staticmethod(on_row_expanded)

    def on_row_collapsed(self, treeiter, path):
        self.set_row_icon(treeiter, gtk.STOCK_ADD)
    on_row_collapsed = staticmethod(on_row_collapsed)

13.15. My TreeView/TreeModel rows represent instances (or any python object), but how can I keep track of them?

Define a extra field in your TreeModel of the following type: gobject.TYPE_PYOBJECT. This field will hold the reference to the instance which the row respesents.

For Example:

 model = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_PYOBJECT)

Now you can set the reference to the instance for a row like this:

 COLUMN_TEXT = 0
 COLUMN_OBJECT = 1

 # the iter is pointing to the row which you want to set
 model.set(iter, COLUMN_TEXT, unicode("Hey", 'iso-8859-1'),   COLUMN_OBJECT, theObject)

Later on if you want to get the Reference to the Instance again:

 COLUMN_TEXT = 0
 COLUMN_OBJECT = 1

 # the iter is pointing to the row which you want to get
 object = model.get_value(iter, COLUMN_OBJECT)

13.16. My Treeview shows all my strings/text values as numbers in the columns!

You're probably using the type gobject.TYPE_CHAR instead of gobject.TYPE_STRING to define the column in your store. The latter is the correct type for string data.

13.17. How do I make a popup menu appear when I right-click my TreeView?

Define a handler for the treeview's button_press_event that sets the treeview cursor and calls popup.popup(). Stephen Kennedy provides an example, assuming you have a popup menu stored as self.popup:

  def on_treeview_button_press_event(self, treeview, event):
    if event.button == 3:
        x = int(event.x)
        y = int(event.y)
        time = event.time
        pthinfo = treeview.get_path_at_pos(x, y)
        if pthinfo is not None:
            path, col, cellx, celly = pthinfo
            treeview.grab_focus()
            treeview.set_cursor( path, col, 0)
            self.popup.popup( None, None, None, event.button, time)
        return True
Note that treeview.get_path_at_pos could return None in the case that the mouse is not over a row when the right button is clicked. You need to decide what your program should do in that case. Perhapse you want a different menu to pop up?

13.18. Is it possible for a TreeModel to tell a CellRendererToggle that it is in an "in between" (inconsistent) state?

The gtk.CellRendererToggle has an "inconsistent" property, similar to the "active" property. If it is set to True, then the cell will display in the inconsistent state. You can either have a column in your model that maps to the inconsistent property, or use a cell data function to set the property based on some other condition.

The C documentation lists all the CellRendererToggle's properties: [developer.gnome.org]

13.19. How do I change alignment on a specific cell renderer?

To right-align a cell renderer, you can alter the xalign property doing:

 renderer.set_property('xalign', 1.0)
You can add padding in the same fashion adjusting the xpad property.

Another thing to note is that renderers use the normal GTK packing mechanism. If you want one renderer to expand and take up any extra space (or `compete' for it if more than one cell has expand=TRUE), pack it with expand=TRUE, and vice-versa.

13.20. How do I keep GenericTreeModel from leaking references?

Arjan Molena added a"leak_references" property to GenericTreeModel to turn this behavior off, but in his words, "Turning this feature off (default is on, the old behaviour) will always decrement the refcount on PyObjects. This will prevent memory/refcnt leaks from happening. The Model should ensure that objects which are used as iterators are not destroyed before the iterator is destroyed. This sounds a bit silly, but there are no other way, unless we get to know when a iterator is being removed..."

If you turn off "leak_references" and don't keep careful track of your nodes, you get a good old-fashioned segfault.

One easy way to "ensure that objects which are used as iterators are not destroyed before the iterator is destroyed" is to have your model keep a dictionary or list of tree nodes so that a reference stays around until you explicitly delete it. (See FAQ 13.15 for another method of keeping track of node references.)

 class MyTreeModel(GenericTreeModel):
      def __init__(self, ...)
 	 GenericTreeModel.__init__(self)
 	 self.set_property("leak_references", 0)
          ...
         self.nodemap = {} # a mapping from paths to nodes
          ...

      def on_get_iter(self, path):
 	 ...
         node = self.nodemap.setdefault(path, MyNodeClass(path, ...))
         return node
Here the dictionary's setdefault method returns self.nodemap[path] if it exists, otherwise the node object is created, added to the dictionary, and returned. Note that the programmer is responsible for deleting these node references when they are no longer needed by the TreeModel.

13.21. How do I get changes in my TreeModel to show up in my TreeView?

Whenever there are changes in your TreeModel, you need to emit a signal to notify the view of the change. Otherwise, your View content may become stale, in which case refreshing the View manually (via a resize or pointer movement) may show the new data. GenericTreeModel provides 4 methods for notifying the View of Model updates:

You can also emit the signals directly with the gtk.Object emit() method. See the TreeModel API reference for more info on these functions and signals: [developer.gnome.org]

13.22. How do I display a combo box in a Treeview?

In PyGTK 2.6+, there is now a Combo Renderer: [www.pygtk.org]

Baiju M provided an example: [www.daa.com.au]

But be careful that there's a bug with the 'edited' signal and the CellRendererCombo.

*-*-*

If you want to do it the old way:

Lorenzo Gil Sanchez writes: Currently, you can only do that with C. With Python you can create a custom CellRenderer to render the cells in the way you want. What you can not do in Python is a CellRender with edit capabilities, like a combo box. If you want a CellRenderer to support edition it must implement the CellEditable interface. There is no way to make a Python class to implement a GLib interface with the current PyGTK bindings.

Having said that, Lorenzo did provide a hacked version of a Treeview with Combos; check it out at [www.mail-archive.com]

13.23. Why doesn't expand_row() display an expanded row for paths longer than one element?

TreeView.expand_row will expand only the exact row specified by the path. If your tree is deeper than 1 level, this means that even though the row is expanded, its parents might not be. If you want to be sure that the expanded row (specified by the path) is expanded and visible to the end-user, you need to expand all its parents rows using a loop:

  for i in range(len(path))
    treeview.expand_row(path[:i+1], gtk.FALSE)
This will be easier when pygtk wraps gtk+ 2.2 functions because the TreeView.expand_to_path() method will be available.

13.24. How do I transform the value in my model before displaying it in the TreeView?

It's easy to have a gtk.CellRendererText render an integer i from your model, but it's not so easy to render f(i). The solution hinges around gtk.TreeViewColumn.set_cell_data_func, using the original CellRendererText you supply to that column, and setting the renderer's 'text' property.

Here's a quick and dirty example:

  def render_filesize(column, cell, model, iter):
      origstr = cell.get_property('text')
      sizestr = origstr + 'B' # Add a "B" for bytes after value
      cell.set_property('text', sizestr)

  model = gtk.ListStore(str, int)
  view = gtk.TreeView(model)

  column = gtk.TreeViewColumn('File', gtk.CellRendererText(), text=0)
  view.append_column(column)

  size_renderer = gtk.CellRendererText()
  size_renderer.set_property('xalign', 1.0)
  size_column = gtk.TreeViewColumn('Size', size_renderer, text=1)
  size_column.set_cell_data_func(size_renderer, render_filesize)
  view.append_column(size_column)

13.25. How do I delete multiple selections?

Yang Zheng writes: pygtk does not allow treemodel.remove(iter) in the selected_foreach(...) function, so I had to store all the iterators for the selected rows and then go back to delete them. The iterator parameter of the function called by selected_foreach is not the actual treestore row iterator, so I had to get it by using treemodel.get_iter(path). Only then was I abe to use treemodel.remove(iter) to remove the row. Here's my code:

  # list that stores all the iterators of the selected rows
  selectList = []
  # function to get iterator of selected row
  def GetSelectedIter(model,path,iter,rowList):
    selectIter = model.get_iter(path)
    rowList.append(selectIter)

  # get reference to each row 
  selection = watchvar_treeview.get_selection()
  selection.selected_foreach(GetSelectedIter,selectList)
  # actual removal of rows
  for iter in selectList:
    watchvar_treestore.remove(iter)
As of at least v2.4 the above can be simplified somewhat with the use of selection.get_selected_rows:
    selection = treeview.get_selection()
    model, selected = selection.get_selected_rows()
    iters = [model.get_iter(path) for path in selected]
    for iter in iters:
         model.remove(iter)
Jiri Bajer: Obtaining the paths from selected_rows() before any deletion and iteration over them doesn't work for me:

Issue 1: The paths change as the items are removed. Imagine the tree contains (0,) and (1,) and we want to delete them at once. After the first deletion the tree now contains (0,) but selected_rows[1] is (1,).

Issue 2: Removing parent causes all children to be removed automatically as well. Imagine the tree contains (0,) and (0,0) and we want to delete them at once. Parent comes always before its children in selected_rows() and thus after the first deletion the tree is empty but selected_rows[1] is (0,0).

The solution is to read the selections one-by-one:

  while True:
    (unused, paths) = model.get_selection().get_selected_rows()
    if paths == []:
      break
    model.remove( model.get_iter(paths[0]) )
There may be a performance issue when the selection is long and flat (has almost no children) because get_selected_rows() is called len(get_selected_rows) times.

13.26. How do I perform an action when the user clicks on the title column of a TreeView?

The TreeViewColumn has a "clicked" signal, which you can attach any callback to. More information at [www.moeraki.com]

The callback will receive as an argument the clicked column instance, and you can either attach data to the TreeViewColumn or pass user data in when you connect the signal (for example a key or column number). You'll usually do this when adding the columns to the TreeView.

(David Cook)

13.27. How do I run a command for each TreeModel row, or how does TreeModel.foreach() work?

TreeModel offers a foreach() function that invokes a function for each row in the model. It takes a handler function and an optional user_data argument which allows arbitrary data to be specified to the function. The function receives as parameters: model, path, iter, and when specified, the user_data supplied to foreach().

  def foreach_handler(model, path, iter, user_data):
    # get value from current row, column 1
    val1 = model.get_value(iter, 1)
    print "value is: %s" % val1
    # set user_data ("my value") as value of current row, column 2
    model.set_value(iter, 2, user_data)

  treemodel.foreach(foreach_handler, "my value")
(Yang Zheng)

13.28. When connecting to 'row-inserted', my model value is always None. Why?

Short answer: you should probably be using 'row-changed' instead of 'row-inserted'. Doug Quale elaborates on the rationale behind this below.

This gotcha seems to be almost certain to trip up everyone at some point. When the 'row-inserted' signal is emitted, the model frequently (always?) contains unitialized (empty) rows. The reason for this is kind of odd, but it's a logical consequence of the gtk+ C API.

If you look at the C API, there's no way to add an initialized row to a TreeModel in one step. The available functions like ListStore.append() and ListStore.insert() add new uninitialized rows to the model and you must subsequently use ListStore.set() to set the column values in the row. This seems harmless, but gtk+ emits the 'row-inserted' signal as soon as the empty row is added and confusion and befuddlement ensues in the signal handlers.

Because of this, the 'row-inserted' signal isn't very useful. Most of the time when you might think you want 'row-inserted' you actually want 'row-changed' instead. This will catch the ListStore.set() which almost inevitably follows an insert. Try changing your handler to be called on 'row-changed' instead of 'row-inserted' to see if that works better. Or you can leave the handler as it is and add a new 'row-changed' handler to set the correct row values when they are set in the model.

13.29. How do I use a python object to store data for all the columns in a row?

(Jeff Bowden:)

Here's an example for how to use a python dict object to store row data:

   def dict_cell_data_func(column, cell, model, iter, col_key):
     text = model.get_value(iter, col_key[0])[col_key[1]]
     cell.set_property("text", text)

   model = gtk.ListStore(object)
   tree_view = gtk.TreeView(model)
   renderer = gtk.CellRendererText()
   column = gtk.TreeViewColumn("Foo", renderer)
   column.set_cell_data_func(renderer, dict_cell_data_func, (0, 'foo'))
   tree_view.append_column(column)

   obj = {'foo': 'foo text'}
   model.append([obj])
(Jiri Bajer:)

This can be useful when we don't know how many model columns we will need. TreeStore columns have to be specified in constructor and there is no way to change the type of or add the columns in runtime.

Some people work around this TreeStore constructor's limitation by putting the columns in a list and passing the list to the constructor. However, once the TreeStore is created, we cannot add/remove the columns anyway -- we have to destroy the whole TreeStore and build it from scratch with different columns. Example (see the *model_columns syntax):

  model_columns = []
  view_columns = []

  model_columns.append(gobject.TYPE_STRING)
  view_columns.append(gtk.TreeViewColumn(title, renderer, text=len(model_columns)))
  ... append more columns ..

  model = gtk.TreeStore(*model_columns)
  view = gtk.TreeView()
  for column in view_columns:
	view.append_column(column)
  view.set_model(model)

13.30. How do I move rows around in a GtkTreeView?

The trick is getting an iter for the row you want to move to, and then reassigning to another row in the model. An example handler which moves the selected row up follows.

Remember to send in model as the second argument to the connect handler, like this:

 button.connect("clicked", button_clicked_cb, model)
To move a row up one step, define button_clicked_cb like this:

 def button_clicked_cb(button, model):
   selection = model.get_selection()
   model, selected = selection.get_selected()
   assert not selected is None
   path = model.get_path(selected)
   row = path[0]
   assert row > 0
   this = model[row][0]
   prev = model[row-1][0]
   model[row-1][0] = this
   model[row][0] = prev
   selection.select_path(row-1)
This handler assumes you have a 1-column model; if you have more than one column the [0] indexes would have to be changed accordingly. Note also that you may use get_value/set_value instead of the __getitem__/__setitem__ protocol as per FAQ 13.2.

This handler takes a model, which should be specified as the optional "user_data" argument while connect()ing. You may of course obtain the model reference through other means, such as via an instance variable.

In case you have an iter and need to obtain a corresponding path to it, just use the model's get_path() method, which takes an iter. From this path you can obtain the row id. (There is no iter_prev() method corresponding to the model's iter_next()).

(Doug Quale)

Note: The approach described by Doug swaps the contents of rows, thus is dependent on the model as he said before. In addition it doesn't care about children. TreeStore.swap(), TreeStore.move_after() and similar work only within the same tree level and also don't care about children. The most generic way of moving cells requires creating a new row and copying contents, the same recursively for all children and then deleting old rows. Example of move_up:

  def copy_subtree(self, tree_store, from_iter, to_iter):
    if not tree_store.iter_has_child(from_iter):
      return
    from_path = list(tree_store.get_path(from_iter))
    for from_child_number in range(0, tree_store.iter_n_children(from_iter)):
      from_child_path = from_path
      from_child_path.append(from_child_number)
      from_child = tree_store.get_iter(tuple(from_child_path))
      to_child = tree_store.append(to_iter, row=tree_store[tuple(from_child_path)])
      self.copy_subtree(tree_store, from_child, to_child)

  new_cell = tree_store.insert_after(None, selected_cell, row=tree_store[previous_path])
  copy_subtree(tree_store, previous_cell, new_cell)
  tree_store.remove(previous_cell)
  tree_view.expand_row(next_path, True)
  tree_view.set_cursor_on_cell(next_path)
See also FAQ 13.51 for generic iter_prev() example.

13.31. How do I change the color of a row or column of a TreeView?

To change the color of an entire column, you can change the foreground and background properties of the renderer:

 renderer = gtk.CellRendererText()
 renderer.set_property("foreground", "red")
 # ... and use renderer in TreeViewColumn 
To change the color of specific rows or cells in a TreeView, use the foreground and background arguments to gtk.TreeViewColumn. The example below demonstrates their usage:

 model = gtk.ListStore(str, str, str, str)
 model.append(("Henrik","Ibsen","green","#23abff"))
 model.append(("Samuel","Beckett","orange","OldLace"))
 model.append(("Thomas","Mann","yellow","peach puff"))
 treeview = gtk.TreeView(model)
 renderer = gtk.CellRendererText()
 treeview.append_column(gtk.TreeViewColumn("First Name", renderer, 
                        text=0, foreground=2, background=3))
 treeview.append_column(gtk.TreeViewColumn("Last Name", renderer,
                        text=1, foreground=3, background=2))
As always with TreeViewColumn, the arguments indicate which field in the module carries the relevant value. For the first column in the first row, for instance, text will come from field 0 ("Henrik"), background colour from field 2 ("#23abff").

NOTE: When setting 'background-cell' or 'foreground' color with set_cell_data_func you cannot just set the cells you want different from the others. You need to set *all cells* otherwise all cells of the column will get colored the same way. You can set background-cell-set to False to tell the cell renderer to render it in default way.

(Walter Anger)

An alternative method (with somewhat different results) to change the color of a specific cell is to render Pango markup for a column. To do so, use the 'markup' argument with gtk.TreeViewColumn in place of the 'text' argument. One difference between this method and the one described above is that its effect applies regardless of whether or not the row is selected or in focus.

 model = gtk.ListStore(str, str, str, str)
 model.append(("<span background='green'>Henrik</span>",
               "<span background='#23abff'>Ibsen</span>"))
 model.append(("<span background='orange'>Samuel<span>","Beckett"))
 model.append(("<span background='yellow'>Thomas</span>",
               "<span background='peachpuff'>Mann</span>"))
 treeview = gtk.TreeView(model)
 renderer = gtk.CellRendererText()
 treeview.append_column(gtk.TreeViewColumn("First Name", renderer, 
                        markup=0))
 treeview.append_column(gtk.TreeViewColumn("Last Name", renderer,
                        markup=1))
(Steven T. Snyder)

13.32. How do I select [or edit] a row in my TreeView?

Using a path, as per FAQ 13.3, you can do something like:

 # assuming treeview is instantiated
 sel = treeview.get_selection()
 sel.select_path(path)
If you would like to prepare the row you're targeting for editing (leaving the cursor in edit mode inside a certain cell), note that you don't need to select the row; all you need is to do:

 treeview.set_cursor(path, focus_column, start_editing=True)
where focus_column is the column you'd like to focus the cursor and edit.

Note that the scroll_to_cell() call may come in handy given that the cell you want to edit may not be on-screen. Dave Aitel points out that it may be necessary to place scroll_to_cell in an idle handler after your set_cursor call or it won't work (at least in Redhat9).

13.33. How do I handle DnD operations in a GtkTreeView?

There are generally two types of DnD operations that can be done regarding a GtkTreeView:

Furthermore, there are two ways to enable DnD for a GtkTreeView:

Note that these functions behave differently:

Using the functions together yields the possibility of dropping external objects onto the column titles but not into the blank area. reorderable() can be used. FAQ 13.34 includes code examples of these approaches.

13.34. How do I work with the reorderable() property of GtkTreeview?/The reorderable() property of GtkTreeView is too limited

The use of reorderable() is described in the Reference. On occasions you may find that it is too limited though:

For example, when a reparenting of rows via DnD is needed, reorderable() won't do. For these cases Walter Anger created an example that covers a reorderable GtkTreeView exaustively (more discussion on the topic can be found in the mailing list thread starting at: [www.daa.com.au] ) This example is also useful for a better insight into DnD in GtkTreeViews.

Such a custom made implementation of reorderable() consists of four parts:

Proper setup of the GtkTreeView with the appropriate DnD functions:

 treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK,
				 [("example", 0, 0)], gtk.gdk.ACTION_COPY)
 treeview.enable_model_drag_dest([("example", 0, 0)],
 				gtk.gdk.ACTION_COPY)
 treeview.connect("drag_data_received", on_dragdata_received_cb)
A callback for generic DnD handling:
 def on_dragdata_received_cb(treeview, drag_context, x, y,
 						    selection, info, eventtime):
         model, iter_to_copy = treeview.get_selection().get_selected()
         temp = treeview.get_dest_row_at_pos(x, y)
         if temp != None:
             path, pos = temp
         else:
             path, pos = (len(model)-1,), gtk.TREE_VIEW_DROP_AFTER
         target_iter = model.get_iter(path)
         if check_row_path(model, iter_to_copy, target_iter):
             iter_copy(model, iter_to_copy, target_iter, pos)
             drag_context.finish(gtk.TRUE, gtk.TRUE, eventtime)
             treeview.expand_all()
         else:
             drag_context.finish(gtk.FALSE, gtk.FALSE, eventtime) 
The treeview.get_dest_row_at_pos(x, y) will be None if you drop the selection on the empty section at the bottom of the TreeView. In that case, set the path and pos from scratch.

A checking function for ancestry and equality of the row:

 def check_row_path(model, iter_to_copy, target_iter):
         path_of_iter_to_copy = model.get_path(iter_to_copy)
         path_of_target_iter = model.get_path(target_iter)
         if path_of_target_iter[0:len(path_of_iter_to_copy)] ==
 	    path_of_iter_to_copy:
             return False
         else:
             return True
And finally the row DnD function:
 def iter_copy(model, iter_to_copy, target_iter, pos):

   	[...retrieve data of the selected row...]

         if (pos == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE) or (pos ==
 	     gtk.TREE_VIEW_DROP_INTO_OR_AFTER):
             new_iter = model.prepend(target_iter, None)
         elif pos == gtk.TREE_VIEW_DROP_BEFORE:
             new_iter = model.insert_before(None, target_iter)
         elif pos == gtk.TREE_VIEW_DROP_AFTER:
             new_iter = model.insert_after(None, target_iter)

 	[...copy over the values of the old row into the new one ...]

         for n in range(model.iter_n_children(iter_to_copy)): 
             next_iter_to_copy = model.iter_nth_child(iter_to_copy, n)
             iter_copy(model, next_iter_to_copy, new_iter,
 		 gtk.TREE_VIEW_DROP_INTO_OR_BEFORE)

 	[...remove old row...]
As said earlier, this implementation allows one to reparent rows via DnD. Of course, when this is not needed, editing out the concerned parts will do just fine.

If you're moving the data instead of copying it, change the .iter_nth_child(iter_to_copy, n) in the last part to be .iter_nth_child(iter_to_copy, 0). As you move items, next siblings all move down.

13.35. How do I use the TreeModelFilter to process tree/store data automatically?

The TreeModelFilter is not just useful for filtering data from a model; it can be used to synthesize completely new columns that were never in the original model. The example code below generates a filtered version of a ListStore, with 2 string columns, from an original model with only one column of Python objects. This filtered model can then be used in TreeViews and ComboBoxes in the usual fashion. This is a powerful way to abstract your application model (your business objects) from the view (the way they are displayed.) For more info on TreeModelFilter see the PyGTK tutorial (FAQ 1.9.)

 import gtk

 # A "business object" class.  Instances will be nodes of our TreeStore.
 class Person(object):
     def __init__(self, lastname='', firstname=''):
         self.lastname = lastname
 	 self.firstname = firstname

 # Create some person objects
 people = [['Ellison', 'Larry'], ['Gates', 'Bill'], ['McNealy', 'Scott']]
 nodes = [Person(*names) for names in people]

 # Put the objects in a store.
 store = gtk.ListStore(object) # A store with only Python objects.
 for node in nodes: store.append([node])

 # Here we use a ModelFilter to synthesize values on the fly using the 
 # modify_func callback.  These values can be used for interactive 
 # searches and ComboBoxes, whereas the original store of Python objects would 
 # not be understood as valid strings by gtk.  The original TreeModel is 
 # a "child" of the ModelFiter.

 # obtain a ModelFilter from our store
 filtered = store.filter_new()

 # The modify func is where the values in the ModelFilter are computed from
 # the the objects in the child model.
 def modify_func(model, iter, col, attrs):
     # Convert the filter iter to the corresponding child model iter.
     child_model_iter = model.convert_iter_to_child_iter(iter)
     child_model = model.get_model()
     obj = child_model.get_value(child_model_iter, 0)
     return getattr(obj, attrs[col])

 # Set the modify func, passing in the "virtual" column types.  The
 # last parameter is user data to specify the attributes/properties of the 
 # business objects that we want to display.
 filtered.set_modify_func([str]*2, modify_func, ['lastname', 'firstname'])

 # Callback for printing out nodes.
 def print_node(model, path, iter):
     print [model.get_value(iter, i) for i in range(model.get_n_columns())]

 # Print out the contents of the ModelFilter.
 filtered.foreach(print_node)

 # Modify the original objects directly.
 people = [['van Rossum', 'Guido'], ['Torvalds', 'Linus'], ['Henstridge', 'James']]
 for node, names in zip(nodes, people):
     node.lastname, node.firstname = names

 # Does the ModelFilter track our changes?    
 filtered.foreach(print_node)
(David Cook, John Finlay)

13.36. How do I unselect a path in a TreeView?

If all you need to do is query and change the current cursor state, you can use the gtk.TreeView class functions set_cursor() and get_cursor().

However, the gtk.TreeView class functions don't directly let you do more complex selection work, such as unselecting everything in a TreeView, or unselecting anything at all for that matter.

However, a TreeSelection object lets you do that just those sorts of things. You can get the TreeSelection object associated with any Treeview with the TreeView's get_selection() member function.

Every Treeview has one gtk.TreeSelection object associated with it. This object is associated with the TreeView, not its underlying model. (So if a particular model has multiple views, each view will have a separate selection object associated with it.)

As an example, to unselect the path of the current cursor:

  path, focus_column = treeview.get_cursor()

  treeview.get_selection().unselect_path(path)
There are also functions select_range() and unselect_range() to do the (un)selections on ranges of paths.

13.37. How do I avoid displaying (hide) a certain column in a TreeView?

As with most column operations, just use the appropriate TreeColumn method; in this case, TreeViewColumn.set_visible: [www.pygtk.org]

(the great John Finlay)

13.38. How do I display pixbufs instead of numbers for integer or boolean values in my treemodel?

This is an example of changing the data type or format of a treemodel column before displaying it. The general technique for these problems is to use a cell data function to modify the value before setting the appropriate cell renderer property to display it. The same idea will work to control the formatting of a text cell, for example to format a number before displaying it.

The cell data function is straightforward. We set the 'pixbuf' cell property to the pixbuf to display or None for a blank column. Replace MODEL_COLUMN_NUMBER with the model column number that provides the value and MY_PIXBUF with the pixbuf you want to display:

    def cell_data_func(tree_column, cell, model, tree_iter):
        if model.get_value(tree_iter, MODEL_COLUMN_NUMBER):
            pixbuf = MY_PIXBUF
        else:
            pixbuf = None
        cell.set_property('pixbuf', pixbuf)
There are several ways to set up a treeview column to use a data function. Here is one example:

    cell = gtk.CellRendererPixbuf()
    treeview.insert_column_with_data_func(-1, 'title xxx', cell,
         cell_data_func)
It's worthwhile to look at the properties provided by each type of cell renderer. CellRendererPixbuf has 'stock-id' and 'stock-size' properties that can be very useful if you want to use stock icons instead of your own pixbufs. To display the stock gtk+ yes and no icons for a boolean model column you can do something like this:

    def cell_data_func(tree_column, cell, model, tree_iter):
        if model.get_value(tree_iter, MODEL_COLUMN_NUMBER):
            stock_id = 'gtk-yes'
        else:
            stock_id = 'gtk-no'
        cell.set_property('stock-id', stock_id)

13.39. I defined a TreeView in glade, how do I manipulate its columns and other properties?

Glade's support for TreeView is somewhat limited: you can only define a "blank" treeview. You must create the columns and (optionally) set other properties entirely in Python code.

What glade can do is assign a model to it, define the model's columns and populate them.

Note that you get hold of your glade-defined treeview using get_object("treeview1") as you would for any other widget in the glade widget tree. Similarly, if you attached a model to it, you can get it via get_object("model"), or similar code.

From there on you can use treeview API to add columns, work on its model, and manipulate its configuration. An example follows:

  builder = gtk.Builder()
  builder.add_from_file("stuff.glade")
  treeview1 = builder.get_object("treeview1")

  # add columns:
  C_DATA_COLUMN_NUMBER_IN_MODEL = 0
  cell0 = gtk.CellRendererText()
  col0 = gtk.TreeViewColumn("title", cell0,    
                            text=C_DATA_COLUMN_NUMBER_IN_MODEL)
  treeview1.append_column(col0)

  # set model (i.e. the data it contains. We assume this is not done via glade.)
  store = gtk.TreeStore(gobject.TYPE_STRING)
  treeview1.set_model(store)
  # If the model was defined via glade, we could get it via something like
  # builder.get_object('model')

  # set reorderable
  treeview1.set_reorderable(True)

  # to add a row see FAQ 13.2

13.40. How do I change the font of a CellRendererText?

If you want to have *all cells* in a column use a specific font use the "font" or "font-desc" properties of the column's cell renderer. See [www.pygtk.org] for details.

  model = gtk.ListStore(str, str)
  tv = gtk.TreeView(model)

  cell = gtk.CellRendererText()
  font = pango.FontDescription('courier bold 12')
  cell.set_property('font-desc', font)
  col = gtk.TreeViewColumn('This column in courier-bold-12!', cell, text=0)
  tv.append_column(col)

  cell = gtk.CellRendererText()
  col = gtk.TreeViewColumn('default font', cell, text=1)
  tv.append_column(col)

  model.append(('cell with changed font', 'cell with default font'))
If you want to have individual cells of a column use a different font, you can have the font attribute set from a model column value:

  model = gtk.ListStore(str, str)
  tv = gtk.TreeView(model)

  cell = gtk.CellRendererText()
  col = gtk.TreeViewColumn('header', cell, text=0, font=1)
  tv.append_column(col)

  model.append(('This text in arial bold 12', 'arial bold 12'))
  model.append(('And this in courier 14', 'courier 14'))
  model.append(('And yet this in mono 12', 'mono 12'))
You can do more complex changes to the font by using pango markup in your text columns. There is a section of the tutorial that covers this in depth: [www.pygtk.org]

(John Finlay, examples by Guilherme Salgado)

13.41. How do I show a GtkImage (even animations) in a treeview? (subclassing GtkCellRenderer)

Here is a cellrenderer that allows to put a gtk.Image in your TreeStore :

 class CellRendererImage(gtk.GenericCellRenderer):

   __gproperties__ = {
      "image": (gobject.TYPE_OBJECT, "Image",
      "Image", gobject.PARAM_READWRITE),
   }

   def __init__(self):
      self.__gobject_init__()
      self.image = None

   def do_set_property(self, pspec, value):
      setattr(self, pspec.name, value)

   def do_get_property(self, pspec):
      return getattr(self, pspec.name)

   def func(self, model, path, iter, (image, tree)):
      if model.get_value(iter, 0) == image:
         self.redraw = 1
         cell_area = tree.get_cell_area(path, tree.get_column(0))
         tree.queue_draw_area(cell_area.x, cell_area.y, cell_area.width, \

            cell_area.height)

   def animation_timeout(self, tree, image):
      if image.get_storage_type() == gtk.IMAGE_ANIMATION:
         self.redraw = 0
         image.get_data('iter').advance()
         model = tree.get_model()
         model.foreach(self.func, (image, tree))
         if self.redraw:
            gobject.timeout_add(image.get_data('iter').get_delay_time(), \
               self.animation_timeout, tree, image)
         else:
            image.set_data('iter', None)

   def on_render(self, window, widget, background_area,cell_area, \
      expose_area, flags):
      if not self.image:
         return
      pix_rect = gtk.gdk.Rectangle()
      pix_rect.x, pix_rect.y, pix_rect.width, pix_rect.height = \
         self.on_get_size(widget, cell_area)

      pix_rect.x += cell_area.x
      pix_rect.y += cell_area.y
      pix_rect.width  -= 2 * self.get_property("xpad")
      pix_rect.height -= 2 * self.get_property("ypad")

      draw_rect = cell_area.intersect(pix_rect)
      draw_rect = expose_area.intersect(draw_rect)

      if self.image.get_storage_type() == gtk.IMAGE_ANIMATION:

         if not self.image.get_data('iter'):
            animation = self.image.get_animation()
            self.image.set_data('iter', animation.get_iter())
            gobject.timeout_add(self.image.get_data('iter').get_delay_time(), \
               self.animation_timeout, widget, self.image)

         pix = self.image.get_data('iter').get_pixbuf()
      elif self.image.get_storage_type() == gtk.IMAGE_PIXBUF:
         pix = self.image.get_pixbuf()
      else:
         return
      window.draw_pixbuf(widget.style.black_gc, pix, \
         draw_rect.x-pix_rect.x, draw_rect.y-pix_rect.y, draw_rect.x, \
         draw_rect.y+2, draw_rect.width, draw_rect.height, \
         gtk.gdk.RGB_DITHER_NONE, 0, 0)

   def on_get_size(self, widget, cell_area):
      if not self.image:
         return 0, 0, 0, 0
      if self.image.get_storage_type() == gtk.IMAGE_ANIMATION:
         animation = self.image.get_animation()
         pix = animation.get_iter().get_pixbuf()
      elif self.image.get_storage_type() == gtk.IMAGE_PIXBUF:
         pix = self.image.get_pixbuf()
      else:
         return 0, 0, 0, 0
      pixbuf_width  = pix.get_width()
      pixbuf_height = pix.get_height()
      calc_width  = self.get_property("xpad") * 2 + pixbuf_width
      calc_height = self.get_property("ypad") * 2 + pixbuf_height
      x_offset = 0
      y_offset = 0
      if cell_area and pixbuf_width > 0 and pixbuf_height > 0:
         x_offset = self.get_property("xalign") * (cell_area.width - \
            calc_width -  self.get_property("xpad"))
         y_offset = self.get_property("yalign") * (cell_area.height - \
            calc_height -  self.get_property("ypad"))
      return x_offset, y_offset, calc_width, calc_height
Don't forget to register this class with:

 gobject.type_register(CellRendererImage)
Then use it as another cellrenderer:

 col = gtk.TreeViewColumn()
 cell = CellRendererImage()
 col.pack_start(cell, False)
 col.add_attribute(cell, 'image', 0)

13.42. How do I show a picture (image) in a treeview background or exist any way how to set treeview (and window with treeview) as transparency ?

FIXME: This needs to be written.

13.43. Are there tips for improving performance when adding many rows to a Treeview?

You should freeze TreeView updates and detach the model before adding a lot of rows:

 treeview.freeze_child_notify()
 treeview.set_model(None)

 # Add rows to the model
 # ...

 treeview.set_model(model)
 treeview.thaw_child_notify()
Note that sorting can slow down addition dramatically, and if you use a sort function, you should set an alternative one for the duration of the insertion:

  model.set_default_sort_func(lambda *args: -1) 
  model.set_sort_column_id(-1, gtk.SORT_ASCENDING)
Alternatively, you can just start with a new model, prefill it before attaching it to the view, and enable sorting at the end of this process.

Another way to make adding rows to treeview "feels faster" is to progressively add rows using a generator function:

  def fill_tree(tree, items, step=128):
      '''Generator to fill the listmodel of a treeview progressively.'''
      n = 0
      model = tree.get_model() # a listmodel in this example

      tree.freeze_child_notify()
      for it in items:
	  model.append(it) # Fill the model

	  # yield to gtk main loop once awhile
	  n += 1
	  if (n % step) == 0:
	      tree.thaw_child_notify()
	      yield True
	      tree.freeze_child_notify()

      tree.thaw_child_notify()
      # stop idle_add()
      yield False

  def on_load_tree(w, tree):
      '''Event handler'''
      keys = [(x,) for x in range(100000)]

      # fill the tree during idle cycles.
      loader = fill_tree(tree, keys)
      gobject.idle_add(loader.next)
For a very large number of rows, you might want to have a look at Easygrid [www.earthenware-services.org] by John Gill:

"I've found the liststore ok up to about 10-20K rows, after that I start to run into problems. With easygrid I'm able to browse tables with 500K rows with no performance problems."

Finally, the Ruby/Gtk TreeView tutorial states that

"You should not keep around a lot of tree row references if you have so many rows, because with each insertion (or removal) every single tree row reference will check whether its path needs to be updated or not."

For ListStore and TreeStore, you may be able to use iters instead of TreeRowReferences, as, according to the pygtk manual "...some models guarantee that an treeiter is valid for as long as the node it refers to is valid (most notably the gtk.TreeStore and gtk.ListStore)."

13.44. What is TreeRowReference and how to use it?

TreeRowReference can be used when you to 'follow' a position of a row that the user may reorder (eg the path will change).

Everytime you need the path you do tree_row_ref.get_path() and you get the current path

and to create a new tree_row_ref that you can use follow:

 iter = model.append(None, 'LSD')
 path = self.tree.get_path(iter)
 tree_row_ref = gtk.TreeRowReference(tree_model, path)
For extreme situtations you may find these fuctions from the API useful: [pygtk.org]

13.45. How do I create a custom gtk.CellRenderer?

In order to render custom objects in TreeViews you have to subclass the gtk.GenericCellRenderer class and register it.

The following example shows a CellRenderer for a custom object.

 class CellRendererCustom(gtk.GenericCellRenderer):
        __gproperties__ = {
                "custom": (gobject.TYPE_OBJECT, "Custom",
                "Custom", gobject.PARAM_READWRITE),
        }

        def __init__(self):
                self.__gobject_init__()
                self.custom = None

        def do_set_property(self, pspec, value):
                setattr(self, pspec.name, value)

        def do_get_property(self, pspec):
                return getattr(self, pspec.name)

        def on_render(self, window, widget, background_area, cell_area, expose_area, flags):
                self.custom.draw(window, widget, cell_area.x, cell_area.y)

        def on_get_size(self, widget, cell_area=None):
                return (0, 0, self.custom.get_width(), self.custom.get_height())

 gobject.type_register(CellRendererCustom)
Note that in order to use the custom object in e. g. a ListStore you'll have to subclass it from gobject.GObject and register it properly.

Notice however that in more recent pygtk versions it is possible to subclass a predefined CellRenderer type instead of starting from scratch from GenericCellRenderer; in this case you just have to overwrite methods of the form do_*: for instance the following creates a CellRenderer for text which cells twice as big as normal:

 class CellRendererBig(gtk.CellRendererText):

     def __init__(self):
         gtk.CellRendererText.__init__(self)

     def do_get_size(self, widget, cell_area):
         # We start from the standard dimension...
         size_tuple = gtk.CellRendererText.do_get_size(self, widget, cell_area)
         size = [item * 2 for item in size_tuple]
         return tuple(size)      

 gobject.type_register(CellRendererBig)
Jiri Bajer: draw() method in on_render is deprecated - use self.widget.window.draw_rectangle() instead. See [www.mail-archive.com] for details.

13.46. How do I add a tooltip to a cell, row or column of a TreeView

The basic idea is to connect a handler to your TreeView for the motion-notify event. As the mouse moves across the view, the handler will be called and the current row and column can be determined via the TreeView.get_path_at_pos() call passing in the x and y coord. from the event. Once the cell (or row or column) is determined, you can compute your tooltip text and popup a window.

To do all this and make it have the same style as a normal Tooltips popup window is non-trivial.

There is an opensource module, TreeViewTooltips, you can download here: [www.astro.umass.edu] which implements all the above and is extensible. A demo app is included.

13.47. How do I create a GtkTreeView having nodes with underlined text?

small example that uses underlined text into the treeview

 import gtk
 import gobject
 import pango

 COL_TEXT = 0
 COL_ULINE = 1

 text = ["Foo", "Bar", "Baz", "Quux", "Bloody", "Underline"]

 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
 window.set_default_size(-1, 300)
 window.connect("destroy", gtk.main_quit)

 store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_UINT)

 i = 0
 for i in range(len(text)):
     if 'a' in text[i]:
         uline = pango.UNDERLINE_DOUBLE
     elif 'o' in text[i]:
         uline = pango.UNDERLINE_SINGLE
     else:
         uline = pango.UNDERLINE_NONE
     iter = store.append()
     store.set(iter, COL_TEXT, text[i], COL_ULINE, uline)

 view = gtk.TreeView(store)
 window.add(view)

 renderer = gtk.CellRendererText()
 renderer.props.underline_set = True

 column = gtk.TreeViewColumn(None, renderer, text=COL_TEXT,  underline=COL_ULINE)
 view.append_column(column)

 window.show_all()

 gtk.main()

13.48. How do I hide some rows in a TreeView?

To be able to hide some of the rows of a TreeView, you need to use a TreeModelFilter. This class acts as a wrapper for your TreeModel (a ListStore or TreeStore), allowing you to choose which rows are displayed based on the value of a gobject.TYPE_BOOLEAN column, or based on the output of a certain function.

Keep in mind that this is only a wrapper, it does not implement the usual insertion or removing functions provided by ListStore or TreeStore. To do that, you need to access the model itself.

Also, when you get an iter from your TreeView, it will point to the TreeModelFilter, so you need to make a translation into a useful iter, by calling convert_iter_to_child_iter(), and viceversa. The same goes for paths.

Here is a working example of how to create a TreeModelFilter to hide some rows, and how to access the data after it's been displayed.

 import gtk
 import gobject

 # Prepare the window and other Gtk stuff 
 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
 window.set_default_size(100, 200)
 window.connect("destroy", gtk.main_quit)
 vbox = gtk.VBox()
 window.add(vbox)

 # Creation of the actual model
 text = ["This", "is", "an", "example", "of", "hiding", "rows"]
 store = gtk.ListStore(gobject.TYPE_STRING, gobject.TYPE_BOOLEAN)
 for i in text:
    store.append((i, True))

 # Creation of the filter, from the model
 filter = store.filter_new()
 filter.set_visible_column(1)

 # The TreeView gets the filter as model
 view = gtk.TreeView(filter)

 # Some other gtk stuff
 renderer = gtk.CellRendererText()
 view.insert_column_with_attributes(-1,"Test",renderer,text=0)
 vbox.pack_start(view)
 hide_button = gtk.Button("Hide Selected")
 vbox.pack_start(hide_button)

 # The hiding function
 def hide_row(widget, *args):
    # Get the selected row
    filter_iter = view.get_selection().get_selected()[1]
    # Translate it into a useful iterator
    store_iter = filter.convert_iter_to_child_iter(filter_iter)
    # Use it to hide the row
    store[store_iter][1] = False

 hide_button.connect("clicked", hide_row)

 # That's it
 window.show_all()
 gtk.main()

13.49. How to manually sort rows?

For some reasons, you may not want to rely on the built-in mechanisms to sort rows in a TreeView. For instance, once a sort column ID has been set on a TreeModel implementing the TreeSortable interface, it cannot be returned to the original unsorted state. This may be a problem if you want your users to be able to move rows even in a sorted tree, since it then needs to be unsorted.

To manually sort rows, you first need the column headers to be clickable. For all columns, you have to do the following:

 column.set_clickable(True)
 column.connect('clicked', sortRows)
The sortRows() function would look like this:

 sortOrder   = gtk.SORT_ASCENDING
 lastSortCol = None

 def sortRows(column):
    """ Sort the rows based on the given column """
    global lastSortCol, sortOrder

    if lastSortCol is not None:
       lastSortCol.set_sort_indicator(False)

    # Ascending or descending?
    if lastSortCol == column:
       if sortOrder == gtk.SORT_ASCENDING:
          sortOrder = gtk.SORT_DESCENDING
       else:
          sortOrder = gtk.SORT_ASCENDING
    else:
       sortOrder   = gtk.SORT_ASCENDING
       lastSortCol = column

    # Sort rows
    # ...

    # Display the sort indicator
    column.set_sort_indicator(True)
    column.set_sort_order(sortOrder)
To actually sort the rows, the most efficient way is to use the reorder() function which is very fast. The pattern would look like this:

 rows = [tuple(r) + (i,) for i, r in enumerate(model)]
 rows.sort(key=your_sort_key_callable)
 model.reorder([r[-1] for r in rows])
It is more efficient than dumping the rows, sorting them, and then individually reloading them.

In any case, you might want to read the sorting mini-howto: [wiki.python.org]

13.50. Target sensitive tooltip for treeview/iconview.

Main idea is similar to FAQ entry 13.46 but instead of manually reimplementing the whole tooltip (with it's timing, windows, signals, whatever), we only change the tooltip string on a mouse move.

This way is direct, consistent and fits well a small projects.

Example callback for an iconview:

    def on_iconview_universe_motion_notify_event(self, iv, event):
        """Deletes old tooltip and adds new one for new icon."""

        # On mouse move, old tooltip must dissapear.
        self.icon_tooltips = gtk.Tooltips()

        # Adds tip if no buttons are pressed during the move.
        if not event.state:
            pos = iv.get_path_at_pos(int(event.x), int(event.y))
            tip = "Place mouse on any icon to see brief info about the object."
            if pos:
                data = list(iv.get_model ()[pos])
                tip  = str(data)
            self.icon_tooltips.set_tip(iv, tip)
"self.tooltips" should be defined in constructor or on class level to protect tooltip from gc. Simple

    def __init__ (self):
        self.icon_tooltips = None
        ...
is enough. Main point is that when we call

    self.icon_tooltips = gtk.Tooltips()
old tooltip is destroyed (garbage collected). New one is updated and will appear in proper place automatically.

Thanks to Christian for useful hints and code improvement.

13.51. How do I get to previous row in the model when iter_prev() method doesn't exist?

You can simulate iter_prev() method using the following code:

 def iter_prev(iter, model):
   path = model.get_path(iter)
   position = path[-1]
   if position == 0:
     return None
   prev_path = list(path)[:-1]
   prev_path.append(position - 1)
   prev = model.get_iter(tuple(prev_path))
   return prev
Returns iter for previous row or None if the node is first on a level. This behavior is consistent with iter_next().

The iter for previous row is calculated from path. As the paths are tuples and they are immutable, we have to convert the tuple to a list. Then cut out the last member (= position on current tree level), decrement it and convert the resulting list back to tuple.

See also FAQ 13.30 for simpler but non-generic approach using hardcoded number of columns.

13.52. How can I save and restore which rows are expanded in a TreeView?

To determine which rows are expanded you must first get the model from the Treeview with gtk.TreeView.get_model(). Then using gtk.TreeModel.foreach() iterate through each row and perform a gtk.TreeView.row_expanded(path).

To restore the expanded rows, instead of row_expanded(), use expand_row().

Here is an example:

  def saveExpandedLines(self):
       self.expandedLines = []
       model = self.myView.get_model()
       model.foreach(self.checkLine)

   def checkLine(self, model, path, iter, data = None):
       if self.myView.row_expanded(path):
           self.expandedLines.append(path)

   def restoreExpandedLines(self):
       model = self.myView.get_model()
       model.foreach(self.restoreLine)

   def restoreLine(self, model, path, iter, data = None):
       if path in self.expandedLines:
           self.myView.expand_row(path, False)

13.53. How can I expand a range of nodes specified by first and last path?

TreeView doesn't contain an expand_range() method similar to TreeSelection's select_range(). Often it is necessary to expand newly created cells prior to selecting them (by default new children are collapsed and select_range selects only expanded rows). Using the same arguments for both actions is desirable. This functionality may be implemented using the following code:

	def expand_range(self, tree_view, first_path, last_path):
		first_list = list(first_path)
		last_list = list(last_path)
		for (common_level, first_item) in enumerate(first_list):
			if first_item != last_list[common_level]:
				common_level = common_level - 1
				break
		# Handle expansion of a single row with its children.
		if common_level == len(first_list) - 1:
			tree_view.expand_row(first_path, True)
			return
		first_index = first_list[common_level + 1]
		last_index = last_list[common_level + 1]
		# Expand everything on the common level between given paths.
		for index in range(first_index, last_index + 1):
			path = first_list[:common_level]
			path.append(index)
			self.tree_view.expand_row(tuple(path), True)
As the expand_row() method is able to expand recursively, all we have to do is to descend to a common level and iterate over paths between first and last. For example if first = (0, 1) and last = (0, 2, 0) the common paths would be (0, something) where something is 1 and 2.

13.54. How can I cut/copy/paste TreeStore rows using clipboard?

The clipboard accepts text or image data, not an arbitrary object. The trick is to create a text representation of selected tree rows and copy it into clipboard. When pasting, create tree rows based on the text obtained from clipboard. Ideal format for this is XML, as a side effect the same serialization/deserialization method can be used when saving/loading the tree contents to/from a file.

The XML tree should contain at least a root XML tag with format description and cell XML tags for each tree row. If the tree model contains columns with short values like checkboxes, put these values directly ito cell XML tags as parameters. If your model contains columns with potentially long text, you can add a special data XML tag as a child of every cell XML tag. Example of format for two-column model with checkbox and text with a parent and child row - (0,) and (0,0):

  <tree version="1.0" creator="my_app">
    <cell toggle="False">
      <data>Text 1</data>
      <cell toggle="True">
        <data>Text 2</data>
      </cell>
    </cell>
  </tree>
Note that putting text directly between cells without a special data XML tag (we use 'data' for this) would prohibit pretty-printing and the resulting XML would be hard to read. This is because prettyprinting adds whitespaces but adding whitespaces into the text would alter the text itself.

Example of creating XML tree (replace the constants with data from TreeStore):

  from lxml import etree

  xml_root = etree.Element('root', { 'version' : '1.0', 'creator' : 'my_app' })
  xml_cell = etree.Element('cell', { 'toggle' : 'False' })
  xml_data = etree.Element('data')
  xml_data.text = 'Text 1'
  xml_cell.append(xml_data)
  xml_root.append(xml_cell)
  xml_text = etree.tostring(xml_root, pretty_print=True)
Other useful methods for XML manipulation:
  try:
    xml_root = etree.fromstring(xml_text)
  except etree.XMLSyntaxError:
    ...
  xml_cell.iterchildren(tag='data')
  xml_cell.get('toggle')
  try:
    xml_root = etree.parse(filename)
  except etree.XMLSyntaxError:
    ...
Useful methods for clipboard manipulation:
  clipboard = gtk.Clipboard(gtk.gdk.display_manager_get().get_default_display(), "CLIPBOARD")
  clipboard.set_text(xml_text)
  xml_text = clipboard.wait_for_text()
How to get all paths in TreeStore (useful for save):
  paths = []
  self.tree_store.foreach(lambda model, path, iter, user_data: paths.append(path), None)
See also [www.le-web.org] for details about URI copy/paste in Nautilus.

Note: If you allow multiple selections in TreeView the user may select a non-contiguous range of rows. Then you have to decide how to paste such weird selections. It is more convenient to describe the selections by paths than via iterators.

13.55. How do I enable editing of CellRendererProgress?

CellRendererProgress has no 'editable' property and doesn't emit 'edited' signal - this renderer can only display the value, not edit. You have two options how to edit the value displayed:

1) easy: share a model column between CellRendererProgress and CellRendererSpin

this method has a disadvantage of having two columns with the same value displayed

2) harder: subclass CellRendererProgress and add the editing capability to it

see FAQ 13.45 for hints on subclassing a CellRenderer and FAQ 6.1 for subclassing a GObject

  class CellRendererProgressEditable(gtk.CellRendererProgress):

	__gproperties__ = { 'editable': ( gobject.TYPE_BOOLEAN, 'editable', 'is editable?', False, gobject.PARAM_READWRITE ) }

	__gsignals__ = { 'edited': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_PYOBJECT, gobject.TYPE_FLOAT )),
			 'editing-done': (gobject.SIGNAL_RUN_FIRST, gobject.TYPE_NONE, (gobject.TYPE_STRING,)) }

	__gtype_name__ = 'CellRendererProgressEditable'

	def __init__(self):
		gtk.CellRendererProgress.__init__(self)
		self.set_property('mode', gtk.CELL_RENDERER_MODE_EDITABLE)

	def do_get_property(self, pspec):
		return getattr(self, pspec.name)

	def do_set_property(self, pspec, value):
		setattr(self, pspec.name, value)

	def do_start_editing(self, event, treeview, path, background_area, cell_area, flags):
		if not self.get_property('editable'):
			return
		adjustment = gtk.Adjustment(value=self.get_property('value'), lower=0, upper=100, step_incr=1, page_incr=10)
		spin = gtk.SpinButton(adjustment)
		spin.connect('editing-done', self.editing_done, path)
		spin.connect('key-press-event', self.key_press_event, path)
		spin.show()
		spin.grab_focus()
		return spin

	def editing_done(self, spin, path):
		self.emit('edited', path, spin.get_property('value'))

	def key_press_event(self, spin, event, path):
		if event.type == gtk.gdk.KEY_PRESS:
			if gtk.gdk.keyval_name(event.keyval) == 'Up':
				spin.spin(gtk.SPIN_STEP_FORWARD)
				return True
			if gtk.gdk.keyval_name(event.keyval) == 'Down':
				spin.spin(gtk.SPIN_STEP_BACKWARD)
				return True
'editable' property and 'edited' signal work in the same fashion as for CellRendererText and others

'start-editing' signal is internal and occurs after user doubleclicks on a cell (or presses space/enter). We have to create and display a gtk.Editable and wait for user to edit the value. By default the TreeView would 'eat' signals for Up and Down arrows - we have to catch them and handle on our own (and notify the parent we have already handled the signals - see return True).

'editing-done' signal is internal and occurs after user finishes editing in our SpinButton. All we have to do is emit the standard 'edited' signal and let the end user to handle it.

13.56. How do I create my own CellRendererDate?

There is no CellRenderer for entering a date via gtk.Calendar, we have to create own custom widget based on gtk.CellRendererText. Usually the CellRenderer creates onw gtk.Editable and returns it at the end of do_start_editing() method. This editable is then drawn inside the cell being edited and has to fit within it - which is not possible for a calendar (because of its size).

We have to bypass all this "editable machinery", create own popup window (based on decoration-less, non-modal gtk.Dialog), properly position it (very tricky) below the cell being edited and handle the date entering. Being non-modal allows us to handle the focus-out event as cancel editing (user just clicks away from the calendar).

  class CellRendererDate(gtk.CellRendererText):

    __gtype_name__ = 'CellRendererDate'

    def __init__(self):
      gtk.CellRendererText.__init__(self)
      self.date_format = '%d/%m/%Y'
      self.calendar_window = None
      self.calendar = None

    def _create_calendar(self, treeview):
      self.calendar_window = gtk.Dialog(parent=treeview.get_toplevel())
      self.calendar_window.action_area.hide()
      self.calendar_window.set_decorated(False)
      self.calendar_window.set_property('skip-taskbar-hint', True)

      self.calendar = gtk.Calendar()
      self.calendar.display_options(gtk.CALENDAR_SHOW_DAY_NAMES | gtk.CALENDAR_SHOW_HEADING)
      self.calendar.connect('day-selected-double-click', self._day_selected, None)
      self.calendar.connect('key-press-event', self._day_selected)
      self.calendar.connect('focus-out-event', self._selection_cancelled)
      self.calendar_window.set_transient_for(None) # cancel the modality of dialog
      self.calendar_window.vbox.pack_start(self.calendar)

      # necessary for getting the (width, height) of calendar_window
      self.calendar.show()
      self.calendar_window.realize()

    def do_start_editing(self, event, treeview, path, background_area, cell_area, flags):
      if not self.get_property('editable'):
        return

      if not self.calendar_window:
        self._create_calendar(treeview)

      # select cell's previously stored date if any exists - or today
      if self.get_property('text'):
        date = datetime.datetime.strptime(self.get_property('text'), self.date_format)
      else:
        date = datetime.datetime.today()
        self.calendar.freeze() # prevent flicker
        (year, month, day) = (date.year, date.month - 1, date.day) # datetime's month starts from one
        self.calendar.select_month(int(month), int(year))
        self.calendar.select_day(int(day))
        self.calendar.thaw()

        # position the popup below the edited cell (and try hard to keep the popup within the toplevel window)
        (tree_x, tree_y) = treeview.get_bin_window().get_origin()
        (tree_w, tree_h) = treeview.window.get_geometry()[2:4]
        (calendar_w, calendar_h) = self.calendar_window.window.get_geometry()[2:4]
        x = tree_x + min(cell_area.x, tree_w - calendar_w + treeview.get_visible_rect().x)
        y = tree_y + min(cell_area.y, tree_h - calendar_h + treeview.get_visible_rect().y)
        self.calendar_window.move(x, y)

        response = self.calendar_window.run()
        if response == gtk.RESPONSE_OK:
          (year, month, day) = self.calendar.get_date()
          date = datetime.date(year, month + 1, day).strftime (self.date_format) # gtk.Calendar's month starts from zero
          self.emit('edited', path, date)
          self.calendar_window.hide()
        return None # don't return any editable, our gtk.Dialog did the work already

    def _day_selected(self, calendar, event):
      # event == None for day selected via doubleclick
      if not event or event.type == gtk.gdk.KEY_PRESS and gtk.gdk.keyval_name(event.keyval) == 'Return':
        self.calendar_window.response(gtk.RESPONSE_OK)
          return True

    def _selection_cancelled(self, calendar, event):
      self.calendar_window.response(gtk.RESPONSE_CANCEL)
      return True
The date format could be further tweaked, especially for proper i11n.

13.57. How do I create my own CellRendererMultiline?

This is very similar to renderer for date shown in previous FAQ entry. Interesting tricks specific for multiline texts are:

Disabling the vertical growth of treeview's cells when they contain multiline text (ellipsize truncates only horizontally):

  self.set_fixed_height_from_font(1) # show exactly one line
Use gtk.TextView instead of gtk.Calendar + put it into a scrolled window (scroll bars appear only when needed - this is not enabled by default):

  self.textedit = gtk.TextView()
  ...
  scrolled_window = gtk.ScrolledWindow()
  scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
  self.textedit_window.vbox.pack_start(scrolled_window)
  scrolled_window.add(self.textedit)
  scrolled_window.show()
Populate the textedit with cell's old contents and resize it to 1/4 of treeview:

  def do_start_editing(...):
  ...
  self.textedit.get_buffer().set_property('text', self.get_property('text'))
  ...
  (textedit_w, textedit_h) = (tree_w / 4, tree_h / 4)
  self.textedit_window.resize(textedit_w, textedit_h)
If the user presses Enter, the textedit just starts a new line. Hook to Ctrl+Enter for editing done:

  if event.state & (gtk.gdk.SHIFT_MASK | gtk.gdk.CONTROL_MASK) and gtk.gdk.keyval_name(event.keyval) == 'Return':
    self.textedit_window.response(gtk.RESPONSE_OK)
      return True
The following is a working example of multi-line custom cellrenderer.

 import gtk
 import pygtk
 pygtk.require('2.0')
 import gobject

 class CellRendererML(gtk.CellRendererText):

 	def __init__(self):
 		gtk.CellRendererText.__init__(self)

 	def do_get_size(self, widget, cell_area):
 		# We start from the standard dimension...
 		size_tuple = gtk.CellRendererText.do_get_size(self, widget, cell_area)
 		return(size_tuple)

 	def do_start_editing(self, event, treeview, path, background_area, cell_area, flags):

 		if not self.get_property('editable'):
 			return

 		self.selection = treeview.get_selection()
 		self.treestore, self.treeiter = self.selection.get_selected()

 		self.textedit_window = gtk.Dialog(parent=treeview.get_toplevel())

 		self.textedit_window.action_area.hide()
 		self.textedit_window.set_decorated(False)
 		self.textedit_window.set_property('skip-taskbar-hint', True)
 		self.textedit_window.set_transient_for(None) # cancel the modality of dialog

 		self.textedit = gtk.TextView()
 		self.textedit.set_editable(True)
 		self.textedit.set_property('visible', True)
 		self.textbuffer = self.textedit.get_buffer()
 		self.textbuffer.set_property('text', self.get_property('text'))

 		#map key-press-event handler
 		self.textedit_window.connect('key-press-event', self._keyhandler)

 		scrolled_window = gtk.ScrolledWindow()
 		scrolled_window.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 		scrolled_window.set_property('visible', True)
 		#self.textedit_window.vbox.pack_start(scrolled_window)

 		scrolled_window.add(self.textedit)
 		self.textedit_window.vbox.add(scrolled_window)
 		self.textedit_window.realize()

 		# position the popup below the edited cell (and try hard to keep the popup within the toplevel window)

 		(tree_x, tree_y) = treeview.get_bin_window().get_origin()
 		(tree_w, tree_h) = treeview.window.get_geometry()[2:4]
 		(t_w, t_h) = self.textedit_window.window.get_geometry()[2:4]
 		x = tree_x + min(cell_area.x, tree_w - t_w + treeview.get_visible_rect().x)
 		y = tree_y + min(cell_area.y, tree_h - t_h + treeview.get_visible_rect().y)
 		self.textedit_window.move(x, y)
 		self.textedit_window.resize(cell_area.width, cell_area.height)

 		#now run dialog, get response by tracking keypresses
 		response = self.textedit_window.run()

 		if response == gtk.RESPONSE_OK:
 			print "OK response received"
 			self.textedit_window.destroy()
 			#update text and so forth....
 			(iter_first, iter_last) = self.textbuffer.get_bounds()
 			text = self.textbuffer.get_text(iter_first, iter_last)
 			#store the text
 			self.treestore[path][2] = text

 			#set focus back on row
 			treeview.set_cursor(path, None, False)

 			#propagate edited signal for other handlers...
 			self.emit('edited', path, text)

 		elif response == gtk.RESPONSE_CANCEL:
 			print "Cancel response received"
 			self.textedit_window.destroy()
 		else:
 			print "response %i received" % response
 			self.textedit_window.destroy()

 	def _keyhandler(self, widget, event):
 		# track keystrokes, look for shift-return or ctrl-return to signal end of cell editing
 		keyname = gtk.gdk.keyval_name(event.keyval)
 		print "Key %s (%d) was pressed" % (keyname, event.keyval)

 		if event.state & (gtk.gdk.SHIFT_MASK | gtk.gdk.CONTROL_MASK) and gtk.gdk.keyval_name(event.keyval) == 'Return':
 			#return 
 			self.textedit_window.response(gtk.RESPONSE_OK)

 gobject.type_register(CellRendererML)

 class TreeViewExample:

 	# close the window and quit
 	def delete_event(self, widget, event, data=None):
 		gtk.main_quit()
 		return False

 	def make_pb(self, tvcolumn, cell, model, iter):
 		stock = model.get_value(iter, 1)
 		pb = self.treeview.render_icon(stock, gtk.ICON_SIZE_MENU, None)
 		cell.set_property('pixbuf', pb)
 		return

 	def __init__(self):
 		# Create a new window
 		self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)

 		self.window.set_title("TreeViewColumn Example")

 		self.window.connect("delete_event", self.delete_event)

 		# create a liststore with one string column to use as the model
 		self.treestore = gtk.TreeStore(str, str, str)

 		# create the TreeView using liststore
 		self.treeview = gtk.TreeView(self.treestore)

 		# create the TreeViewColumns to display the data
 		self.tvcolumn = gtk.TreeViewColumn('Pixbuf and Text')
 		self.tvcolumn1 = gtk.TreeViewColumn('Editable Text')

 		# add a row with text and a stock item 
 		self.treestore.append(None,['Open', gtk.STOCK_OPEN, 'Open a File'])
 		self.treestore.append(None,['New', gtk.STOCK_NEW, 'New File'])
 		self.treestore.append(None,['Print', gtk.STOCK_PRINT, 'Print File'])

 		# add columns to treeview
 		self.treeview.append_column(self.tvcolumn)
 		self.treeview.append_column(self.tvcolumn1)

 		# create CellRenderers to render the data
 		self.cellpb = gtk.CellRendererPixbuf()
 		self.cell = gtk.CellRendererText()
 		#this is our custom cell renderer
 		self.cell1 = CellRendererML()

 		self.cell1.set_property('editable', True)
 		self.cell1.set_fixed_height_from_font(1)

 		# add the cells to the columns - 2 in the first
 		self.tvcolumn.pack_start(self.cellpb, False)
 		self.tvcolumn.pack_start(self.cell, True)
 		self.tvcolumn1.pack_start(self.cell1, True)

 		# set the cell attributes to the appropriate liststore column
 		# GTK+ 2.0 doesn't support the "stock_id" property
 		if gtk.gtk_version[1] < 2:
 			self.tvcolumn.set_cell_data_func(self.cellpb, self.make_pb)
 		else:
 			self.tvcolumn.set_attributes(self.cellpb, stock_id=1)
 		self.tvcolumn.set_attributes(self.cell, text=0)
 		self.tvcolumn1.set_attributes(self.cell1, text=2)

 		# Allow sorting on the column
 		self.tvcolumn.set_sort_column_id(0)

 		self.window.add(self.treeview)

 		self.window.show_all()

 def main():
 	gtk.main()

 if __name__ == "__main__":
 	tvexample = TreeViewExample()
 	main()

13.58. How do I hide the row expanders (or How do I share a model between tree and table view)?

As there are two types of model - TreeStore and ListStore and only one type of view - TreeView, it is not obvious how to share a model between two views.

The trick is to use one model and one view but to control the visibility of row expanders. All we have to do is to add a first dummy column (with no model column equivalent), keep it hidden all the time and switch the 'expander-column' property between this and next column (having 'expander-column' set to column that is not visible effectively hides the expanders).

Please note the user has no way how to expand/collapse the rows when the expanders are hidden - it is useful to expand all rows prior to hiding the expanders.

hide the dummy column:

  treeview.get_column(0).set_property('visible', False)
hide the expanders:
  treeview.expand_all()
  treeview.set_property('expander-column', self.treeview.get_column(0))
show the expanders:
  treeview.set_property('expander-column', self.treeview.get_column(1))
See also en.wikibooks.org/wiki/GTK+_By_Example/Tree_View/Miscellaneous

13.59. Changing full background color of Treeview

Instead of using modify_bg use modify_base:

treeview.modify_base(STATE, color)

to modify only a row back color you have to:

cell.set_property('cell-background', color)

13.60. How do I end editing immediately after an item is selected in a CellRendererCombo?

Ending editing of a gtk.CellRendererCombo immediately after an item is selected is a two stage process.

In the first stage, you must capture the combo itself, since it is not accessible later. To capture the combo, connect to the `editing-started` gtk.CellRenderer signal. You may define the connection in Glade or create it manually in code.

In the second stage, emit a `focus-out-event` in a `changed` signal handler for gtk.CellRendererCombo.

Here is sample code to demonstrate:

  import pygtk
  pygtk.require('2.0')
  import gtk
  import gobject

  class AutoEndingComboDemo(object):
    def __init__():
      self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
      self.window.set_size_request(500, 500)
      self.window.connect('destroy', lambda w: gtk.main_quit())
      self.comboModel = gtk.Liststore(gobject.TYPE_STRING)
      self.comboModel.append(['Item 1'])
      self.comboModel.append(['Item 2'])
      self.comboModel.append(['Item 3'])
      self.treeModel = gtk.Liststore(gobject.TYPE_STRING)
      self.treeModel.append()

      crc = gtk.CellRendererCombo()
      crc.set_property('model', self.comboModel)
      crc.set_property('text-column', 0)
      crc.set_property('editable', True)
      crc.set_property('has_entry', False)
      crc.connect('changed', self.comboChanged)
      crc.connect('editing-started', self.editingStarted)
      crc.connect('edited', self.edited, self.treeModel, 0)

      cl = gtk.TreeViewColumn('Select One', crc, text=0)

      self.treeView = gtk.TreeView(self.treeModel)
      treeView.append_column(cl)

      self.window.add(self.treeView)
      self.window.show()

      self.comboEditable = None

    def comboChanged(self, cell, path, newiter):
      e = gtk.gdk.Event(gtk.gdk.FOCUS_CHANGE)
      e.window = self.treeView.window
      e.send_event = True
      e.in_ = False
      self.comboEditable.emit('focus-out-event', e)

    def editingStarted(self, cell, editable, path):
      self.comboEditable = editable

    def edited(self, cell, path, newtext, model=None, columnNumber=0):
      model[path][columnNumber] = newtext

  if __name__ == "__main__":
    app = AutoEndingComboDemo()
    gtk.main()


14. Editables: GtkEntry, GtkCombo, GtkText, GtkSpinButton, GtkTextView

14.1. How do I make a GtkEntry exactly 5 characters long?

here are three methods; the third method is prone to breakage if the font size is changed.

a) just call

  entry.set_width_chars(5)
or:

b) On older gtk+ only, according to Jamesh; first get a reference to the font used by the entry:

    font = entry.get_style().font
then you can measure a string:

 width = font.width('55555')
then set the width:

 entry.set_usize(width, -1)
although that doesn't take padding or anything into account, and if you pack the widget telling it to expand or fill, it will grow larger than that width (set_usize sets a minimum size).

Note that this must be done at runtime if the size is to adapt to a font selected through themes.

c) On older gtk+ only, measure and set a fixed size in pixels using glade or set_usize. argh.

14.2. What is a GtkTextIter, and how do I get one for position X (and other positions)?

James Henstridge and Pier Carteri help us out:

Text iters represent a position in the text buffer. You can create them with a GtkTextBuffer object as follows.

To get an iter for the current line:

  line_iter = text_buffer.get_iter_at_line_offset(linenum, charoffset)
For a specified offset:

  offset_iter = text_buffer.get_iter_at_offset(charoffset)
To get iters at the buffer bounds:

  start_iter = text_buffer.get_start_iter()
  end_iter = text_buffer.get_end_iter()
or in a more compact form:

  start_iter, end_iter = text_buffer.get_bounds()
To get an iter at the current cursor position, do:

  iter_here = text_buffer.get_iter_at_mark(text_buffer.get_insert())
There are a few other text buffer methods for creating iters, but those should be enough most of the time. You can then use iter methods to advance by chars, words or lines, etc:

  iter.backward_char()
  iter.forward_char()

  iter.forward_word_end()
  iter.backward_word_start()

  iter.forward_line()
  iter.backward_line()
See the complete GtkTextIter reference at [www.pygtk.org]

14.3. How do I change the cursor for a GtkEntry?

The GtkEntry is composed of two GdkWindows, one for the black border around it, and one for the white editable area. To change the cursor for both:

 watch = gtk.gdk.Cursor(gtk.gdk.WATCH)
 gdkwin = entry.window
 gdkwin.set_cursor(watch)
 # the gdkwin has a child window, which is for the editable area 
 gdkwin.get_children()[0].set_cursor(watch)
See faq 5.6 for more on cursor changing.

14.4. Why does GtkText's insert_text generate critical messages complaining "assertion `index <= TEXT_LENGTH (text)' failed."?

Due to a PyGTK bug in all versions up to 0.6.11, insert_text works with GtkText, but generates GTK critical warnings, even though it is defined for all GtkEditables.

The workaround is to use insert_defaults(), which works and doesn't generate warnings. It has one nasty side-effect: see faq 14.7

For the original message explaining this, see [www.mail-archive.com]

insert_text has been fixed (in the same patch that added the position argument to GtkEditable.insert_text()) in version 0.6.10 and should be used if that version is available.

14.5. I want to change the text being typed into an entry or textbox, but the original text is also inserted!

A common need is to handle text being inserted into an entry or textbox, but change that text on-the-fly. As an example, Pier Carteri wrote the mailing list asking how he could expand tabs typed into spaces; however, the original tab was still being inserted.

The general solution to this is to use two functions, one as a "proxy" callback that calls emit_stop_by_name() and idle_add()s the real function. It could work something like this:

 def insert_cb(widget, text, length, *args):
    # if you don't do this, garbage comes in with text
    text = text[:length]
    pos = widget.get_position()
    # stop default emission
    widget.emit_stop_by_name("insert_text")
    gtk.idle_add(insert, widget, text, pos)

 def insert(widget, text, pos):
    # the next three lines set up the text. this is done because we
    # can't use insert_text(): it always inserts at position zero.
    orig_text = widget.get_text()
    text = string.replace(text, " ", "<SPACE>")
    new_text = orig_text[:pos] + text + orig_text[pos:]
    # avoid recursive calls triggered by set_text
    widget.signal_handler_block(insert_sig)
    # replace the text with some new text
    widget.set_text(new_text)
    widget.signal_handler_unblock(insert_sig)
    # set the correct position in the widget
    widget.set_position(pos + len(text))

 entry = gtk.Entry()
 insert_sig = entry.connect("insert_text", insert_cb)
Some notes about this approach:

14.6. Why does the second parameter to insert_text (the `text' parameter) contain garbage?

If you connect to the insert_text signal of an editable, you will notice very quickly that the second parameter contains garbage. The function signature has the following format:

 def on_insert_text(widget, text, len, *args):
   pass
The text parameter will contain garbage, which is no good for us. So you should split the text accordingly using something like:

 text = text[:len]
This is something of a bug in GTK+ that bleeds into PyGTK, says James. "This is not a bug I can correct for (easily). Gtk claims that the text argument to the signal is a G_TYPE_STRING argument, which is accepted to mean "standard NUL terminated C string" everywhere else in gtk+. This is the one handler where they are using G_TYPE_STRING with a non NUL terminated string, so things go weird." (QED)

14.7. Why isn't GtkText.insert_defaults() generating the signal insert_text

It seems to be a GTK+ bug. You can get away with attaching a callback to the changed signal and then calling changed() manually after insert_defaults() is called:

  text.connect("insert_text", self._insert_text)
  text.connect("changed", self._insert_text)
  text.insert_defaults("GTK+ is broken") # generates no signals :-(
  self.changed()                         # triggers changed()

14.8. How do I get the currently selected text in a GtkCombo?

The GtkCombo inherits from a GtkHBox, and contains both a GtkEntry and a GtkButton, but it offers a convenience attribute that gets the entry back for you. Since the current selection is held in the GtkCombo's GtkEntry, use something like:

 text = combo.child.get_text()

14.9. How do I programatically set the max value for a GtkSpinButton?

Steve McClure offered the following answer to Greg Ward:

 # Sets the upper limit from 99...
 adj = GtkAdjustment(1, 1, 99, 1, 1, 1)
 sb = GtkSpinButton(adj, 1, 0)
 # ... to 5
 my_adj = sb.get_adjustment()
 my_adj.upper = 5
 my_adj.set_all(my_adj.value, my_adj.lower, my_adj.upper,
                my_adj.step_increment, my_adj.page_increment, 
                my_adj.page_size)
 # isn't that the darndest API I've seen
set_all() actually applies the changes done to the adjustment's member attributes.

14.10. How do I scroll a TextView to display the text being inserted?

When inserting text using insert_at_custor(), it may happen that the text inserted surpasses the textview's current viewport, and requires scrolling.

Gustavo Carneiro and Mikoyan wrote in to suggest using the textbuffer's scroll_to_mark() method, which scrolls to a certain point in the buffer. You can use the get_insert() method to return the current insert position right after inserting if you want to make sure you scroll to the end of the text.

  end_iter = text_buffer.get_end_iter()
  text_buffer.insert(end_iter, text)
  text_view.scroll_to_mark(text_buffer.get_insert(), 0)
There is also a simplier method to make sure the text view's cursor is visible:

  text_view.scroll_mark_onscreen(text_buffer.get_insert())

14.11. How do I insert colored text into a TextView?

Someone on #pygtk (probably gjc) was nice enough to send me this code snippet when I was trying to make a color coded log window. Keep in mind, that naming a TextTag "blue" is considered bad form - you want to name it after what it represents.

 tag_table = text_buffer.get_tag_table()

 warn_tag = gtk.TextTag("warning")
 warn_tag.set_property("foreground", "blue")
 tag_table.add(warn_tag)

 sob, eob = text_buffer.get_bounds()
 text_buffer.insert_with_tags_by_name(eob, "This is a warning", "warning")

14.12. How can I make GtkTextView to always show the last line

Dan Christian writes:

The way that I did it for a scrolling text window is to set a mark at the end of the buffer like this:

 mark = text_buffer.create_mark("end", text_buffer.get_end_iter(), False)
Then (after every text addition), I tell it to scroll to the end, like this:

 text_view.scroll_to_mark(mark, 0.05, True, 0.0, 1.0)
The mark will "do the right thing" about where it is in the buffer and how the idle task works.

14.13. How do I add items into GtkCombo

This code add one or many items to GtkCombo object named combo

Just add one item like this

 listitem = gtk.ListItem("String 1")
 combo.list.append_items([Listitem])
 listitem.show()
Or if you like you can add two:

 listitem_a = gtk.ListItem("String 2")
 listitem_b = gtk.ListItem("String 3")
 combo.list.append_items([listitem_a, listitem_b])
 listitem_a.show()
 listitem_b.show()

14.14. How can get back the strings that I set using Combo.set_popdown_strings()

I don't think it's actually supposed to be done; if you look at the GTK+ C code for set_popdown_strings, it creates list items that contain the labels stuffed with the strings in question. You could iterate through combo.list.children() and then grab the label, which should be the first element of the list item itself (.children()[0]). This is an O(n) operation, however.

However, you have a much simpler alternative: just store the strings yourself, locally.

    def set_combo_strings(self, s):
        self.strings = s
        self.combo.set_popdown_strings(s)
You have self.strings conveniently stored in a python list, and you can get them back whenever you like, at O(1).

14.15. How do I change the mouse cursor on a TextView (or how do I get the "right" GdkWindow from a TextView)?

As described in FAQ 5.6, and similarly to the GtkEntry discussed in FAQ 14.3, the TextView widget is made up of several underlying GdkWindows. The actual text window already has a cursor set on it (the i-beam cursor), but it's not the TextView's main window, which is why using a plain TextView.get_window() call won't work. You need to get the child window:

 child_win = v.get_window(gtk.TEXT_WINDOW_TEXT)
 child_win.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
(Tim Evans)

14.16. Is there a signal sent when a user hits enter in an editable?

Yes. Connect to signal "activate".

14.17. What X clipboard do TextView's context menu items use?

They use the default gdk.SELECTION_CLIPBOARD; see the gtk.Clipboard reference at [www.pygtk.org] for details.

14.18. How do I get the clipboard functions to work properly?

First, get an instance of the default display from the global gtk.gdk.DisplayManager:

 display = gtk.gdk.display_manager_get().get_default_display()
Then get a reference to a gtk.Clipboard object, specifying the CLIPBOARD clipboard (and not PRIMARY):

 clipboard = gtk.Clipboard(display, "CLIPBOARD")
Now your cut/copy/paste callbacks can be written as follows:

 def on_cut_activate(self, obj):
 	textbuffer.cut_clipboard(clipboard, textview.get_editable())

 def on_copy_activate(self, obj):
 	textbuffer.copy_clipboard(clipboard)

 def on_paste_activate(self, obj):
 	textbuffer.paste_clipboard(clipboard, None, textview.get_editable())
Where "textview" is a reference to your gtk.TextView widget and "textbuffer" is a reference to your gtk.TextBuffer.

Note: the functions used in the callbacks are available as of PyGTK 2.4

14.19. I'm getting a Gtk-CRITICAL messsage: assertion `g_utf8_validate (text, len, NULL)' failed [using insert_*]

The message is only saying that your text string is not well encoded in utf-8 -- this happens, for instance, when using a "regular" python string instead of a unicode one.

Try using unicode objects instead of strings if you're getting these problems -- python will automatically convert to utf-8 for you.

(Gustavo Carneiro)

14.20. How do I write clipboard callbacks for multiple widgets?

First write a method to get the currently focused widget from a container::

 def _get_focus_widget(self, parent):
       """Gets the widget that is a child of parent with the focus."""
       focus = parent.get_focus_child()
       if focus is None or (focus.flags() & gtk.HAS_FOCUS):
           return focus
       else:
           return self._get_focus_widget(focus)
Then you can write your copy callback to copy from the currently focused widget (assumes that self.vbox is the top-level container of the window)::

 def on_copy(self, widget, data=None):
       """Copies currently selected text."""
       focus = self._get_focus_widget(self.vbox)
       if focus is not None and hasattr(focus, "copy_clipboard"):
           focus.copy_clipboard()
The cut callback does the same thing, but tells the focused widget to cut::

 def on_cut(self, widget, data=None):
       """Cuts currently selected text."""
       focus = self._get_focus_widget(self.vbox)
       if focus is not None and hasattr(focus, "cut_clipboard"):
           focus.cut_clipboard()
Likewise, the paste callback does the same thing as the last two, but tells the focused widget to paste::

 def on_paste(self, widget, data=None):
       """Pastes text to currently focused widget."""
       focus = self._get_focus_widget(self.vbox)
       if focus is not None and hasattr(focus, "paste_clipboard"):
           focus.paste_clipboard()

14.21. How do I right-align text in an Entry?

Just set the "xalign" property:

  entry.set_property('xalign', 1)
Note that this works normally in LTR locales; an entry with the number 23.22 would show up as something like (using your ascii-art imagination):

  [        23.22 ]

14.22. How do I create a mask or validator for a GtkEntry?

There is an opensource subclass of gtk.Entry, ValidatedEntry, available at: [www.astro.umass.edu] otherwise...

In short, there is no feature currently implemented that makes this easy. You can hack your own mask support by catching the insert and delete_text signals and doing the appropriate manipulation, but it is far from trivial to write; FAQ 14.5 includes a basic recipe. There is a bug filed at [bugzilla.gnome.org] that discusses implementation of something like this (validation and masks) at the C level.

See the thread at [www.daa.com.au] for more details.

14.23. How do I send the output of an external process to a gtk.TextView without freezing the GUI?

The problem here is to avoid waiting for the external process to finish. That can easily be done with threads but it should be possible to get it working using pipes in non-blocking IO mode and monitoring output using the gobject.io_add_watch() function. The problem with this last approach is that only sockets, not pipes, can be used with the select interface in Win32... so that solution seems not too portable for that reason.

This example shows how to do it the "threaded way", as it seems quite straightforward and portable through platforms without additional tweaking [1].

 #!/usr/bin/env python
 """Show a shell command's output in a gtk.TextView without freezing the UI"""

 import os, threading, locale

 import gobject
 import gtk

 gobject.threads_init()
 gtk.gdk.threads_init()

 encoding = locale.getpreferredencoding()
 utf8conv = lambda x : unicode(x, encoding).encode('utf8')

 def on_button_clicked(button, view, buffer, command):
     thr = threading.Thread(target= read_output, args=(view, buffer, command))
     thr.start()

 def read_output(view, buffer, command):
     stdin, stdouterr = os.popen4(command)
     while 1:
         line = stdouterr.readline()
         if not line:
             break
         gtk.gdk.threads_enter()
         iter = buffer.get_end_iter()
         buffer.place_cursor(iter)
         buffer.insert(iter, utf8conv(line))
         view.scroll_to_mark(buffer.get_insert(), 0.1)
         gtk.gdk.threads_leave()

 sw = gtk.ScrolledWindow()
 sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
 textview = gtk.TextView()
 textbuffer = textview.get_buffer()
 sw.add(textview)
 win = gtk.Window()
 win.resize(300,500)
 win.connect('delete-event', gtk.main_quit)
 button = gtk.Button(u"Press me!")
 command = 'ls -R %s' % (os.getcwd(),)
 button.connect("clicked", on_button_clicked, textview, textbuffer, command)
 vbox = gtk.VBox()
 vbox.pack_start(button, False)
 vbox.pack_start(sw)
 win.add(vbox)
 win.show_all()

 gtk.main()

Note that this code is dangerous: if the widget is destroyed while the thread is still running, nasty things may happen, from nothing visible to segfault.

[1] Nobody really knows if this works on windows.

Dangerous code is wonderful, but how would you do this safely? Is there locking involved? Where?

When multiple threads are writing to the same text buffer, the program has a tendency to fail an assert and segfault on the buffer.insert line. If you explicitly silence the assert error, the interpreter tends to crash. This probably isn't a result of bad interpreter code, but just really nasty thread handling.

Moral of the story: Don't let multiple threads write to the same text-buffer. Create a new one for every thread.

14.24. How do I add completion support for an entry?

Here is a simple example that demonstrates how to add entry completion to a GtkEntry:

 import gtk

 COL_TEXT = 0

 class CompletedEntry(gtk.Entry):
     def __init__(self):
         gtk.Entry.__init__(self)
         completion = gtk.EntryCompletion()
         completion.set_match_func(self.match_func)
         completion.connect("match-selected",
                             self.on_completion_match)
         completion.set_model(gtk.ListStore(str))
         completion.set_text_column(COL_TEXT)
         self.set_completion(completion)

     def match_func(self, completion, key, iter):
         model = completion.get_model()
         return model[iter][COL_TEXT].startswith(self.get_text())

     def on_completion_match(self, completion, model, iter):
         self.set_text(model[iter][COL_TEXT])
         self.set_position(-1)

     def add_words(self, words):
         model = self.get_completion().get_model()
         for word in words:
             model.append([word])

 if __name__ == "__main__":
     win = gtk.Window()
     win.connect('delete-event', gtk.main_quit)

     entry = CompletedEntry()
     entry.add_words(['abc', 'def', 'ghi', 'jkl', 'mno',
                      'pqr', 'stu', 'vwx', 'yz'])
     win.add(entry)
     win.show_all()

     gtk.main()

14.25. How can I place a background image on a TextView widget?

Here's some sample code:

 tv = gtk.TextView()
 tv.show()
 tv_win = tv.get_window(gtk.TEXT_WINDOW_TEXT)
 tv_win.set_back_pixmap(yourPixmap, gtk.FALSE)
Note the placement of tv.show(). It appears that the tv.show() needs to precede getting the gtk.gdk window.

14.26. The text in the TextView is not aligned! Any ideas?

You need to use a monospace font

You will have to use TextTags which is not as easy as set_text() but not as very hard either. Then you do something like:

   tag = gtk.TextBuffer.create_tag('aligned')
   tag.set_property("font", "Courier")
   tag.set_property("foreground", "red")
   tag.set_property("size-points", 12)
   tag.set_property("weight", 400)
then you add the text by:

TextBuffer.insert_with_tags(your_text, 'aligned')

14.27. How do I prevent unselected gtk.Entry from being highlighted after losing focus?

If a window contains multiple gtk.Entry() objects, pressing Tab from an entry containing text to advance to one that is empty (null) results in the previous entry remaining highlighted in grey.

To solve this you can connect to the focus-out-event and deselect the region:

 def focus_out_cb(entry, event):
   entry.select_region(0, 0)
   return False

 entry = gtk.Entry()
 entry.connect('focus-out-event', focus_out_cb)
You can also workaround this by using RC files, Add this RC string:

  gtk.rc_parse_string("""
  style 'entry' { text[ACTIVE] = 'black' 
                  base[ACTIVE] = 'white' } 
  class 'GtkEntry' style 'entry'
  """)
But that's a nasty workaround as it only hides the selection without removing it. So you should really use the focus-out-event method.

14.28. How do I make the Enter key behave as a Tab key in a GtkEntry?

To connect to the Enter key, you can use the activate signal. To make it behave as a Tab key, you need to send the move-focus signal to the containing window, with the proper direction.

For this to work you need to have a reference to the containing window, you can do this by having an attribute in your class, or by sending the window as the user parameter to the signal. Small example:

 import gtk

 def on_entry_activate(widget, window, *args):
     window.do_move_focus(window, gtk.DIR_TAB_FORWARD)

 def main():
     window = gtk.Window()
     window.set_position(gtk.WIN_POS_CENTER)
     window.connect('delete-event', gtk.main_quit)

     vbox = gtk.VBox()
     for i in range(5):
         entry = gtk.Entry()
         vbox.pack_end(entry)
         entry.connect("activate", on_entry_activate, window)

     window.add(vbox)
     window.show_all()
     gtk.main()

 main()


16. GtkOptionMenu, GtkComboBox, GtkComboBoxEntry

16.1. Why doesn't the GtkOptionMenu work like a real listbox?

I personally think the GtkOptionMenu was designed by the devil, and it's API is a stamina test to all good men and women out there.

GtkOptionMenu will be deprecated in GTK+ 2.4 in favor of the new GtkComboBox.

16.2. Let's say I accept it as it is. How do I implement one using pygtk?

David Pinson has sent in an example to keep us all sane:

 def on_optionmenu_activate(widget, data):
     print data                      # print the data for the 
                                     # current selection
 options = ["cat", "dog", "mouse"]   # our options
 menu = gtk.Menu()                   # create a menu
 for str in options:                 # fill our menu with the options
    menu_item = gtk.MenuItem(str)
    menu_item.connect("activate",    # attach "str" to widget
                      on_optionmenu_activate, str) 
    menu_item.show()                 # don't forget this here
    menu.append(menu_item)
 option_menu = gtk.OptionMenu()      # create the optionmenu
 option_menu.set_menu(menu)          # add the menu into the optionmenu
(Note that Kiwi also includes a new API for the OptionMenu that makes it much easier to manipulate: it does signal connection automatically, fills the menu and attaches objects to the items. Check it out)

16.3. If I set the OptionMenu's state to insensitive, and i call set_history() on it, and put it back to sensitive, the previously selected menuitem still looks insensitive!

This is a bug in GTK+ (see [bugzilla.gnome.org] ). Kiwi implements a workaround for it (see [bugs.async.com.br] ) which involves setting the menuitem state to STATE_PRELIGHT and then back to STATE_NORMAL:

  menu = optionmenu.get_menu()
  for item in menu.get_children():
     item.set_state(gtk.STATE_PRELIGHT)
     item.set_state(gtk.STATE_NORMAL)

16.4. How do I find out which is the selected item in a GtkOptionMenu?

The optionmenu is an evil widget, make no mistake. By using it you will see the `magic' it uses to appear to be a simple listbox (make no mistake!) Note these important, err, `aspects' of it:

To get the text of the selected menuitem you can take advantage of this last point and use:

  selected_text = optionmenu.children()[0].get()
If you want to know the index (or, in the OptionMenu's terms, the `history'), you will need to do some further hacks using the optionmenu's menu's get_active() method:

  menu = optionmenu.get_menu()
  items = menu.children()
  selected_item = menu.get_active()
  index = children.index(item)
This index is the same as its `history'. In GTK+2.0 there is a get_history() method that can be used (avoiding the need to code this hack) to make the API a bit more consistent.

(FAQ suggested by Padraig Brady, thanks)

16.5. What signal is emitted when an optionmenu's item is selected?

In PyGTK0, the `activate' signal of the selected GtkMenuItem (yes, the item, not the menu) is triggered. This means that, if you want to be notified of a change in the optionmenu, you will need to do something like:

  def optionmenu_changed(self, item, *args):
    print "it changed: %s was selected", item

  for item in optionmenu.get_menu().children();
    item.connect("activate", optionmenu_changed)
If you want to find out which item was selected, see faq 16.4.

In PyGTK2, the `changed' signal is emitted (along with the item's `activate' signal, I suspect), so you don't need this hack.

16.6. How do I get the label of an OptionMenu's item?

This is a tricky one. Read carefully.

 menu = optionmenu.get_menu()
 for item in menu.get_children():
   chilren = item.get_children()
   if children:
     label = item.get_children()[0]

 label = optionmenu.get_children()[0] # notice - NOT item.get_children()

16.7. How do I get the text from the selected item in GtkComboBox/ComboBoxEntry

For the ComboBox it's a matter of getting the value relative to the active iter:

  def on_combo_box_changed(widget):
     model = widget.get_model()
     iter = widget.get_active_iter()
     print model.get_value(iter, 0)

  combo.connect("changed", on_combo_box_changed)
In the example above, when an item is selected, its text is printed out.

For a ComboBoxEntry, the text can be retrieved using:

  combo_box_entry.child.get_text()
Since the Entry text can be changed by the user the "changed" signal is not sufficient to detect whether the user is done changing the Entry. Also the "changed" callback must be changed to:

  def on_combo_box_entry_changed(widget):
     model = widget.get_model()
     iter = widget.get_active_iter()
     if iter:
         print model.get_value(iter, 0)
because the "changed" signal will be issued if a user edits the text (or pastes it from a clipboard) thereby causing no model row to be active. To detect user edits you have to connect to the child Entry.

16.8. How do I populate a ComboBox or ComboBoxEntry with strings?

For glade users, you can create a simple model for your ComboBox* using

  store = gtk.ListStore(gobject.TYPE_STRING)
  store.append (["testing1"])
  store.append (["testing2"])
  store.append (["testing3"])
  store.append (["testing4"])
For a ComboBoxEntry, it's then a matter of assigning the model to the combo and specifying the text column:

  combo = tree.get_widget("comboboxentry1")
  combo.set_model(store)
  combo.set_text_column(0)
For a ComboBox, pack a renderer into it, specifying the text cell:

  combo = tree.get_widget("combobox1")
  combo.set_model(store)
  cell = gtk.CellRendererText()
  combo.pack_start(cell, True)
  combo.add_attribute(cell, 'text',0)
Thomas Hinkle offers a convenience function that does all this for you:

  def set_model_from_list (cb, items):
    """Setup a ComboBox or ComboBoxEntry based on a list of strings."""           
    model = gtk.ListStore(str)
    for i in items:
        model.append([i])
    cb.set_model(model)
    if type(cb) == gtk.ComboBoxEntry:
        cb.set_text_column(0)
    elif type(cb) == gtk.ComboBox:
        cell = gtk.CellRendererText()
        cb.pack_start(cell, True)
        cb.add_attribute(cell, 'text', 0)
If you are not using glade, it's easier to use the gtk.combo_box_new_text() function with the append_text(), prepend_text(), insert_text() and remove_text() methods as explained here:

[www.pygtk.org] [www.pygtk.org]

(John Finlay, Thomas Hinkle)


17. GtkNoteBook

17.1. How do I get a reference to the page my GtkNotebook just switched to (or, what is the deal with the second argument to GtkNotebook's switch_page handler)?

If you attach a handler to a GtkNotebook's page_switch handler, you may have noticed that the second argument isn't a python instance. James says:

  newpage isn't a GtkObject (if it was, it would have been wrapped in a 
  class already).  For 2.0, it is an opaque struct, so useless to C 
  programmers as well.  Use the pagenum argument and methods of the 
  GtkNotebook to get info about the page.
pagenum refers to the tab number in the notebook. The leftmost tab is 0, the tab next to the leftmost is 1, etc... To get the pagenum, use the following code:

    pagenum = widget.current_page()
So if you have a GtkNotebook and you want to know what page you just switched to, use something like:

  def handler(widget, dummy, pagenum):
    page_widget = widget.get_nth_page(pagenum)
    print "Page number switched to: %s" % pagenum
    print "Widget attached to page %s: %s" % ( pagenum, page_widget )

  notebook.connect("switch_page", handler)
And your notebook will print out the information on each page switch.

17.2. How do I make one toolbar button (e.g. an Add button) call a different function for each notebook tab?

Some applications need a main toolbar (with all of its buttons) to respond according to which tab the user has currently selected. The following code creates a function for an Add button that brings up different windows depending on what the user wants to add:

 def on_add_activate(self, widget, *args):
        #context yourApp.on_add_activate {
        # create a dictionary where the key is the name of the main
        # widget of the notebook tab and the value is the name 
        # of the function that should be called for that specific tab
        addItem = {'CustomerTab':AddCustomerWindow,
                    'InventoryTab':AddInventoryWindow,
                    'VendorTab':AddVendorWindow,
                    'ReportTab':AddReportWindow}
        # for readability purposes, create a variable that points to  
        # the notebook
        notebook = self.MainNotebook
        # tabChild points to the main widget in the current tab
        tabChild = notebook.get_nth_page(notebook.get_current_page())
        # tabName is the name of tabChild
        tabName = tabChild.get_name()
        # now you can use tabName to reference the dictionary and call
        # the appropriate function  
        additem[tabName]()  
        return gtk.TRUE
        #context yourApp.on_add_activate }

17.3. How do I create a popup menu on a notebook tab and figure out which tab a click comes from

Brian Campbell said:

For an easy way to create popup menus, and figuring out which tab a click comes from, put your tab labels into event boxes:

 tab_label_box = gtk.EventBox()
 tab_label = gtk.Label("Some label here")
 tab_label_box.add(tab_label)
 tab_label_box.connect('event', on_tab_click, your_page_widget)
 notebook.append_page(your_page_widget, tab_label_box)

 def on_tab_click(self, widget, event, child):
    if event.type == gtk.gdk.BUTTON_PRESS:
        n = notebook.page_num(child)
        # this will automagically switch to whatever page you click on
        notebook.set_current_page(n)
        if event.button == 3:
             menu = create_a_menu() # I still use the ItemFactory
             menu.popup(None, None, None, event.button, event.time)


18. GtkDrawingArea

18.1. How do I make a gray-scale gradient picture?

Rok Roskar was trying to make a simple gray-scale gradient picture (different shades of gray, starting with white on the left and eventually going to black on the right).

John Finlay provided this code example (hacked for brevity):

 #!/usr/bin/env python

 from gtk import *

 WIDTH=300
 HEIGHT=300

 def pix_init(d_area, width, height):
    d_area.realize()
    win = d_area.get_window()
    pixmap = create_pixmap(win, width, height, -1)
    context = win.new_gc()
    cmap = d_area.get_colormap()
    for x in range(WIDTH):
        color = cmap.alloc(x*200, x*200, x*200)
        context.foreground = color
        for y in range(HEIGHT):
            draw_point(pixmap, context, x, y)
    d_area.connect("expose-event", pix_expose, pixmap)

 def pix_expose(da, event, pixmap):
    x, y, width, height = da.get_allocation()
    da.draw_pixmap(da.get_style().fg_gc[0], pixmap, 0, 0, 0, 0, -1, -1)

 def main():
    top = GtkWindow(WINDOW_TOPLEVEL)
    da = GtkDrawingArea()
    da.size(WIDTH, HEIGHT)
    top.add(da)
    pix_init(da, WIDTH, HEIGHT)
    top.show_all()
    mainloop()

 if __name__ =="__main__":
    main()

18.2. When I place a DrawingArea inside a ScrolledWindow the event object in callbacks has X and Y coordinates off by a few pixels!

Cameron Blackwood noticed that, when placing a GtkDrawingArea inside a GtkScrolledWindow, two peculiarities arise:

a) Connecting to GtkDrawingArea's button_press_event doesn't get called on button presses (when inside a GtkScrolledWindow).

b) If you work around this connecting the signal to the GtkScrolledWindow instead, the X and Y coordinates are off by a few pixels (3 and 4, horizontal and vertically, respectively for the default pointer).

To get this working it's matter of setting the event mask correctly on GtkDrawingArea (faq 3.3) and not attaching to GtkScrolledWindow's button_press_event signal.

 drawingarea.add_events(GDK.BUTTON_PRESS_MASK)
Adding the GtkDrawingArea directly to a GtkWindow also allows the signal connect to work normally.

18.3. How do I set line attributes for draw_line() and draw_lines()?

James says:

All drawing operations in X take a GC (which stands for graphics context), which holds some settings used for doing the drawing. If you are going to change the settings of a GC, it is probably best to create your own (you don't really want to cause all your widgets to draw with double dashed lines).

This can be done with the drawable.new_gc() method. You can then use the gc.set_line_attributes() method to set the line width, line style, cap style and join style:

 gc.set_line_attributes(3, 
                        gdk.LINE_DOUBLE_DASH, 
                        gdk.CAP_BUTT, 
                        gdk.JOIN_MITER)
Now if you draw lines with this GC, they will use these attributes.

18.4. How do I draw dashed or dotted lines in a GtkDrawingArea?

To draw dashes, you can manipulate the line style attribute of the DrawingArea's GC object before drawing the lines. Constant values from GDK.py are:

 LINE_SOLID
 LINE_ON_OFF_DASH
 LINE_DOUBLE_DASH
So you can do something like:

 line_style = GDK.LINE_ON_OFF_DASH
 gc.line_style(line_style)
For dots, John Finlay writes: "You can create your own dash pattern using set_dashes()." I've added information here from the tutorial at [www.moeraki.com] :

"To define a dash pattern (taking notice that the line_style must be set to LINE_ON_OFF_DASH or LINE_DOUBLE_DASH), use the following GC method:

 gc.set_dashes(offset, dash_list)
where offset is the index of the starting dash value in dash_list and dash_list is a list or tuple containing numbers of pixels to be drawn or skipped to form the dashes. The dashes are drawn starting with the number of pixels at the offset position; then the next number of pixels is skipped; and then the next number is drawn; and so on rotating through all the dash_list numbers and starting over when the end is reached. For example, if the dash_list is (2, 4, 8, 16) and the offset is 1, the dashes will be drawn as: draw 4 pixels, skip 8 pixels, draw 16 pixels, skip 2 pixels, draw 4 pixels and so on."

John Hunter shows us how dots can be done in practice:

 self._spacing = 2
 gc.line_style = GDK.LINE_ON_OFF_DASH
 gc.cap_style =  GDK.CAP_BUTT
 gc.join_style = GDK.JOIN_ROUND
 gc.set_dashes(0,[1,self._spacing])
 widget.draw_lines(gc, zip(x, y) )

18.5. What's the essential approach to tracking mouse events in a GtkDrawingArea?

Assuming you want to know where the mouse is, you can either get the coordinate of a mouse click or a mouse motion. The approach is the same:

 drawing_area.connect('motion-notify-event', motion_notify_event_cb)
 drawing_area.connect('button-press-event', button_press_event_cb)  

 drawing_area.set_events(gdk.BUTTON_PRESS_MASK | gdk.POINTER_MOTION_MASK)
You need to define these functions. Eg, for button-press-event:

 def button_press_event_cb(widget, event):
    if event.button == 1:
      ... do something, when the first button is pressed ...
    elif event.button == 3:
      ... do something, when the third buttin is pressed ...
    return True
Notice how event.button carries information about which button was pressed and event.x and event.y give you the x and y coords.

For mouse motion, you simply need to define something like this:

 def motion_notify_event_cb(self, widget, event):
   print "Mouse moved to", event.x, event.y
   return True

18.6. How do I get scrollbars to work with a DrawingArea?

Make the GtkDrawingArea as a child of a GtkViewport which is in turn the child of a GtkScrolledWindow. Whenever you determine the size of what you want to draw in the drawing area, call set_size_request on the GtkDrawingArea widget.

Small example:

 sw = gtk.ScrolledWindow()
 sw.set_policy(gtk.POLICY_ALWAYS, gtk.POLICY_ALWAYS)
 viewport = gtk.Viewport()
 drawing_area = gtk.DrawingArea()
 sw.add(viewport)
 viewport.add(drawing_area)

18.7. How do I make my DrawingArea have the same background used in other widgets?

What we want is draw the background of the DrawingArea with the same background color or pixmap that the one used by our current theme.

We just need to add this line to our redraw function:

  drawing_area.style.apply_default_background(drawing_area.window, True, gtk.STATE_NORMAL, None, 0, 0, w, h)

18.8. What basic pattern should I follow when using a DrawingArea?

The DrawingArea (and drawing in GTK+ in general) is peculiar in the sense that you never draw directly to the widget. Instead, you tell the X server the widget needs to be drawn, then the X server calls you back telling you to draw an area of your widget. This important because if you don't follow this pattern, either what you draw won't be displayed, or it will fail to redraw when the window is covered and subsequently uncovered.

The key to this pattern is the 'expose-event' signal. The handler you connect to it has the following signature:

  def expose_event_cb(widget, event):
     # ...
where event is a GdkEvent structure containing the fields x, y, width, height. These fields define the area that actually needs to be painted, which might be different from the entire widget area if, for example, there is a window on top of the widget, partially obscuring it.

Note that you should call widget.queue_draw() whenever you want to repaint your widget (i.e., when you want to redraw it with something different from what's currently displayed on it).

Here's some example code to start off from:

    class MyWidget(gtk.DrawingArea):
        def __init__(self):
            gtk.DrawingArea.__init__(self)
            self.gc = None  # initialized in realize-event handler
            self.width  = 0 # updated in size-allocate handler
            self.height = 0 # idem
            self.connect('size-allocate', self.on_size_allocate)
            self.connect('expose-event',  self.on_expose_event)
            self.connect('realize',       self.on_realize)

        def on_realize(self, widget):
            self.gc = widget.window.new_gc()
            self.gc.set_line_attributes(3, gtk.gdk.LINE_ON_OFF_DASH,
                                        gtk.gdk.CAP_ROUND, gtk.gdk.JOIN_ROUND)

        def on_size_allocate(self, widget, allocation):
            self.width = allocation.width
            self.height = allocation.height

        def on_expose_event(self, widget, event):
            # This is where the drawing takes place

            widget.window.draw_rectangle(self.gc, False,
                                         1, 1, self.width - 2, self.height - 2)
            widget.window.draw_line(self.gc,
                                    0, 0, self.width - 1, self.height - 1)
            widget.window.draw_line(self.gc,
                                    self.width - 1, 0, 0, self.height - 1)

    win = gtk.Window()
    win.add(MyWidget())
    win.show_all()
    win.connect("destroy", lambda w: gtk.main_quit())
    gtk.main()
(Gustavo Carneiro, John Hunter)

18.9. How to set a tiled background pixmap on gnomecanvas.Canvas? Or, how do set custom background on gnomecanvas.Canvas?

You have to connect_after or override the signal "draw-background", and paint there what you want as canvas background, such as tiled pixmap, grid, etc. Here's an example for setting tiled pixmap:

 import gtk
 from gtk import gdk
 import gnomecanvas as canvas

 def drawbk(acv, dw, x, y, ww, hh, pb):
     gc = dw.new_gc()
     pw = pb.get_width()
     ph = pb.get_height()
     offset_x = x % pw
     offset_y = y % ph
     dw_y = -offset_y
     while dw_y < hh:
         dw_x = -offset_x
         while dw_x < ww:
             dw.draw_pixbuf(gc, pb, 0, 0, dw_x, dw_y)
             dw_x += pw
         dw_y += ph

 # window 
 win = gtk.Window()
 win.resize(100, 200)
 win.connect('destroy', gtk.main_quit)
 win.realize()

 # load a graphic
 pb = gdk.pixbuf_new_from_file('baize.png')
 w, h = pb.get_width(), pb.get_height()

 cv = canvas.Canvas()
 cv.connect_after('draw-background', drawbk, pb)

 win.add(cv)
 win.show_all()
 gtk.main()


19. Other widgets

19.1. Are there any HTML rendering widgets for PyGTK?

Yes, there are several different HTML widgets you can use in Python program.

There is however currently no stable, up to date, flexible and multi-platform widget.

19.2. What about HTML widgets for PyGTK2?

Johan Dahlin wrapped GtkMozEmbed in a python module, which is packaged as part of gnome-python-extras.

gtkhtml2 uses pango for i18n text rendering, etc. [gtkhtml2.codefactory.se] . The HTML rendering still needs work.

Note that Evolution uses libgtkhtml3, which is yet unwrapped.

Gustavo Carneiro did a XHTML-IM (XHTML-1.0 subset) renderer on top of gtk.TextView. It can be found at: [www.gnome.org]

19.3. GnomeIconList's get_icon_data() method doesn't work!

Right now, actually, it could return a SEGV if you are trying to retrieve the data from a position without any data set, as is demostrated below:

 l = gnome.GnomeIconList() 
 l.append('some-icon.png', 'some text')
 l.get_icon_data(0)
JamesH says:

If you didn't set the data associated with the icon, then the results can be unpredictable (ie. get_icon_data() will return whatever you set with set_icon_data()).

Basically, don't get() the data unless you have set() it. This could result of a basic lack of understanding of what the object data attribute is. See question 5.1

19.4. Can I do plots or charts with PyGTK?

If you are using PyGTK2, then the answer is yes:

John Hunter's Matplotlib: [matplotlib.sourceforge.net]

matplotlib is a pure python 2D plotting library with a Matlab® syntax which produces publication quality figures using in a variety of hardcopy formats (PNG, JPG, TIFF, PS) and interactive GUI environments (WX, GTK) across platforms. matplotlib can be used in python scripts, interactively from the python shell (ala matlab or mathematica), in web application servers generating dynamic charts, or embedded in GTK or WX applications.

Jonathan Merritt's PyStripchart [jstripchart.sourceforge.net]

PyStripchart is a set of widgets for displaying sampled information in an interactive "strip chart" form. The website contains code and screenshots.

19.5. How do I get the current color from a gnome ColorPicker?

Gustavo Carneiro suggests using properties:

 color_picker.get_property("red")
 color_picker.get_property("green")
 color_picker.get_property("blue")
The returned values are in in range 0..65535 (16 bits).

19.6. Is there a syntax highlighting widget for PyGTK?

Yes, there is. GtkSourceView has been wrapped as PySourceView, and it's available (as a 3rd-party library) from: [www.bitbuilder.com]

19.7. When displaying a GnomeAbout box, it doesn't display the program name or version.

Set the 'name' and 'version' properties on the GnomeAbout widget before the widget is shown:

  aboutbox.set_property('name','Demo Program')
  aboutbox.set_property('version','0.1')
By the way, the name you want shown in the about box is not necessarily the name string you pass in to the gnome.init() method. It really wants to be the same as whatever the 'human-readable-name' property of GnomeProgram to (if you set that property), but that is getting pretty subtle (not a lot of programs do that).

(Malcolm Tredinnick, Colin Fox)

19.8. How do I pass extra arguments to a Gnome Applet's setup_menu() callback?

If setup_menu() is called with 'None' as user_data (applet.setup_menu(xml,verbs,None)), the callback prototype is callback(widget,verb). If setup_menu() is called with an extra arguement, the callback prototype is callback(widget,verb,user_data).

19.9. In creating a Gnome Applet, how do I use class members for callbacks?

Just create your verbs list like this in your class:
 class MyApplet:
   def __init__(self,applet):
     verbs = [ ( "Properies", self.properties), ("About",self.about) ]
     applet.setup_menu("xml here",verbs,None)
   def properties(self):
     pass # and display properties
   def about(self):
     pass # and display about box.
When called, 'self' will be set properly.

19.10. How do I hide the toolbar of a gnome.ui.App() instance?

If you just call hide() on the toolbar, it is hidden but its display area is still visible (empty, though); that's because it's held in a Bonobo Dock. You need hide the dock item itself, but first you have to get the dock item. One way is to use get_dock_item_by_name().

Here is a snippet from some test code that might put you on the right track. The variable my_app is a reference to the gnome.ui.App instance.

    # Hide toolbar.  We need to get the bonobo dock item to show/hide
    # instead of simply hiding the toolbar itself or we will leave
    # blank dock space when we hide.
    # The default toolbar name for a gnome.ui.App seems to be 'Toolbar'.
    bonobo_toolbar = my_app.get_dock_item_by_name('Toolbar')            
    if bonobo_toolbar:
        bonobo_toolbar.hide()
You can show it again using show() in place of hide().

(Doug Quale)

19.11. Can I use OpenGL to draw in a PyGTK application?

You can, by using a supported OpenGL extension to GTK+. There are currently two extensions in common use:

  As opposed to Jane Loff's GtkGLArea , it provides not an OpenGL
  widget, but an additional GtkWidget API which enables the standard
  (and custom) GTK+ widgets to render 3D scene using OpenGL.

Extra:

You can also do your own code for this, without relying on external libraries. In Linux, you basically have to access GLX functions (glXCreateContext, glXDestroyContext, glXChooseVisual, glXMakeCurrent, glXSwapBuffers) to create and maintain an OpenGL context. If you want to know how to access these functions, see the Python-XLib project.

Then, you have to access GTK's colormap functions like gdk_colormap_new, gtk_widget_push_colormap and gtk_widget_pop_colormap. You create a special OpenGL-enabled colormap and then do something like this:

  1. gtk_widget_push_colormap( opengl-enabled-colormap )
  2. create a GtkDrawingArea widget
  3. gtk_widget_pop_colormap()
Don't forget to call set_double_buffered( False ) on the created widget.

After all that, you can use glXMakeCurrent and glXSwapBuffers with the GtkDrawingArea widget.

19.12. Is there support for tray notification area clients?

A very basic libegg tray icon example is in gnome-python-extras: [cvs.gnome.org]

These wrap the libegg trayicon components (viewable at [cvs.gnome.org] ).

For Microsoft Windows you can look at [aspn.activestate.com]

A common problem with libbegg is that Image widgets do not receive events -- to solve this, place them inside an EventBox.

19.13. How do I a signal a callback when a gtk.Paned widget handle is dragged?

The gtk.Paned widget provides a 'move-handle' signal that would seem to be appropriate, but Skip Montanaro points out that the 'move-handle' signal is only emitted when the handle is moved by use of the keyboard. If the paned window handle is dragged using the mouse, the signal is not emitted.

John Finlay suggests a good solution: Connect to the 'notify' signal and watch for changes in the 'position' property of the paned window. The 'notify' signal will be emitted when any property of a GObject changes.

    def on_pane_notify(pane, gparamspec):
        # A widget property has changed.  Ignore unless it is 'position'.
        if gparamspec.name == 'position':
            print 'pane position is now', pane.get_property('position')

    pane = gtk.HPaned()
    pane.connect('notify', on_pane_notify)

19.14. Is there a grid or spreadsheet-like widget available?

There is Lorenzo's GtkGrid, which is independently packaged and has Python wrappers: [www.sicem.biz]

It is currently in alpha state. There is also a GtkSheet widget which was included in GtkExtras, but no python wrapper currently exists for it, and the project itself is no longer active.

19.15. How do I embed something using Plugs and Sockets?

You can embed other X objects into a gtk.Socket by using the X window's XID. Note that you can reliably embed foreign windows if and only if both sides comply to some common protocol (like Plug and Socket) -- if not, their are nasty corner-cases and things that can go wrong. In other words, you cannot just embed arbitrary XIDs and expect it to work in all cases. Best thing here is to try, and see if things don't break too badly.

We'll use as an example embedding an xterm.

 xwininfo: Window id: 0x1a0000e "xterm"

  Absolute upper-left X:  5
  Absolute upper-left Y:  649
  Relative upper-left X:  5
  Relative upper-left Y:  21
  Width: 484
  Height: 316
  Depth: 24
  Visual Class: TrueColor
  Border width: 0
  Class: InputOutput
  Colormap: 0x20 (installed)
  Bit Gravity State: NorthWestGravity
  Window Gravity State: NorthWestGravity
  Backing Store State: NotUseful
  Save Under State: no
  Map State: IsViewable
  Override Redirect State: no
  Corners:  +5+649  -791+649  -791-59  +5-59
  -geometry 80x24+0-54

  >>> long(0x1a0000e)
  27262990L

  $ python socket.py 27262990

For another example, take a look at the example in the pygtk tutorial: [www.pygtk.org]

(N. Volbers, Maciej Katafiasz)

19.16. How can I use the IconView widget?

here is an example that emulates the preferences window of Firefox (on hover effect which is not easy to do is not here)

    import pygtk
    pygtk.require('2.0')
    import gtk

    class PreferencesMgr(gtk.Dialog):
        def __init__(self):
            gtk.Dialog.__init__(self, 'Preferences', None,
                       gtk.DIALOG_MODAL | gtk.DIALOG_DESTROY_WITH_PARENT,
                       (gtk.STOCK_OK, gtk.RESPONSE_OK,
                        gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL))
            self.current_frame = None
            self.create_gui()

        def create_gui(self):

            model = gtk.ListStore(str, gtk.gdk.Pixbuf)

            pixbuf = gtk.gdk.pixbuf_new_from_file('images/prefs_general.png')        
            model.append(['General', pixbuf])

            pixbuf = gtk.gdk.pixbuf_new_from_file('images/prefs_security.png')
            model.append(['Security', pixbuf])

            self.icon_view = gtk.IconView(model)
            self.icon_view.set_text_column(0)
            self.icon_view.set_pixbuf_column(1)
            self.icon_view.set_orientation(gtk.ORIENTATION_VERTICAL)
            self.icon_view.set_selection_mode(gtk.SELECTION_SINGLE)
            self.icon_view.connect('selection-changed', self.on_select, model)
            self.icon_view.set_columns(1)
            self.icon_view.set_item_width(-1)
            self.icon_view.set_size_request(72, -1)

            self.content_box = gtk.HBox(False)
            self.content_box.pack_start(self.icon_view, fill=True, expand=False)
            self.icon_view.select_path((0,)) # select a category, will create frame
            self.show_all()
            self.vbox.pack_start(self.content_box)        
            self.resize(640, 480)
            self.show_all()

        def on_select(self, icon_view, model=None):
            selected = icon_view.get_selected_items()
            if len(selected) == 0: return
            i = selected[0][0]
            category = model[i][0]
            if self.current_frame is not None:
                self.content_box.remove(self.current_frame)
                self.current_frame.destroy()
                self.current_frame = None
            if category == 'General':
                self.current_frame = self.create_general_frame()
            elif category == 'Security':
                self.current_frame = self.create_security_frame()    
            self.content_box.pack_end(self.current_frame, fill=True, expand=True)
            self.show_all()

        def create_general_frame(self):
            frame = gtk.Frame('General')        
            return frame        

        def create_security_frame(self):
            frame = gtk.Frame('Security')        
            return frame        

    if __name__ == '__main__':
        p = PreferencesMgr()
        p.run()
        p.destroy()

19.17. How can I distribute gtkhtml2 (outside of gnomepythonextras)?

first get gnome-python-extras package, extract it, and copy the gtkhtml2 subdirectory somewhere, delete Makefile.in and Makefile.am from that directory as you don't need them and use this Makefile:

	PYTHONVER = `python -c 'import sys; print sys.version[:3]'`
	CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0 libgtkhtml-2.0` -fPIC -I/usr/include/python$(PYTHONVER) -I.
	LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0 libgtkhtml-2.0`

	all: gtkhtml2.so

	# Build the shared objects
	gtkhtml2.so: gtkhtml2.o gtkhtml2module.o
		$(CC) $(LDFLAGS) -shared $^ -o $@

	# The path to the GTK+ python types
	DEFS=`pkg-config --variable=defsdir pygtk-2.0`

	# Generate the C wrapper from the defs and our override file
	gtkhtml2.c: gtkhtml2.defs gtkhtml2.override
		pygtk-codegen-2.0 --prefix pygtkhtml2 \
		--register $(DEFS)/gdk-types.defs \
		--register $(DEFS)/gtk-types.defs \
		--override gtkhtml2.override \
		gtkhtml2.defs > $@

	# A rule to clean the generated files
	clean:
		rm -f gtkhtml2.so *.o gtkhtml2.c *~  

	.PHONY: clean

19.18. Why does gtkmozembed somtimes crash in load_url()?

This happens on URL:s like "[art.gnome.org] ". It happens because gtkmozembed need to be initialised with a profile before it can work correctly:

  gtkmozembed.set_profile_path("/tmp", "foobar")
  gtkmozembed.MozEmbed().load_url("http://art.gnome.org")
Note that the profile file need not to exist.

19.19. How can I change the background color of the IconView widget?

set the base color of the IconView widget style for diverse states of the widget. Here is an example demonstrating how to set the background of an IconView widget to the same color as the parent ScrolledWindow widget:

    sw = gtk.ScrolledWindow()
    iconview = gtk.IconView()
    style = iconview.get_style().copy()
    style_sw = scrolled_window.get_style()
    for state in (gtk.STATE_NORMAL, gtk.STATE_PRELIGHT,gtk.STATE_ACTIVE):
        style.base[state] = style_sw.bg[gtk.STATE_NORMAL]
    iconview.set_style(style)

19.20. Could I get another example of how to use the IconView please?

Another simple example of how to use the IconView...

    import pygtk
    pygtk.require('2.0')

    import gtk
    import gtk.gdk

    if gtk.gtk_version < (2, 12):
        import warnings

        msg = ('This example tested with version 2.12.9 of gtk. Your using version %d.%d.%d. Your milage may vary.'
               % gtk.gtk_version)
        warnings.warn(msg)

    if __name__ == '__main__':

        # First create an iconview
        view = gtk.IconView()

        # Create a store for our iconview and fill it with stock icons
        store = gtk.ListStore(str, gtk.gdk.Pixbuf)
        for attr in dir(gtk):
            if attr.startswith('STOCK_'):
                stock_id = getattr(gtk, attr)
                pixbuf = view.render_icon(stock_id,
                    size=gtk.ICON_SIZE_BUTTON, detail=None)
                if pixbuf:
                    store.append(['gtk.%s' % attr, pixbuf])

        # Connect our iconview with our store
        view.set_model(store)
        # Map store text and pixbuf columns to iconview
        view.set_text_column(0)
        view.set_pixbuf_column(1)

        # Pack our iconview into a scrolled window
        swin = gtk.ScrolledWindow()
        swin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        swin.add_with_viewport(view)
        swin.show_all()

        # pack the scrolled window into a simple dialog and run it
        dialog = gtk.Dialog('IconView Demo')
        close = dialog.add_button(gtk.STOCK_CLOSE, gtk.RESPONSE_NONE)
        dialog.set_default_size(400,400)
        dialog.vbox.pack_start(swin)
        dialog.run()

19.21. How can I send a pdf file to a printer over the gtk printing dialog?

The gtk+ printing API gives the possibility of creating page content via the cairo infrastructure and sending it to the printer on a per page basis. Though, when the page content is already available in pdf or postscript form, sending it to the printer is quite easier. In Linux one can use the following snippet:

    import gtk
    import gtkunixprint

    def print_cb(printjob, data, errormsg):
        if errormsg:
            print('Error occurred while printing:\n%s' % errormsg)

    filename = 'the_pdf_file_to_be_printed.pdf'
    pud = gtkunixprint.PrintUnixDialog()
    response = pud.run()
    if response == gtk.RESPONSE_OK:
        printer = pud.get_selected_printer()
        settings = pud.get_settings()
        setup = pud.get_page_setup()
        printjob = gtkunixprint.PrintJob('Printing %s' % filename, printer, settings, setup)
        printjob.set_source_file(filename)
        printjob.send(print_cb)
    pud.destroy()
In Windows it is quite simple to achieve a similar result:

    import win32api
    win32api.ShellExecute (0, "print", filename, None, ".", 0)


20. The GTK Mainloop and Threading

20.1. What are the general tips for using threads with PyGTK?

One thread (usually the main thread) should call gtk.threads_init() and gtk.main():

 import gobject
 gobject.threads_init()

 ...

 gtk.main()
On non-win32 platforms other threads can do window modification, processing, etc. Each of those other threads needs to wrap any GTK+ method calls in a gtk.gdk.threads_enter()/gtk.gdk.threads_leave() pair. Preferably, this should be done in try..finally -- if you miss threads_leave() due to exception, your program will most likely deadlock. If your Python is recent enough, use context manager instead of enter/leave functions:

 with gtk.gdk.lock:
     ...
Signal callbacks will be executed in the main thread.

A way to avoid using threads_enter/threads_leave or similar context manager is to call the function from the main thread. A simple way of sending a request to the server is to use gobject.idle_add:

  gobject.idle_add(...)
This is recommended for being portable to win32. E.g., if you want to set the text of an entry:

  gobject.idle_add(entry.set_text, 'new text')
But be careful, because it cannot return anything which evaluates to True. If it does, you have to wrap it in a lambda or a separate function (returning True will cause the function being called more than once, and that is not you want).

20.2. On Win32, the input_add() function doesn't work!

No it works. It might not work with pipes but works for sockets for sure in Windows

In PyGTK 2.6 it's called gobject.io_add_watch()

You can get pipe file descriptors using msvcrt.dll (look into g_io_channel_win32_new_fd documentation) _pipe call and pass (one of) them to gobject.IOChannel() as a real file descriptor.

20.3. How can I make Ctrl-C in the console quit my app which uses PyGTK 1.99.13 or older?

This is something of a hack, since it burns up CPU, and mainquit() won't work, but for a quick shot you can use:

 while True:
   gtk.main_iteration()
This lets the python signal handler breathe every so often. This was originally posted on [www.pycage.de] and stolen :-)

See the thread [www.daa.com.au] for more information, and GNOME bug 72333: [bugzilla.gnome.org]


If you are only interested in Ctrl-c finishing your application and you don't need special cleanup handlers, the following will perhaps work for you:

 import signal
 signal.signal(signal.SIGINT, signal.SIG_DFL)
In PyGTK 1.99.14 a timeout function was added that checks if Ctrl-C was pressed and quits.

20.4. I get random crashing when using lots of threads in PyGTK

20.5. I want to show a splash screen and make it disappear. How?

Pablo Endres Lozada presented this question. I'd suggest using a timeout handler that calls hide() on the window. Something like:

 def setup_app(*args):
   main = gtk.Window()
   # [...] set main up

 splash = gtk.Window() 
 # [...] set splash up
 splash.show()
 # ensure it is rendered immediately
 while gtk.events_pending():
   gtk.main_iteration()

 gobject.timeout_add(5000, splash.hide) # 5*1000 miliseconds
 gobject.idle_add(setup_app)
 gtk.mainloop()
5 seconds later, the splash screen should hide. You should tie the setup portion of your application inside an idle handler (or use a similar technique) or you will end up doing all the work before the splash screen shows up, mind you.

20.6. I am using a separate thread to run my code, but the application (or the UI) hangs.

There are a couple of hitches you can run into when trying to use threading and PyGTK together. For starters, if you are using threads, no matter if you are doing PyGTK calls from a separate thread or not, you must compile PyGTK with --enable-threads.

Now there are two approaches for threads in PyGTK:

1. Allow only the main thread to touch the GUI (gtk) part, while letting other threads do background work. For this to work, first call

  gobject.threads_init()
at applicaiton initialization. Then you launch your threads normally, but make sure the threads never do any GUI tasks directly. Instead, you use gobject.idle_add to schedule GUI task to executed in the main thread. Example:

 import threading
 import time
 import gobject
 import gtk

 gobject.threads_init()

 class MyThread(threading.Thread):
     def __init__(self, label):
         super(MyThread, self).__init__()
         self.label = label
         self.quit = False

     def update_label(self, counter):
         self.label.set_text("Counter: %i" % counter)
         return False

     def run(self):
         counter = 0
         while not self.quit:
             counter += 1
             gobject.idle_add(self.update_label, counter)
             time.sleep(0.1)

 w = gtk.Window()
 l = gtk.Label()
 w.add(l)
 w.show_all()
 w.connect("destroy", lambda _: gtk.main_quit())
 t = MyThread(l)
 t.start()

 gtk.main()
 t.quit = True
2. Allow any thread to do GUI stuff. Warning: people doing win32 pygtk programming have said that having non-main threads doing GUI stuff in win32 doesn't work. So this programming style is really not recommended.

Anyway, to make this work, start by calling:

 gtk.gdk.threads_init()
at startup. Failing to do this will make PyGTK never release the python threading lock. At least Debian's packages are compiled properly, so it's a matter of using that call.

Then you have to wrap your main loop with gtk.threads_enter()/gtk.threads_leave(), like this:

 gtk.threads_enter()
 gtk.main()
 gtk.threads_leave()
Your threads code must, before touching any gtk functions or widgets, call gtk.threads_enter(), and after gtk.threads_leave(), for example:
  ...
  gtk.threads_enter()
  try:
      myentry.set_text("foo")
  finally:
      gtk.threads_leave()
  ...
Also, keep in mind that signal handlers don't need gtk.threads_enter/leave(). There are other concerns, see [developer.gnome.org] .

Cedric Gustin posted a short example of threaded code at [www.daa.com.au] -- it's a good building block for a more complex threaded application.

Finally, if you are writing a C extension module, remember that you need to protect calls that potentially lock the thread with Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS.

20.7. I set up a timeout handler using timeout_add, but the handler only runs once.

When using a timeout handler:

 def on_timeout(self, *args):
   print "Ping", args 

 gobject.timeout_add(1000, on_timeout)
If you fail to return True in the timeout handler, it will only run once. Therefore:

 def on_timeout(self, *args):
   print "Ping", args 
   return True
will run the timeout handler every 1s.

20.8. How do I check if threading was compiled in my version of PyGTK

In PyGTK-2 all gtk.threads_init(). If you get an exception, then it isn't supported (you need to call gtk.threads_init() to enable threading support in a threaded build anyway).

In PyGTK-0, use ldd to list the dependencies of _gtkmodule.so -- if it lists pthread, it was compiled with threading.

20.9. I don't want to use threading. What other options do I have?

Stephen Kennedy reminds us that cooperative threading using generators is an alternative. Two links describe this at a bit more length:

Advantages:

Disadvantages:

For capturing the output of another process, or other file-based I/O, Danny Milosavljevic proposes using non-blocking I/O. This works like so:

He has an example module available under the LGPL at [traveller.cvs.sourceforge.net] Check out about line 243. You should note he has deprecated this particular piece of code, and is using gobject.io_add_watch instead. The input_add functionality is commented still.

20.10. When an exception is raised, it is printed out to standard error! (or how do I get exceptions to be printed to X or displayed in a window?)

One feature of running an application in the gtk mainloop is that exceptions raised don't cause an actual crash. All that happens is the callback that was executing will be interrupted -- the mainloop goes on spinning and handling events. The exception is printed out to standard error, which is great for development and developer-testing, but not as great when running without a console attached to your application, or in a production environment.

There are two approaches here, both useful in different situations.

  logfile = os.path.expanduser("~/.myapp.log")
  sys.stderr = open(logfile, 'a')
You can also combine this with a log() call that outputs to sys.stderr too:

  def log(self, s):
      now = time.strftime("%Y-%m-%d %H:%M")
      sys.stderr.write("%s: %s\n" % (now, s))
I use a function like this with a cronjob to pick up exceptions raised daily in client installations. This way I can collect problems before the user has time to report them!

20.11. How can I monitor sockets or files inside the gtk mainloop (or how does gtk.input_add() work)?

PyGTK provides a method for monitoring a file or socket and automatically calling a users function:

 id = gtk.input_add(file_object, condition, function)
As seen above, gtk.input_add parameters are a file object, an integer constant that describes the condition you are monitoring for, and a callable.

condition is one of the following (use gtk.gdk for PyGTK-2):

Note, some versions of pyGTK require you to use:

 import GDK
 GDK.INPUT_READ
instead of gtk.INPUT_READ (or WRITE or EXCEPTION).

Example call:

 id = gtk.input_add(self.server, gtk.INPUT_READ, self.GetIO)
gtk.input_add returns an identifier, an integer than can be used with:

 gtk.input_remove(id)
to stop processing the associated file or socket. This only needs to be called when your application no longer needs the socket, not after each read or write.

The callable function should return gtk.TRUE if it wants to continue getting called in the future.

John Nelson writes to say: It may be worth noting that if your application has separate mainloop threads (i.e. you run the pygtk mainloop from more than one thread), there seems to be evidence that gtk "may" use a seperate thread to notify your program when the desired condition becomes true. Thus, if you do any gtk (gdk, really) work in the handler, you may need to call gtk.threads_enter() and gtk.threads_leave() when done.

While I can't confirm this is true, if you are seeing this symptom, give it a try and email me to update the FAQ if you do.

Another important note is that in GTK version 2, you will get back a fd in your handler if the object you pass in has a fileno() method (like a socket does). In GTK version 1, you will get a socket back if you pass a socket in. E.G.:

 ...
 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)

 listenhost=""
 listenport=port
 s.bind((listenhost, listenport))
 s.listen(5)
 #GDK->gtk.gdk in GTK V 2.0
 id=gtk.input_add(s, GDK.INPUT_READ, handleNewConnection)

 ...

 def handleNewConnection(self,source,condition):
     #source is a socket in GTK v 1 and a fd in version 2
     ...
     return gtk.TRUE

20.12. How do I get an action to run periodically, say, every 30 seconds?

Short answer: use gobject.timeout_add(). A longer answer with one caveat is available as FAQ 20.7.

20.13. The GTK thread dies, but some windows remain open. I don't want that, what can I do?

GTK doesn't close windows automatically when the thread which create them exits because it doesn't associate its windows with threads, so there's no reason to close them when a thread exits.

You can use the gtk.window_list_toplevels() function that will get all top level windows in the application. And you can destory those windows. If you want to close only some windows, then you must keep track of them or somehow choose which ones to destroy.

Note that closing all windows won't release all memory allocated by GTK. AFAIK, there is no function to clean up everything. GTK is designed to run for the lifetime of the process, so it is not a high priority to add functions to clean up internal hash tables and other data structures because they are usually needed until the process terminates. If you need a hard guarantee that everything will be freed, you may want to start a separate process.

Information provided by John Ehresman

20.14. My application uses threads and GtkDialogs seem to freeze it! What can I do?

You can sove it easily: see Q 10.17

20.15. I'm using threads and timeout or idle or input handlers and the app freezes. What's wrong?

From gtk.gdk.theads_init reference: Signal handlers are automatically invoked within a gdk_threads_enter() and gdk_threads_leave() function pair by GTK so the gtk.gdk.threads_enter() and gtk.gdk.threads_leave() functions should not be called within a Python signal handler or the application will deadlock. However, idle, timeout and input handlers are executed outside the GDK global lock (GGL) so these should use the gtk.gdk.threads_enter() and gtk.gdk.threads_leave() functions if PyGTK methods or functions are called.

An example to illustrate better the proposed solution follows:

    def run(self, called_by_timeout=False):
        if called_by_timeout:
           # if it was called outside of GDK global lock (eg. here a timeout) make sure we threas_enter
           gtk.gdk.threads_enter()

        ...code-here...

        if called_by_timeout:
           gtk.gdk.threads_leave()
more: [www.pygtk.org]

info provided by Víctor M. Hernández Rocamora

If your code contains thread_enter and thread_leave, and on win32 platform it working fine, but on linux it hangs, that because mutexes on win32 are recursive (you can obtain lock any times in thread), while on linux they not. So, I have found easy way to work with that:

 class CGtkLocker:
        def __init__(self):
                self.lock = threading.Lock()
                self.thread = None
                self.locked = 0

        def __enter__(self):
                with self.lock: DoLock = (thread.get_ident()!=self.thread)
                if DoLock:
                        gtk.gdk.threads_enter()
                        with self.lock: self.thread = thread.get_ident()
                self.locked += 1
                return None

        def __exit__(self, exc_type, exc_value, traceback):
                with self.lock:
                        self.locked -= 1
                        if self.thread!=thread.get_ident():
                                print "!ERROR! Thread free not locked lock!"
                                sys.exit(0)
                        else:
                                if self.locked == 0:
                                        self.thread = None
                                        gtk.gdk.threads_leave()
                return None
 GtkLocker = CGtkLocker()

 def GtkLocked(f):
        @wraps(f)
        def wrapper(*args, **kwds):
                with GtkLocker.lock:
                        if GtkLocker.thread == None or GtkLocker.thread==thread.get_ident():
                                GtkLocker.thread = thread.get_ident()
                                GtkLocker.locked += 1
                                WeHold = True
                        else:
                                print "!ERROR! GtkLocked for non-owned thread!"
                                WeHold = False
                try:
                        ret = f(*args, **kwds)
                        return ret
                finally:
                        if WeHold:
                                with GtkLocker.lock:
                                        GtkLocker.locked -= 1
                                        if GtkLocker.locked == 0: GtkLocker.thread = None
        return wrapper
that code put into global GUI unit (for example, called "gui"), and use
 with gui.GtkLocker:
   code-that-use-gtk()
where you need to get lock for GTK -- that works, that block can call GtkLocker any times it need without deadlock. But! Since all event handlers called with already gtk locked, you must bind wrapped handlers, so you must call instead of
  somewidget.connect('event-name', handler)
that way:
  somewidget.connect('event-name', gui.GtkLocked(handler))
that makes handler called in already-locked context, so your "with gui.GtkLocker"'s will still works without deadlock.

Info provided by Anton Fedorov (datacompboy)

20.16. So how do I use gobject.io_add_watch (used to be input_add) ?

this will get and print index.html's html source without blocking or freezing your GUI (notice that if there are no special requirements, FAQ 20.21 explains how to do the same thing in a simpler and cleaner way):

	import socket
	import gobject
	import gtk

	def handle_data(source, condition):
		data = source.recv(1024)
		if len(data) > 0:
			return True # run again
		else:
			return False # stop looping (or else gtk+ goes CPU 100%)

	sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
	sock.settimeout(15)
	sock.connect(('pygtk.org', 80))
	sock.send('GET /index.html HTTP/1.1\nHost: pygtk.org\n\n')

	gobject.io_add_watch(sock, gobject.IO_IN, handle_data)
	w = gtk.Window()
	w.add(gtk.Button('abc'))
	w.show_all()
	gtk.main()
io_add_watch() can watch on objects return by urllib.urlopen() too. However, the urlopen() operation takes some time, hence freezing the GUI for a fraction of second.

Please keep in mind that io_add_watch() works for sockets on all platforms, but if you want to watch files you have to use GNU/Linux or other Unices

Advanced Usage:

as you can see once you get EOF gtk+ forces you to give up on reading more possible stuff there. That is not sane for all usages but it's what it's done. I sat down and tried to workaround this. I ended up with something I hope you will find useful:

	import socket
	import gobject
	import gtk
	import signal

	def get_file():
		sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		sock.settimeout(15)
		sock.connect(('pygtk.org', 80))
		sock.send('GET /index.html HTTP/1.1\nHost: pygtk.org\n\n')
		return sock

	def handle_data(source, condition):
		data = source.recv(12)
		print len(data)
		if len(data) > 0:
			return True #run forever
		else:
			print 'closed'
			print 'so get new data...'
			sock = get_file()
			gobject.io_add_watch(sock, gobject.IO_IN, handle_data)
			return False # stop looping

	sock = get_file()
	gobject.io_add_watch(sock, gobject.IO_IN, handle_data)

	w = gtk.Window()
	w.set_border_width(15)
	msg = '''\
	Play with resizing the window...

	RESULT:
	It will only block on sock.connect()
	which is normal because to use the socket you have to connect
	here we wait for maximum 15 seconds and then we timeout'''
	w.add(gtk.Label(msg))
	w.show_all()
	signal.signal(signal.SIGINT, signal.SIG_DFL) # ^C exits the application
	gtk.main()

20.17. Why isn't my thread running?

Regardless of what the thread does, gtk.threads_init() must be called before gtk.main(). Typically the main thread calls both.

20.18. How do I write a qt application using gobject.MainLoop?

(The latest copy of this document can be found at [www.patrickkidd.com] )

GStreamer-0.10 uses asynchronous calls to control its pipelines, and these calls have async replies. You can get these replies by either polling the pipeline's bus, or by running a gobject.MainLoop. Problems arise when you are writing a qt application that has its own main loop, and your application doesn't necessarily have multi-threaded requirements (besides those already implemented by gstreamer). The following class will run the gobject.MainLoop whenever the QApplication is idle by using QTimer.start(0), and gobject.MainLoop.MainContext.pending/iteration.

The exception in the constructor protects the singleton-nature of gobject.MainLoop for this application. Now you can just make your async calls from within the main qt thread. Fire away!

 import sys
 import time
 import gobject
 from PyQt4.QtCore import QObject, QTimer, SIGNAL, QThread, QEventLoop
 from PyQt4.QtGui import QApplication

 gobject.threads_init()

 class GObjectLoop:
     """ Manages a gobject.MainLoop. """

     _instance = None

     def __init__(self):
         if not QGObjectLoop._instance is None:
             raise RuntimeError('there can only be one QGObjectLoop')
         else:
             QGObjectLoop._instance = self
         self.gmainloop = gobject.MainLoop()
         # this is horribly inefficient!
         self.gcontext = self.gmainloop.get_context()
         self.idletimer = QTimer(QApplication.instance())
         QObject.connect(self.idletimer, SIGNAL('timeout()'),
                         self.on_idle)
         self.idletimer.start(0)

     def __del__(self):
         self.gmainloop.quit()

     def on_idle(self):
         while self.gcontext.pending():
             self.gcontext.iteration()

 # this prevents a seg fault, not sure why.
 import atexit
 def _atexit():
     GObjectLoop._instance = None
 atexit.register(_atexit)
The only problem with this is that it is terribly (horribly) inefficient. In fact, your main thread is likely to hog all remaining CPU cycles! This is because qt will check the gobject main loop whenever it is idle, which is the same as saying your machine will run on_idle whenever it is idle. I ran into some threading problems with trying to run the qt and gobject loops in seperate threads, and decided that this was much easier. Good luck!

20.19. What does "Fatal Python error: GC object already tracked" mean?

This error will most likely happen in a threaded application. Make sure you have informed gobject you are writing a threaded script/application by calling gobject.threads_init() just after importing the gobject module.

20.20. gobject.io_add_watch doesn't work with non-blocking sockets on win32!

Due to limitations in the winsock API, you can only have one io watch active per non-blocking socket, so you will need to write one function for both IO_IN and IO_OUT events or only look for IO_IN or IO_OUT events at a time. When you call gobject.io_add_watch on a non-blocking socket which already has an io watch on it, the previous watch will be silently removed- on UNIX, of course, you must explicitly remove it. Also, you must watch for IO_HUP to detect the socket being closed on the other end- unlike on UNIX, IO_IN will not be flagged when a socket is closed.

20.21. How do I download something without freezing the GUI (and without threading)?

Using Gio.File.read_async, as the following code, which downloads pygtk's homepage and displays part of its html, shows:

    import gio, gtk

    class Downloader(object):
        def get(self, url):
            gfile = gio.File(url)
            gfile.read_async(self._file_read_cb)

        def _file_read_cb(self, gfile, result):
            stream = gfile.read_finish(result)
            # This will only read the first 100 bytes.
            stream.read_async(100, self._stream_read_cb)

        def _stream_read_cb(self, stream, result):
            data = stream.read_finish(result)
            label.set_text(data)

    down = Downloader()

    dial = gtk.Dialog()
    label = gtk.Label()
    dial.action_area.pack_start(label)
    label.show_all()
    label.connect('realize', "http://www.pygtk.org")
    dial.run()


21. Win32 and PyGTK

21.1. How do I get PyGTK running on MS Windows?

The easiest way to install PyGTK is by following these steps:

To check if everything is working correctly, run this script from a file or inside the Python interactive console:

  import gtk

  window = gtk.Window()
  window.set_title("PyGTK Test Window")
  window.connect("destroy", gtk.main_quit)
  window.show_all()

  gtk.main()
NOTE: Be sure to check if you already have a GTK+ 2.10 runtime installed, this may cause conflicts with others applications using the GTK+ runtime, like GIMP.

There are some older versions of pygtk still available:

21.2. Is there a walkthrough on getting PyGTK2 and libglade2 to work on win32

You need to install win32 versions of the following:

Here is how to do it:

1. If you don't have it, get Python for Windows from [www.python.org]

2. There is more than one way to install GTK runtime for win32. (2a) is the easiest (2b) gives a recipe that uses a simple installer. (2c) is more complicated but lets you choose which bits of GTK you want.

2a. The gladewin32 project [gladewin32.sourceforge.net] offers a Gtk+/Win32 Development Environment (runtime, devel, docs, glade, etc.) Installer. This includes both GTK and glade libraries, plus a win32 version of the glade editor too. It installs in C:/GTK by default (we refer to this folder as %gtkdir% in a step further down).

If you use this installer, it includes libglade, and you can skip to step 4.

2b. From [www2.arnes.si] get the GTK+ 2 for Windows runtime environment. Unzip it and run the setup program. It should install the libraries in C:\Program Files\Common Files\GTK\2.0\ (from now on called %gtkdir%).

Note this does not include libglade. Go to step 3.

2c. From [www.gimp.org] get the recommended versions of the following packages:

Unpack the packages downloaded in a common directory, e.g. C:\Program Files\Common Files\GTK\2.0\ (from now on called %gtkdir%)

Note this does not include libglade. Go to step 3.

3. From [gladewin32.sourceforge.net] download libglade-bin. Unzip and copy the contents of the bin directory to %gtkdir%/bin. While you're there, you can grab the Glade for Win32 Binary Installer [gladewin32.sourceforge.net] which confusingly does not include libglade!

4. There are two possibilities for this step, which involves making the installed libraries visible to other programs. *Note that this requires modifying PATH and NOT PYTHONPATH*

4a. The simplest way to enable GTK+ for your system is to add %gtkdir%\lib and %gtkdir%\bin to your PATH.

If you are using Windows 2000/XP, you can edit the path in Start - Control Panels - System - Advanced - Environment Variables.

If you are using a DOS-based Windows version (W95,W98,ME), add the following line to your C:\AUTOEXEC.BAT file:

  set PATH="%PATH%;%gtkdir%\lib;%gtkdir%\bin" 
(You need to substitute %gtkdir% with your actual directory of course.)

4b. If you don't want to alter the system path, but can change the scripts you will run that require gtk2, add these lines to them (before the pygtk import):

 # Make Windows actually find the stuff installed
 gtkdir = 'C:/Program Files/Common Files/GTK/2.0'
 import os
 os.environ['PATH'] += ";%s/lib;%s/bin" % (gtkdir, gtkdir)
5. Reboot (editor's note: mwahahaha). (Although you probably don't need to reboot on WinXP.)

6. Download and install the PyGTK package from [www.mapr.ucl.ac.be]

7. You can test everything is working by starting a Python interpreter and issuing:

  # ensure we're using the right version
  import pygtk
  pygtk.require ('2.0')

  import gtk
  import gtk.glade
The "import pygtk" bits will be necessary depending on what PyGTK version you have. If you omit it, you may get exceptions such as "AttributeError: 'module' object has no attribute 'Window'" when referring to objects in the gtk module (in this case, gtk.Window).

8. Don't get an error message.

9. You're done.

* Note that on WinXP with the default Luna theme, GTK+-2.2.4.1 has a bug where radio buttons do not activate when clicked. GTK+-2.2.4 works fine.

(Lars Bensmann, John Platte, John Hunter)

21.3. Does the Win32 port support threading?

More or less.

The current (and unlikely to change) status of threads on win32 is that you basically can't perform gui operations from a subthread, even with gdk_threads_enter/leave (and any GTK or GDK call should be considered a "gui operation"). Essentially, the X11 and win32 gui/threading models are different, and making gtk work the same on both would be very hard. There is a proposal to solve this problem more fundamentally at [bugzilla.gnome.org]

This isn't entirely bad news, though. Threads on win32 /do/ work in most situations. Be sure to check general tips at [faq.pygtk.org] first

If you need to use signals in a threaded win32 application, you need to make sure that the signal sent to your widget is done from the main thread instead of the subthread. The easiest way to do this is using gobject.idle_add via a wrapperfunction:

  def do_gui_operation(function, *args, **kw):
      def idle_func():
          gtk.threads_enter()
          try:
              function(*args, **kw)
              return False
          finally:
              gtk.threads_leave()
      gobject.idle_add(idle_func)
Now, in your subthread, instead of calling:

  gtk.threads_enter()
  do_gtk_stuff(arg1, arg2)
  gtk.threads_leave()
You should call:

  do_gui_operation(do_gtk_stuff, arg1, arg2)
You don't need to hold the thread lock to call gobject.idle_add (or do_gui_operation) but you do need to acquire it inside the idle function because they are, by default, run without holding the thread lock.

Note also some advice from Alexandre Fayolle, Win32 PyGTK extraordinaire, on older versions of PyGTK:

A trick to get threads to work properly that was sent to the list some time ago (I don't remember who I should credit for it, but it works very well) is to add a timeout function that does a very short sleep, for instance 1e-3 seconds, using timeout_add(...), for instance:

 from gtk import *
 import time
 import sys
 def sleeper():
    time.sleep(.001)
    return 1 # don't forget this otherwise the timeout will be removed

 if __name__== '__main__':
    # do other inits here
    if sys.platform == 'win32':
        timeout_add(400,sleeper)
    mainloop()
You should adjust the value of the period of the timeout so that your app still runs smoothly.

If you want pseudothreads that do not suffer from such problems see: [aspn.activestate.com] [www.gnome.org]

21.4. Where is GdkImlib for MS Windows?

If you're looking for information on running GdkImlib under windows, here's the beef:

See [groups.yahoo.com] . The native port of gdkimlib has been "abandoned" by the author of gtk+ on win32. I guess the only solution is to compile gtk+-1.2, gdkimlib and pygtk for X11 using cygwin and its port of XFree 4.2.

(Cedric Gustin)

If you plan to work with pygtk and gnome 2.0, you should switch to gdk-pixbuf, which actually works under windows : [developer.gnome.org]

(Runar Petursson)

21.5. How can I bundle a PyGTK program in windows so my users don't need to install Python or the GTK+ libs?

On win32, you should give py2exe [www.py2exe.org] a try. It works with pygtk. Once your code is frozen, you can create an installer with Inno Setup for example.

Michal Pasternak recommends giving cxFreeze a try: [starship.python.net] . It works in a different way than py2exe and McMillan Installer; it's faster building the package, and it doesn't automatically include all the DLLs.

The gtk+-2.x runtime environment is available here, and also as a nice installer: [gladewin32.sourceforge.net]

Other alternatives may include Gordon McMillan's installer which used to be available at [www.mcmillan-inc.com] ([web.archive.org] waybackmachine copy) - he had an overview of the other options as well in the right-hand column of that page.

[www.anti-particle.com] describes one example using GTK+ 2.4, py2exe (0.5.x) and Inno Setup, and here's another one, courtesy of Jamey Cribbs:

Ok, here are some very rough notes on creating a self-executing installer of your pygtk app for Windows. I'm sure there are better ways to do this, but this works for me.

1.) Install py2exe and Inno Setup.

2.) Add os.environ['PATH'] += ";gtk/lib;gtk/bin" to top of your script.

3.) Create an executable of your app using py2exe. This is going to take a lot of trial and error, because, although the exe will probably work on your original machine, when you move it to a "clean" machine, you invariably will be missing a module that py2exe did not automatically include. Not to worry! Py2exe give you various ways to manually include missing modules. It's going to take some tweaking, but you will get there. Here is an example of the command line that I use for my app:

python setup.py py2exe --force --excludes gtk, gobject,pango --packages pyPgSQL --icon fred6.ico

(Note I think this command example is a bit stale. E.g. --force does not seem to work with versions downloaded in Oct 2004. Also the --excludes and other options can be included in the setup.py script. I suggest checking the mailing list archives.)

The reason we exclude gtk is that gtk needs some extra files, which gtk searches for relative to the path of the gtk DLLs. So it is safer to just copy the whole gtk tree intact, as is done below. This means the extra files can be found, e.g. those in gtk/etc and gtk/lib; and helps with debugging by avoiding multiple copies of the same DLL in the installation.

Here's what my setup.py script looks like:

  from distutils.core import setup
  import py2exe
  import glob

  setup(name="fredgui", scripts=["fredgui.pyw"],
   data_files=[(".",glob.glob("*.bmp")),(".",glob.glob("*.gif")),
               (".",glob.glob("*.png")),(".",glob.glob("*.jpg")),
               (".",glob.glob("*.ico")),(".",glob.glob("*.xpm")),
               (".",glob.glob("../../jgcmodules/*.py"))],)
4). Ok, now that I have a exe for my app, I need to copy some directories to the "dist/fredgui" directory that py2exe created to hold my app. I copy everything below c:\program files\common files\GTK\2.0 to a "gtk" directory under my dist/fredgui directory. (NOTE: this is not needed (py2exe does that) I also copy all of the pygtk files (and included subdirectories), from my python disribution, into my dist/fredgui directory.)

5.) Now, we turn to Inno Setup. There's a copy of my Inno script at [www.async.com.br] .

6.) I compile the script and it creates a setup.exe. Copy this to a "clean" machine and run it. It should install the app, create desktop icon, start menu icons, etc. Try to run the app. If it doesn't work, chances are that you are missing a module that didn't get included in either py2exe or Inno setup. One cheezy way to debug it is to initially create the executable in py2exe as a console app (using the --console flag in py2exe). This means that, even though the app is a gui, it will still open a dos box when it runs on the target machine. This will alllow you to see the error message that gets generated when it bombs out on the clean machine.

7). Don't give up. It will probably take several tries, but eventually you will end up with a working executable on the clean machine!

Note: The above instructions are an EXTREMELY cheesy way to accomplish the task of creating a self-installing pygtk app. I'm sure that there are many more efficient ways of doing this. Also, my knowledge of py2exe and Inno setup is VERY limited, so I'm sure that there are things that could be done much better using these tools.

I hope these notes have been helpful (and that I didn't forget any steps!).

Note: If your app crashes on non-English Windows, but works OK on English Windows, it may be due to corrupted locale files (*.mo in the gtk runtime tree).

Final note: If you are using Python 2.2.3 or later, and you're getting a UnicodeError when running your script, see Michal's Pasternak's explanation at [pasternak.w.lub.pl]

21.6. How do I change the Window icon of a Win32 PyGTK app?

See FAQ 10.7.

21.7. How do I make the my PyGTK app look a bit more like a `normal' Windows app?

The Gtk Wimp project produces a theme that makes GTK+ look quite similar to Windows, and on WinXP it actually uses native calls to render them. See [gtk-wimp.sourceforge.net] for details and download.

It is based on the Redmond95 theme but changed significantly. Note that Raleigh is also pretty close to windows (except for subtle colors and the optionmenu).

John K Luebs offered this great explanation on what sort of differences exist, and workarounds if you don't want to use Wimp:

One important difference is the size of the fonts. The reason the default font looks so big is because Windows has a default res of 96 dpi. When GTK was first released, most people were running with monitors that were actually around 75dpi (I bet you that even today this is still the case) and therefore most people were running their X server at 75 dpi. When you run the default GTK font size (can't remember if its 10 or 12 points) at 96 it looks ridiculously big.

This does not require a change of theme. You simply need to edit your gtkrc file or parse a new one when your program starts. The "default" font on Windows 2000 systems is Tahoma 8.You can edit the gtkrc-2.0 file in your GTK runtime tree. You can also use the gtk.rc_parse function to parse a specific rc file when your application starts.

As for the resource file syntax, I think you do best to read the Resource Files chapter in section II of the GTK 2.0 API reference. What you might want is something like this in one of the rc files:

 style "win32-font"
 {
   font_name = "tahoma 8"
 }
 class "*" style "win32-font"

21.8. How do I compile PyGTK for win32

There are a set of the steps at Cedric Gustin's [www.pcpm.ucl.ac.be]

One potential roadbump is that for WindowsME/mingw/python2.2/pygtk2, the compiler flag -mms-bitfields needs to be set to successfully import pygtk. You can do this by editing setup.py and calling

  for module in ext_modules:
      module.extra_compile_args.append('-mms-bitfields')
Note that it has been said that cygwin-compiled pygtk may not work.

21.9. How do I find out the GTK+ installation path on windows?

Luca Gambetta (ziabice at ziabice.net) contributes the following script, which is portable between Win32 and *nix:

 import sys

 if sys.platform.startswith("win"):
     # Fetchs gtk2 path from registry
     import _winreg
     import msvcrt
     try:
         k = _winreg.OpenKey(_winreg.HKEY_LOCAL_MACHINE, "Software\\GTK\\2.0")
     except EnvironmentError:
         print "You must install the Gtk+ 2.2 Runtime Environment to run this program"
         while not msvcrt.kbhit():
             pass
         sys.exit(1)
     else:    
         gtkdir = _winreg.QueryValueEx(k, "Path")
         import os
         os.environ['PATH'] += ";%s/lib;%s/bin" % (gtkdir[0], gtkdir[0])
         import pygtk
         pygtk.require ('2.0')
 import gtk

21.10. DLL Errors after upgrading to PyGTK-2.0.0.win32-py2.3

Why do I get "The procedure entry point gdk_window_get_decoration could not be located in the dll libgdk-win32-2.0-0.dll" in Windows when running a PyGTK app after upgrading to PyGTK 2.0.0.win32-py2.3?

The dll could be any of several GTK related DLLs. Such as iconv.dll, libgdk-win32-2.0-0.dll etc.. Charles Lepple was exactly right when he pointed me to the winnt/system32 directory. Glade 1.1.2 had installed a bunch of dll's in that location that were getting picked up by Python and the system, before the new GTK+ runtime 2.2.4 dlls. Python wasn't happy about it. On another system, I found a PATH with d:\tcl\bin in it, and the iconv.dll was there as well. After removing the entry from the path, and removing the dlls from the system32 dir I rebooted. Now the app loads perfectly. I haven't tried reinstalling Glade yet... However I think if I leave the GTK 2.2.4 in the PATH, and remove any rouge dlls after the install, everything should be fine.

21.11. Is it possible to have antialiased fonts on Win32?

Fonts on Windows are drawn by GTK+ using the native win32 calls; therefore, you need to have font smoothing enabled in Windows itself. Note that Windows will not smooth fonts within certain point sizes (6pt - 10pt for most fonts) unless you are using Windows XP.

On versions other than WinXP, you can enable font smoothing on Windows by following these steps:

And on Windows XP:

Note that GTK and Pango do not use Xft on Windows, so the GDK_USE_XFT flag doesn't have any meaning there.

(James and Tim Evans)

21.12. How do themes work on win32?

A patch was submitted to sourceforge to request the inclusion of the precompiled engines and associated themes in the main distro a while ago; check the patches page on [sourceforge.net] .

The tricky bit is how to tell GTK on Windows which theme to use. There are at least 3 ways to do this (though I have only tested 2):

With the second choice there is less room for error since you do not have to rename folders: you simply copy one file into a different location. To get back to the original settings you just delete that gtkrc from the etc/gtk-2.0 folder.

If you don't want to tweak with rc files, there also a GUI program by Alex Shaduri to preview and select the theme and font to be used by all GTK apps. It's called "gtk2_prefs" and you will find it at [members.lycos.co.uk] (version 0.2.0 was current as of this writing).

Note that all themes mostly work with some off-by-one glitch drawing seen on the right of some borders.

(Tyler Wilson, Fabien Coutant)

21.13. Can PyGTK have the native filechooser of Windows?

This is a replacement for the earlier version of this FAQ entry that didn't work when tested in Win 2k.

The following is directly copied from C:\Python24\Lib\site-packages\win32\Demos\GetSaveFileName.py (so you need to install the 'win32all' package).

  import win32gui, win32con, os

  filter='Python Scripts\0*.py;*.pyw;*.pys\0Text files\0*.txt\0'
  customfilter='Other file types\0*.*\0'

  fname, customfilter, flags=win32gui.GetSaveFileNameW(
    InitialDir=os.environ['temp'],
    Flags=win32con.OFN_ALLOWMULTISELECT|win32con.OFN_EXPLORER,
    File='somefilename', DefExt='py',
    Title='GetSaveFileNameW',
    Filter=filter,
    CustomFilter=customfilter,
    FilterIndex=1)

  print 'save file names:', repr(fname)
  print 'filter used:', repr(customfilter)
  print 'Flags:', flags
  for k,v in win32con.__dict__.items():
    if k.startswith('OFN_') and flags & v:
        print '\t'+k

  fname, customfilter, flags=win32gui.GetOpenFileNameW(
    InitialDir=os.environ['temp'],
    Flags=win32con.OFN_ALLOWMULTISELECT|win32con.OFN_EXPLORER,
    File='somefilename', DefExt='py',
    Title='GetOpenFileNameW',
    Filter=filter,
    CustomFilter=customfilter,
    FilterIndex=0)

  print 'open file names:', repr(fname)
  print 'filter used:', repr(customfilter)
  print 'Flags:', flags
  for k,v in win32con.__dict__.items():
    if k.startswith('OFN_') and flags & v:
        print '\t'+k


22. libglade

22.1. How do I use PyGTK and glade together (using libglade)?

For a more in depth answer see the Glade articles at [www.pygtk.org]

Basically, the steps involved are:

1. Create your interface with glade, and save the XML file (say, foo.glade).

2. Implement the relevant code using gtk.glade:

  import gtk.glade
  # instantiate XML object
  tree = gtk.glade.XML("foo.glade")
  # get references to individual widgets
  w1 = tree.get_widget("window1")
  e1 = tree.get_widget("entry1")
Some explaining is due. First, by instantiating an gtk.glade.XML object, you are actually parsing the glade file in runtime. The XML instance abstracts the glade widget tree, which is why it's often named "tree" or "wTree" in examples.

It's important to understand that by creating an XML instance you are in fact *generating the UI*, and all widgets will be created in this step. To deal with visibility issues, see FAQ 22.6.

The most important method in the XML instance is get_widget(), which returns widgets defined in your glade file by name. Glade assigns names by default, and the pattern is usually <widgetname><number>; in the example above we are using the default widget names for a GtkWindow and a GtkEntry. You are advised to change these names to something that makes sense for your application to avoid going insane performing code maintenance.

If you'd like to deal with signals defined in the gladefile, take a look at FAQ 22.4.

Keep in mind that gtk.glade automatically caches XML trees. So don't try any complex tricks to reuse XML trees if you have to create the same UI multiple times. The correct thing to do is simply to instantiate the XML multiple times with the same parameters.

22.2. How do I internationalize a PyGTK and libglade program?

1. Simple PyGTK application

1.1 Prepare your application

 print _('Hello World!')
 s = _('%s: %u / %u\n') % (id, x, y)
1.2 Include gettext support

 APP = 'myapp'
 DIR = 'locale'

 import locale
 import gettext
 locale.setlocale(locale.LC_ALL, '')
 gettext.bindtextdomain(APP, DIR)
 gettext.textdomain(APP)
 _ = gettext.gettext
1.3. Create the translations

Please note that the command line tools used in this example requires gettext installed. See* [www.gnu.org] for more information

 xgettext -k_ -kN_ -o messages.pot *.py

 LANG=de_DE msginit

 msgmerge -U de.po messages.pot

 mkdir -p locale/de/LC_MESSAGES/
 msgfmt de.po -o locale/de/LC_MESSAGES/myapp.mo
4. Thats it - now use your application!

 # start without any translation
 LANG=de_DE python myapp.py
2 Translating glade files

2.1 Extracting strings

 intltool-extract --type=gettext/glade foo.glade
This way is prefered and will also take into account and will not include the strings that were not marked for translation

Include *.c as an argument to xgettext if you chose to have glade generate .c file instead of using intltool. In case of intltool-extract add *.glade.h instead of the .c file

2.2 Using the right domain

 widgets = gtk.glade.XML(glade_file, widget_name, APP)

 gettext.bindtextdomain(APP, DIR)
 gettext.textdomain(APP)
into this:

 for module in (gettext, gtk.glade):
     module.bindtextdomain(APP_NAME, LOCALE_DIR)
     module.textdomain(APP_NAME)
3.0 Installing .mo files libraries provided by the operating system

In Ubuntu you need to install a separate package for each language you wish to support. The packages contains the .mo files for glibc,gtk+ etc. The name of the packages in ubuntu are

  language-pack-XX
  language-pack-gnome-XX
where XX should be replaced with the first two letter code, eg es for spanish and sv for swedish.

22.3. Why doesn't gettext work on my libglade UIs with Python <= 2.2?

Note: this has been fixed in Python2.3 by Martin v. Löwis; see the bug report at [sourceforge.net] for details.

This was actually a problem with Python. Python2.0 to 2.2 included a pure-python gettext.py module, which provides the same basic gettext API, but has some new features. The problem with a pure python implementation is that it never calls glibc textdomain() and bindtextdomain(). Since libglade is implemented in C, the internationalization happens outside the scope of the python interpreter. Without *textdomain(), libglade never knows that C gettext support is to be activated for the UI you are instantiating.

There are a few workarounds:

 gtk.glade.bindtextdomain(APP, DIR)
 gtk.glade.textdomain(APP)

 import dl
 l = dl.open('/lib/libc.so.6')
 l.call('bindtextdomain', APP, DIR)
 # if you want unicode strings:
 l.call('bind_textdomain_codeset', APP, 'UTF-8');

22.4. I'm using libglade, but what do I do with the signals and handlers I set in the glade file?

Typically, you create an python object to represent a window, and then construct that object from a libglade file. PyGTK allows you to connect the signal handlers from the glade file directly to methods on your glade proxy object:

 class MyWindow:

    def __init__(self):
	# Load the glade file
        wtree = glade.XML('foo.glade')
	# Connect the glade signals handlers to the python callbacks
	wtree.signal_autoconnect(self)

    # define a callback (method)
    def a_name_of_a_signal_handler(self, *args):
        ....
The nice thing about autoconnecting to an object is that you connect to bound methods, so you always receive a reference to the object itself in the method arguments. The other arguments of the method are the standard signal arguments. Note that PyGTK _will not_ warn you about signal handlers that were registered in the glade file, but are not implemented in your object.

Often, you will also want to reference the widgets that you construct. This snippet of code, to be placed at the end of __init__, will make add each widget as an attribute of your object:

        for w in wtree.get_widget_prefix(''):
            name = w.get_name()
            # make sure we don't clobber existing attributes
            assert not hasattr(self, name)
            setattr(self, name, w)
The object-autoconnection feature was implemented in PyGTK 1.99.15; older versions don't have it. Other methods for doing the autoconnection follow.

Instead of passing signal_autoconnect an object, you can pass it a dict filled with methods, like

 dict[glade_method name] = python_method_reference
and call:

 gladetree.signal_autoconnect(dict)
for signal connection to be performed.

There are a number of base classes that wrap this process, as well. One is included with Kiwi: [www.async.com.br] and another, with Mitch Chapman's GladeBase: [ftp.ssc.com] (article at [www.linuxjournal.com] )

Jonathan Bartlett also contributed this class to the list:

 import new, types

 class GladeWidget:
    #This method loads the XML file and autoconnects the signals
    def initialize(self, glade_file, widget_name):

        #initialize variables
        self.widgets = GladeXML(glade_file, widget_name)
        callbacks = {}

        #find and store methods as bound callbacks
        class_methods = self.__class__.__dict__
        for method_name in class_methods.keys():
            method = class_methods[method_name]
            if type(method) == types.FunctionType:
                callbacks[method_name] = new.instancemethod(
                                         method, self, self.__class__)
        self.widgets.signal_autoconnect(callbacks)
Simply use this as the base class of your GLADE window, and just define the signal handlers as regular methods. In your __init__ method, you need to call self.initialize("yourfile.glade", "YourGLADEWindowName").

Here's an example where arguments other than the widget are passed to the signal handler (note the tuple for handling clicks to the ok button):

 wTree2 = libglade.GladeXML("somefile.glade","proxy1")
 proxywidget = wTree2.get_widget("proxy1")
 id=1
 dic= {"on_cancel_clicked": proxywidget.destroy,
       "gtk_widget_destroy": proxywidget.destroy,
       "on_ok_clicked": ( handle_ok_clicked, wTree2,id)}
 wTree2.signal_autoconnect (dic)
Then the handler would be defined like so:
 def handle_ok_clicked(self,widget,name,wTree2,widgetid):
Last but not least read this tutorial: [patrick.wagstrom.net]

22.5. I'm using Gnome and libglade, but some widgets don't work properly.

This can happen with quite a few widgets (though a crash is more likely, as you can see from the last faq). The example posted to the mailing list recently refers to GnomeDateEdit - it was being made available (using GladeXML's get_widget() call) as a gtk.HBox. What could it be?

When using Gnome and libglade, you MUST import gnome.ui before doing any GladeXML parsing. Failing to do that means gnome will never be initialized and libglade will just Do Bad Things<tm>

22.6. When I invoke GladeXML() or glade.XML() all the widgets in my gladefile are displayed!

This is the correct behaviour with libglade, since all it does it render widgets as specified in the gladefile. What you need to do is set them as non-visible (in glade, the Properties dialog, Common tab contains a "Visible" toggle button. Push it).

Normally, you want to make all *top-level* widgets in your gladefile non-visible. The child widgets should be visible - this way, you only need to show/hide the toplevel to show the whole window, which is what you usually want.

22.7. How do I create and use a custom Glade widget?

Ross Burton wrote a patch for custom widget support, which has been integrated into PyGTK-2. A working example follows.

        import gtk
        import gtk.glade

        def create_source_cd_dropdown():
            return gtk.Label("source")

        gtk.glade.set_custom_widget_callbacks(locals())
        glade = gtk.glade.XML("cd-copier.glade")
        window = glade.get_widget("window")
        window.show_all()
        gtk.main()
Note that the glade file must define the proper callback name for the custom widget; in this case, create_source_cd_dropdown. The important call is gtk.glade.set_custom_widget_callbacks(), which takes a dictionary of function names->functions (which is why locals() works in the example).

The above method is deprecated in recent versions of pygtk.

The new API uses the method gtk.glade.set_custom_handler, which allows you to treat widget creation more dynamically if you wish.The set_custom_handler API works as follows:

    def my_handler (glade, function_name, widget_name, str1, str2, int1 , int2):
        # create your widget based on our arguments...
        return a_custom_widget

    gtk.glade.set_custom_handler(my_handler)
The following example, adapted from SimpleGladeApp.py in Sandino Flores Moreno's SimpleGladeApp.py shows how to use set_custom_handler to allow you to create custom handler constructors simply by naming class methods with the constructor names.

IMPORTANT: The call to gtk.glade.set_custom_handler() (as well gtk.glade.set_custom_widget_callbacks()) must come before the load of any Glade widget (by calling gtk.glade.XML()). The reason is that Glade needs to call the handlers when processing the XML file. The handlers are used to construct widgets, which happens at construction-time.

 class MyGladeApp:

     def __init__ (self):
         gtk.glade.set_custom_handler(self.get_custom_handler)
         self.glade = gtk.glade.XML('/path/to/gladefile.glade')
     ...

     def get_custom_handler(self, glade, function_name, widget_name,
			str1, str2, int1, int2):
	"""
	Generic handler for creating custom widgets, used to
	enable custom widgets.

	The custom widgets have a creation function specified in design time.
	Those creation functions are always called with str1,str2,int1,int2 as
	arguments, that are values specified in design time.

	This handler assumes that we have a method for every custom widget
        creation function specified in glade.

        If a custom widget has create_foo as creation function, then the
	method named create_foo is called with str1,str2,int1,int2 as arguments.
	"""
	handler = getattr(self, function_name)
	return handler(str1, str2, int1, int2)

22.8. How do I retrieve the ID of a signal connection made by signal_autoconnect?

This is currently not possible via the libglade API. However, you can avoid using autoconnect for the specific signals you require the ID, and connect() manually, storing the ID returned.

22.9. My libglade files have widgets that don't show up in the GladeXML tree!

"I seem to be having some trouble with libglade for glade files larger than about 230K. libglade cannot seem to find widget names for widgets near the end of a file this big. If I chop the end off the file and put it in a new file (fun with vi), then things work o.k. from the new file."

Do you have repeated widget names? That is usually the cause of these problems. Try doing a grep for "<name>" in the glade file, and look for duplicates.

It has been reported that reordering the widgets in the glade file may work around this problem when you are sure there are no duplicate widgets. (But why are you using glade instead of Gazpacho by now?)

22.10. When I load a glade file in GladeXML I get evil warnings about GnomeApp and a crash!

If you are using libglade to import your glade file, and you get something like:

 GnomeUI-CRITICAL **: file gnome-app.c: 
    line 208 (gnome_app_new): assertion `appname != NULL' failed.
 Gtk-WARNING **: invalid cast from (NULL) pointer to `GnomeApp'
it means you have GNOME widgets in your libglade app but forgot to import gnome.ui and initialize it (using the gnome-python module). However, this could happen by mistake - you might not be intentionally requiring GNOME. If you are only using GTK+ and don't want GNOME:

 *NOTE* STOCK ICONS ARE GNOME-ONLY IN GTK+ 1.2!
 YOUR BUTTONS SHOULD NOT USE THEM IF YOU DON'T WANT TO REQUIRE GNOME!
If you are using GNOME, you need to:

 import gnome.ui    
 gnome.init("programname", "version")
before you try and instantiate a GladeXML object, or you will get crashes, even in PyGTK 0.6.11 (though i'll try and fix this soon).

22.11. How do I produce or reuse a [portion of a] widget tree in glade?

You can create as many widget trees as you like based on the same glade XML content -- and libglade even caches xml parse trees automatically. You can also grab portions of widget trees by supplying a second parameter to your XML() call specifying the name of the toplevel widget you want.

The example below creates 10 identical dialogs:

  for i in range(10):
      xml = gtk.glade.XML("foo.glade", "my-window")
      win = xml.get_widget("my-window")
      win.show()
You can also get portions of windows and place them inside other widgets in runtime.

  xml = gtk.glade.XML("foo.glade", "my-vbox")
  vbox = xml.get_widget("my-vbox")
  win = gtk.Window()
  win.add(vbox)
  win.show()
You can experiment using reparent(), add() and remove() to compose your interface dynamically, reusing both code and glade XML. The only thing to remember is to make the windows not visible by default, as per FAQ 22.6

NB: The only thing to watch out for is keyboard accelerators, which need to be attached to the main window. This, at least in PyGTK 0.6, was a non-trivial task.

22.12. How can I get a new instance of a widget defined in a glade file?

The trick here lies in the root parameter given to the gtk.glade.XML constructor, which has this signature:

  PyGladeXMLObject = gtk.glade.XML(fname, root, domain)
where usually root and domain default to None. (Refer to the libglade reference for details).

root points to the widget from which the PyGladeXML object will start to be built. Thus, if you have a widget with an id such as "label6" and you need a new copy of it you would create a new PyGladeXML object using the glade file as fname and the widget's id as the root parameter.

This is better shown with an example:

 >>> import pygtk
 >>> pygtk.require('2.0')
 >>> import gtk
 >>> gladeXML = gtk.glade.XML("mygladefile.glade") # first 
 >>> print gladeXML
 <gtk.glade.XML object (PyGladeXML) at 0xd8d990>
 >>> label6a = gtk.glade.XML.get_widget(gladeXML, "label6")
 >>> print label6a
 <gtk.Label object (GtkLabel) at 0xf5b030>
 >>> label6b = gtk.glade.XML.get_widget(gladeXML, "label6")
 >>> print label6b
 <gtk.Label object (GtkLabel) at 0xf5b030>
 >>> gladeXML2 = gtk.glade.XML("mygladefile.glade", "label6")
 >>> print gladeXML2
 <gtk.glade.XML object (PyGladeXML) at 0xef22b0>
 >>> newlabel6 = gtk.glade.XML.get_widget(gladeXML2, "label6")
 >>> print newlabel6
 <gtk.Label object (GtkLabel) at 0xf5a7d8>
As we can see, label6a and label6b are the same object, while newlabel6 is a new instance of the "label6" widget.

22.13. Tabs in Notebook don't show up!

Either you have set the number of pages to 0 or you have empty notebook pages! Libglade has problems with empty pages. One workaround is to just put an empty hbox in the pages.

you might have got this message:

(gtk_notebook_set_tab_label): assertion `GTK_IS_WIDGET (child)' failed

22.14. How do I create and use a custom Builder widget?

migrating from glade to Builder comes out as a very simple thing. The harder part is understanding... how simple it is! the tricky way libglade allowed to add custom widgets (see FAQ 22.7) is now completely gone away.

You are just supposed to import in the module that instantiates the Builder the custom widget you need. Suppose you have an xml as the following one:

  xml = '''<?xml version="1.0"?>
  <interface>
    <object class="GtkWindow" id="window1">
      <property name="visible">True</property>
      <child>
        <object class="Test" id="test1">
          <property name="label" translatable="yes">Stop</property>
          <property name="visible">True</property>
        </object>
      </child>
    </object>
  </interface>'''
that refers to object of class Test defined as follows:

  class Test(gtk.Button):
      __gtype_name__ = 'Test'
All you need to do to render it will be to import test before adding xml definition:

   from mytest import Test

   b = gtk.Builder()
   b.add_from_string(xml)
In the beginning I experimented problems since one of my widgets emitted a signal during __init__. It was not difficult to fix it. The next question addresses the way to make glade read and display your custom widgets

22.15. How can I make glade to know my custom PyGTK widgets?

Official documentation is here: [library.gnome.org] . You may find it clear enought, I didn't... I used instead this post: [forum.promotux.it]

Glade, since rel 3.7 has a plugin that allows to use widgets directly created in PyGTK. This means it can

 * show the widgets in the left pane to choose from, possibily split in different "groups"
 * introspects the widgets to add signals and properties
 * renders them correctly 
this process need the following steps:

 a. create a catalog
 b. create a python module (below: sqlkitplugin.py) that will be imported by the glade's python plugin 
    at run time to import Widget's definitions
 c. export GLADE_CATALOG_PATH that must point to a directory where the catalog is found (file with extension .xml)
As an example, here is a catalog (sqlkit-catalog.xml):

  <glade-catalog name="sqlkitplugin" library="gladepython" domain="glade-3" depends="gtk+">
  <init-function>glade_python_init</init-function>

   <glade-widget-classes>
     <glade-widget-class title="The Test" name="TestField" generic-name="test"/>
     <glade-widget-class title="The Container" name="TestBox" generic-name="cont"/>
   </glade-widget-classes>

   <glade-widget-group name="sk-fields" title="SqlKit fields">
     <glade-widget-class-ref name="TestField"/>
   </glade-widget-group>
   <glade-widget-group name="sk-boxes" title="SqlKit containers">
     <glade-widget-class-ref name="TestBox"/>
   </glade-widget-group>
  </glade-catalog>
Note that the Python interpreter of the plugin must be able to import the module with all the custom widgets so that if this module is not in the directory of the catalog you may need to set PYTHONPATH as well.

The init function 'glade_function_init' will look for the module with a name as declared in the glade catalog's name (sqlkitplugin in the example).

The catalog as described above will add 2 groups of widgets in the left pane


23. Miscellaneous questions

23.1. Why does ancient PyGTK versions segfault with Python 2.2?

Ancient versions of pygtk (0.6.x) will segfault with Python 2.2 if you turn on pymalloc support when compiling python. A build of python without PyMalloc will work fine with pygtk. This is fixed in 0.6.10.

The fix is to do a search and replace s/PyMem_DEL/PyObject_DEL/ in the pygtk sources.

Thanks go to Dave Wallace for tracking this down.

23.2. Are there any helpful tools when developing with PyGTK?

Yes, a number.

    def dirpat(o, pat):
        """like dir, but only return strings matching re pat"""
        import re
        names = dir(o)
        pat = re.compile(pat)
        return [x for x in names if pat.search(x) is not None]

 >>> import gtk
 >>> gtk.DI <Press TAB !>
 gtk.DIALOG_DESTROY_WITH_PARENT  gtk.DIR_LEFT
 gtk.DIALOG_MODAL                gtk.DIR_RIGHT
 gtk.DIALOG_NO_SEPARATOR         gtk.DIR_TAB_BACKWARD
 [...]

23.3. How do I find out the current X and Y position of my mouse?

Every event object generated contains the x and y attributes which indicate the current pointer position. You need to find a relevant signal to generate it. So something like:

 def on_w_motion(event):
  print "Mouse position: X:%s Y:%s" % (event.x, event.y)

 w = gtk.Window()
 e = gtk.EventBox()
 w.add(e)
 e.connect("motion_notify_event",on_w_motion)
 w.show_all()
 gtk.main()
Will generate the information when you have the mouse button clicked and dragged upon the client area.

23.4. Are there any tips for UI designers?

There is a lot of online material on designing usable interfaces, so it's really a matter of looking into it.

[www.asktog.com] is a real nice reference site by Bruce Tognazzini. His column on Fitts' law is particularly interesting: [www.asktog.com]

[www.useit.com] is Jakon Nielsen's site. Nielsen is the usability guru, but he has been concentrating on the web and appliances lately, so you might not see much conventional computer UI advice.

You should spend some time reading the HCI guidelines for the relevant projects. Reading other UI specs is interesting because you get a feeling of what research led to what.

Books I can recommend are:

23.5. Why does my X selection disappear when my window dies?

If you have selected some text in an entry, and your application dies, you will notice that the text is "removed" from the X clipboard. James clarifies:

X selection handling is an asynchronous operation. When a user "copies" some text to the clipboard, the text doesn't necessarily get copied anywhere. Instead, the application claims the CLIPBOARD selection. When another app wants to paste the contents of the clipboard, they request the contents of the CLIPBOARD selection in a particular format (eg. UTF8 text, html, an image, etc), which sends a message to the first app. The first app then sends the data back in the requested format. This has the benefit that no data is sent over the wire until it is requested, and content type negotiation can be performed.

As you can see, this model breaks down when the selection owner window gets destroyed. There are some tools to work around this problem such as xclipboard. The downside to xclipboard is that every time the CLIPBOARD selection is claimed, the data gets requested by xclipboard, and xclipboard will only store the data in one format.

23.6. When compiling PyGTK, I get a bunch of weird "Could not write method ..." messages!

While building pygtk we get a whole lot of these messages:

 Could not write method GtkTextIter.forward_find_char: No ArgType 
       for GtkTextCharPredicate
 Could not write method GtkTextIter.backward_find_char: No ArgType 
       for GtkTextCharPredicate
 Could not write method GtkAccelGroup.connect: No ArgType for 
       GClosure*
 Could not write method GtkAccelGroup.connect_by_path: No ArgType 
       for GClosure*
 [...]
These are expected and not a serious problem. They are generated by the automatic code generation stuff and are more indicative of TODO items than real problems.

23.7. Is there a way to get version information from pygtk?

For all versions of pygtk beyond 0.6.8, there are two attributes of the gtk module that provide version information.

Use gtk.pygtk_version which is a tuple with three items, (major, minor, micro):

  if gtk.pygtk_version >= (1,99,12):
      ...
If you want to check for the Gtk+ version, use gtk.gtk_version:

  if gtk.gtk_version >= (2,0,5):
      ...

23.8. How do I beep the speaker?

Easy:

 gtk.gdk.beep()
Note that it needs to be called inside the gtk mainloop for it to run immediately; if you invoke it in interactive mode, it only beeps when you exit python.

23.9. Is there a way to grab the keyboard from X (like XGrabKey())?

XGrabKey grabs the input so that no other application (including the window manager) can get any keystrokes or insert them with XSendEvent. This is sometimes done for entering passwords or so to make it more difficult to sniff the keystrokes or manipulate them. In PyGTK, you can use something like:

 gdk_win = window.window
 gdk_win.keyboard_grab(1, 0) # owner_events and time, respectively
                             # XXX: is this the way?
In gtk+'s gdk.c you can see keyboard_grab() calls XGrabKeyboard. 'man XGrabKeyboard' is your friend in understanding if this does what you want.

Russ Nelson originally asked this, and Markus Schaber offered this tip.

23.10. When wrapping a widget into a new Python extension, I get undefined symbols on importing it!

Ha shao reported the following comment to a problem reported on the mailing list when wrapping GtkSourceView:

 I import gtksourceview, kablam, here is what I get:

  /usr/lib/python2.2/site-packages/gtksourceviewmodule.so: 
     undefined symbol: gtk_source_buffer_get_tag_end
To fix this, make sure you include the header file which has gtk_source_buffer_get_tag_end defined and make sure that you link against the library in which the missing symbol is defined, in this case libgtksourceview.

23.11. Does VTK support PyGTK?

VTK, the Visualization Toolkit [public.kitware.com] is an open source 3D visualization system. If you download the VTK distribution and look in Wrapping/Python/vtk/gtk/ you'll see a class GtkVTKRenderWindow that contains a demo in the __main__ section at the bottom. A more verbose description is available at [www.daa.com.au]

23.12. How do I create a GdkRectangle?

GTK+ defines a simple graphical type called GdkRectangle, which is described in more detail at [developer.gnome.org]

Instead of providing the widget as a Python class, PyGTK allows one to use a tuple wherever a GdkRectangle is expected. You can simply pass in a sequence of 4 integers of the form (x, y,width, height), and it will be interpreted as a rectangle.

23.13. When I create a gnome Druid, the first and last page are blank.

Rob Brown-Bayliss:

The first and last pages need to have their show() method called, I just did this:

 wtree = glade.XML("glade_file.glade")
 start_page = wtree.get_widget("start_page")
 start_page.show()
 finish_page = wtree.get_widget("finish_page")
 finish_page.show()
I am not sure why these two pages need the show() method call and the other pages in the druid dont?

23.14. I disable text or graphics on my GtkToolbar, or the time in my GnomeDateTime, and they still show up, or, why is show_all() considered harmful?

Certain composite widgets (in other words, widgets formed by composing other widgets together in a container) which provide functionality for disabling parts of their display implement this using a simple hide() call on their subwidgets.

If you use show_all() to display them (either calling show_all() on them or on one of their parent containers) then the subwidget that was originally hidden will be shown again.

Moral of the story: avoid using show_all() when possible; it may produce unexpected results.

23.15. I'm writing a C extension that uses PyGTK. How do I acess a PyGTK object's C counterparts and vice-versa?

Tim Evans provides a simple example based on a skeleton C extension.

  #include <pygobject.h>           
  #include <pygtk.h>    
  /* global variable declared at top of file */
  static PyTypeObject *PyGObject_Type=NULL;    
  /* ... */                                
  void initfoo(void)
  {                 
      PyObject *module;
      Py_InitModule("foo", foo_functions);

      init_pygobject();
      init_pygtk();
      module = PyImport_ImportModule("gobject");
      if (module) {
          PyGObject_Type =
           (PyTypeObject*)PyObject_GetAttrString(module, "GObject");
          Py_DECREF(module);
      }
  }    

  pygobject_new((GObject*) widget);             
  /* If a python wrapper for 'widget' already exists, it will
    incref and return that, otherwise it will create a new
    python wrapper object. */
  was passed as an argument, do something like this:

  PyGObject *py_widget;                         
  GtkWidget *widget;   

  if (!PyArg_ParseTuple(args, "O!", PyGObject_Type, &py_widget))
      return NULL;
  widget = GTK_WIDGET(py_widget->obj);
You might also want to look at the 'codegen' stuff that pygtk uses to automatically generate most of the pygtk interface. Once you get used to using it, it's much easier to use than writing everything by hand.

23.16. How do I change the font and colour of some GnomePrint text?

To change font, try calling

  gnomeprint.font_find_closest_from_weight_slant(family(string),
                                                 weight(enum), 
                                                 italic(gboolean), 
                                                 size(float))
For the weight enumeration, there are FONT_* constants defined in the gnomeprint module. Try help(gnomeprint). An example is available at [cvs.gnome.org]

You can't change the color of a gnomeprint.Font. You should change the color of your gnomeprint.Context instead, with

  gnomeprint.Context.setrgbcolor(r,g,b).  
r/g/b are floating point values in the range 0.0 - 1.0

23.17. Is there a way to query for the current screen size?

Yes. Use gtk.gdk.screen_width() and gtk.gdk.screen_height() for the current screen width and height, respectively.

The following code will instead get the effective screen space available (net of panels and docks):

w = gtk.gdk.get_default_root_window()

p = gtk.gdk.atom_intern('_NET_WORKAREA')

width, height = w.property_get(p)[2][2:4]

More info on WORKAREAs can be found at [standards.freedesktop.org]

23.18. When dragging and dropping, Netscape/Firefox/etc and gedit/native gtk apps don't behave the same. Why?

Each application indicates what drag context targets it supports. It appears that Firefox and Netscape specify MIME text context targets:

 text/_moz_htmlcontext
 text/_moz_htmlinfo
 text/html
 text/unicode
 text/plain
while gedit offers text context targets:

 GTK_TEXT_BUFFER_CONTENTS
 UTF8_STRING
 COMPOUND_TEXT
 TEXT
 STRING
To handle both you need to enable them in your drag destination. For a TreeView, for instance, you might do:

 tree.enable_model_drag_dest([('text/plain',0,0),
                              ('TEXT', 0, 1),
                              ('STRING', 0, 2),
                              ('COMPOUND_TEXT', 0, 3),
                              ('UTF8_STRING', 0, 4)],
                               gtk.gdk.ACTION_DEFAULT |
                               gtk.gdk.ACTION_COPY |
                               gtk.gdk.ACTION_MOVE)
To find out what drag targets a certain selection supports, you can use this short script:

 def gettargets(wid, context, x, y, time):
   for t in context.targets:
       print t
   return True

 w = gtk.Window()
 w.set_size_request(100, 100)
 w.drag_dest_set(0, [], 0)
 w.connect('drag_motion', gettargets)
 w.show_all()

 gtk.main()
(John Finlay)

23.19. What do you see as the flaws in the Minimalist Programme?

Transformational grammar is cognitively implausible and syntactocentric. I prefer multi-stratal versions of generative unification models.

(Joe Geldart)

23.20. How do I update a progress bar and do some work at the same time

You have created a progress bar inside a window, then you start running a loop that does some work:

    while work_left:
        ...do something...
        progressbar.set_fraction(...)
You will notice that the window doesn't even show up, or if it does the progress bar stays frozen until the end of the task. The explanation is simple: gtk is event driven, and you are stealing control away from the gtk main loop, thus preventing it from processing normal GUI update events.

The simplest solution consists on temporarily giving control back to gtk every time the progress is changed:

    while work_left:
        ...do something...
        progressbar.set_fraction(...)
        while gtk.events_pending():
            gtk.main_iteration()
Notice that with this solution, the user cannot quit the application (gtk.main_quit would not work because of new loop [gtk.main_iteration()]) until your heavy_work is done.

Another solution consists on using gtk idle functions, which are called by the gtk main loop whenever it has nothing to do. Therefore, gtk is in control, and the idle function has to do a bit of work. It should return True if there's more work to be done, otherwise False.

The best solution (it has no drawbacks) was pointed out by James Henstridge. It is taking advantage of python's generators as idle functions, to make python automatically preserve the state for us. It goes like this:

    def my_task(data):
        ...some work...
        while heavy_work_needed:
            ...do heavy work here...
            progress_label.set_text(data) # here we update parts of UI
            # there's more work, return True
            yield True
        # no more work, return False
        yield False

   def on_start_my_task_button_click(data):
        task = my_task(data)
        gobject.idle_add(task.next)
The 'while' above is just an example. The only rules are that it should yield True after doing a bit of work and there's more work to do, and it must yield False when the task is done.

More on generators:

Generators are objects that are defined as functions, and when called produce iterators that return values defined by the body of the function, specifically yield statements.

The neat thing about generators are not the iterators themselves but the fact that a function's state is completely frozen and restored between one call to the iterator's next() and the following one. This is just the right thing we need to turn our functions into pseudo-threads, without actually incurring the wrath of the gods of software. More: [www.gnome.org]

23.21. How can I package my gnome-python application using autotools?

I recently packaged a GNOME application written in Python with the autotools, which I chose over distutils purely as a learning exercise. If you fancy giving autotools a go you may find it to be a useful example (including glade, GConf, scrollkeeper, .desktop file and pixmap installation):

[bandsaw.sourceforge.net]

I found the GNOME Blog autotools files provided a good starting point.

The one thing I didn't find online was up to date information on setting up autogen.sh for use with GNOME. I was targetting GNOME 2.6 and ended up following largely out of date documentation. The correct approach is to checkout the latest version of gnome-common from the GNOME CVS server (don't use the 2.4.0 version that is packaged with many distributions; it is far too old to provide the right tools) and modify an existing autogen.sh to suit your needs. Band Saw's should be fine (for GNOME 2.6 at least).

23.22. How can I extend PyGTK using gtkmm/C++ ?

If you want to extend pygtk with gtkmm that means C++. Almost everything is equivalent to the C-stuff (refer to FAQ 23.15), except:

   int argc = 0;
   char **argv = NULL;
   Gtk::Main kit(argc, argv)
This way the important internals of gtkmm are initialized. Although it may seem that just calling the static function Gtk::Main::init_gtkmm_internals() would be sufficient it is NOT.

   public PyObject* get_pyobject()
   {
     return pygobject_new((GObject*)gobj());
   }

   hbox = gtk.HBox()
   widget = MyCustomWidget()
   widget.thisown = 0
   hbox.pack_start(widget.get_pyobject())
That's it. Don't forget the 'thisown=0' if you don't want to end up with an segmentation fault because if you'd forget then Python would delete the object as soon as your function ended (thus also leaving the function's namescope).

In case you still want to have Python delete the object at the end you have the option to instantiate it using the global or object's self namescope. Normally this shouldn't be necessary because gtk takes care of the widgets memory management.

23.23. How do I debug a PyGTK application without an interactive session?

If you need to debug an application but are unable to obtain an interactive session to trace it from (for instance, if it crashes at startup or shutdown), you can use the following recipe, contributed by Gustavo Carneiro:

1. Install Xnest;

2. Add a test user to your system;

3. Run a nested window GDM session (in System Tools);

4. Login as the test user;

5. In your own user session:

6. In the test user nested session, trigger the error.

7. View the python backtrace in your shell, or trigger an interrupt in gdb to capture a stack trace.

23.24. Can GTK know the mouse position outside of GTK Application?

To get the position relative to a given window

  gdkwindow.get_pointer() 
If you need the absolute position, call get_pointer on the root window of the current screen:

  rootwin = widget.get_screen().get_root_window()
  x, y, mods = rootwin.get_pointer()
If you call get_pointer() on some other GdkWindow, the result will be relative to the position of that window (so you can get negative coordinates)

(James Henstridge)

23.25. Is widget.set_property('visible', False) the same as widget.hide() ?

Yes it is.

set_property('visible', True) is also the same as widget.show()

23.26. How do I change window properties involving atom values?

Whereas in C you would have to take the address of the integer containing the atom as property value, in PyGTK is simpler; you just have to pass the atom itself inside a sequence.

An example follows:

 desktop_type = gtk.gdk.atom_intern("_NET_WM_WINDOW_TYPE_DESKTOP", False)
 win = gtk.Window()
 win.show()
 win.realize()
 win.window.property_change(gtk.gdk.atom_intern("_NET_WM_WINDOW_TYPE", False),
                            gtk.gdk.atom_intern("ATOM", False), 32,
                            gtk.gdk.PROP_MODE_REPLACE,
                            [desktop_type])
Note: don't try to use struct.pack("I", atom)!

(Gustavo Carneiro)

23.27. How do I port a GObject/Glib based C application to PyGTK?

Initialization

  gtk_init(&argc, &argv);
...becomes

  import gtk
Constructors:

  GtkWidget *button;
  button = gtk_button_new();
...becomes

  button = gtk.Button()
Methods are similar:

  gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(button));
...becomes

  window.add(button)
Signals:

  g_signal_connect(G_OBJECT(button), "clicked",
                   G_CALLBACK(button_clicked_cb), NULL);
...becomes

  object.connect("clicked", button_clicked_cb)
Other considerations:

23.28. How can I distribute gtkspell, trayicon (eg. modules that do not depend on gnome) so my application will take advantage of those but the user won't have to install gnome-python-extras?

You must get the source files and distribute those with your program. You can use this Makefile:

	# Set the C flags to include the GTK+ and Python libraries
	PYTHONVER = `python -c 'import sys; print sys.version[:3]'`
	CFLAGS = `pkg-config --cflags gtk+-2.0 pygtk-2.0` -fPIC -I/usr/include/python$(PYTHONVER) -I.
	LDFLAGS = `pkg-config --libs gtk+-2.0 pygtk-2.0`

	all: trayicon.so gtkspell.so

	# Build the shared objects
	trayicon.so: trayicon.o eggtrayicon.o trayiconmodule.o
		$(CC) $(LDFLAGS) -shared $^ -o $@

	gtkspell.so:
		$(CC) $(CFLAGS) $(LDFLAGS) `pkg-config --libs --cflags gtkspell-2.0` -shared gtkspellmodule.c $^ -o $@

	# The path to the GTK+ python types
	DEFS=`pkg-config --variable=defsdir pygtk-2.0`

	# Generate the C wrapper from the defs and our override file
	trayicon.c: trayicon.defs trayicon.override
		pygtk-codegen-2.0 --prefix trayicon \
		--register $(DEFS)/gdk-types.defs \
		--register $(DEFS)/gtk-types.defs \
		--override trayicon.override \
		trayicon.defs > $@

	# A rule to clean the generated files
	clean:
		rm -f trayicon.so *.o trayicon.c gtkspell.so *~  

	.PHONY: clean

23.29. How do I configure emacs to be used with pygtk?

People seem to be using python mode, abbrevs, and perhaps dynamic-completion-mode.

To turn on Abbrev mode, type:

  M-x abbrev-mode
To save the abbrevs you have currently defined to a file, type:
  M-x write-abbrev-file [RET] ~/.pygtk-abbrevs [RET]
Later, in a new session you can read the abbrevs from the file typing:
  M-x read-abbrev-file [RET] ~/.pygtk-abbrevs [RET]
Does anybody have a nice list of pygtk abbrevs, to be used in a ~/.abbrevs_defs as .pygtk-abbrevs instead of having some buffers open with pygtk code?

This abbrevs keybinding configuration seems to be quite useful too for some people:

  ;; code completion
  (global-set-key (quote [S-iso-lefttab]) (quote dabbrev-expand))
  (global-set-key (quote [S-tab]) (quote dabbrev-expand))
  (global-set-key (quote [f9]) (quote dabbrev-completion))

23.30. Q_() is not available in my pygtk app. How to use Qualified translatable strings?

glib 's gstrfuncs.c

has:

 G_CONST_RETURN gchar *
 g_strip_context  (const gchar *msgid, 
		  const gchar *msgval)
 {
  if (msgval == msgid)
    {
      const char *c = strchr (msgid, '|');
      if (c != NULL)
	return c + 1;
    }

  return msgval;
 }
which is defined as #define Q_(String) g_strip_context ((String), gettext (String))

now this is done in python this way (apart from the | check which I did not implement):

 def Q_(s):
   s = _(s)
   if s[0] == '?':
       s = s[s.find(':')+1:] # remove ?abc: part
   return s
Now some theory..

in your code you do:

 menu.name = Q_('?vcard:Unknown')
 special.name = Q_('?os:Unknown') 
so pot will have:

 #: vcard.py:123 
 msgid "?vcard:Unknown" 
 msgstr "" 

 #: vcard.py:126
 msgid "?os:Unknown" 
 msgstr ""
translators get the idea how to translate Unknown and then can either do their translation either by including the ?zzz: part or without

this helps them so then now the context but moreover the know that gender (masculine, feminine, neutral)

thanks to piman, nkour

23.31. How to get the path to the file(s)/folder(s) that was dropped (by drag 'n' drop) in my application? [using selection.data]

You connect like that:
 widget.connect('drag_data_received', on_drag_data_received)
and in your callback you do:

 def on_drag_data_received(widget, context, x, y, selection, target_type, timestamp):
	uri = selection.data.strip('\r\n\x00')
	uri_splitted = uri.split() # we may have more than one file dropped
	for uri in uri_splitted:
		path = get_file_path_from_dnd_dropped_uri(uri)
		if os.path.isfile(path): # is it file?
			data = file(path).read()
			print data

 def get_file_path_from_dnd_dropped_uri(uri):
	# get the path to file
	path = ""
	if uri.startswith('file:\\\\\\'): # windows
		path = uri[8:] # 8 is len('file:///')
	elif uri.startswith('file://'): # nautilus, rox
		path = uri[7:] # 7 is len('file://')
	elif uri.startswith('file:'): # xffm
		path = uri[5:] # 5 is len('file:')

	path = urllib.url2pathname(path) # escape special chars
	path = path.strip('\r\n\x00') # remove \r\n and NULL

	return path
Real life example:

 import gtk
 import urllib
 import os

 TARGET_TYPE_URI_LIST = 80
 dnd_list = [ ( 'text/uri-list', 0, TARGET_TYPE_URI_LIST ) ]

 def get_file_path_from_dnd_dropped_uri(uri):
	# get the path to file
	path = ""
	if uri.startswith('file:\\\\\\'): # windows
		path = uri[8:] # 8 is len('file:///')
	elif uri.startswith('file://'): # nautilus, rox
		path = uri[7:] # 7 is len('file://')
	elif uri.startswith('file:'): # xffm
		path = uri[5:] # 5 is len('file:')

	path = urllib.url2pathname(path) # escape special chars
	path = path.strip('\r\n\x00') # remove \r\n and NULL

	return path

 def on_drag_data_received(widget, context, x, y, selection, target_type, timestamp):
	if target_type == TARGET_TYPE_URI_LIST:
		uri = selection.data.strip('\r\n\x00')
		print 'uri', uri
		uri_splitted = uri.split() # we may have more than one file dropped
		for uri in uri_splitted:
			path = get_file_path_from_dnd_dropped_uri(uri)
			print 'path to open', path
			if os.path.isfile(path): # is it file?
				data = file(path).read()
				#print data

 w = gtk.Window()
 w.connect('drag_data_received', on_drag_data_received)
 w.drag_dest_set( gtk.DEST_DEFAULT_MOTION |
                  gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_DROP,
                  dnd_list, gtk.gdk.ACTION_COPY)

 w.show_all()
 gtk.main()

23.32. How to get coordinates relative to X11 for a widget that has no window of its own?

Try this code:

 # here I get the coordinates of the button relative to
 # window (self.window)
 button_x, button_y = self.actions_button.allocation.x, self.actions_button.allocation.y

 # now convert them to X11-relative
 window_x, window_y = self.window.window.get_origin()
 x = window_x + button_x
 y = window_y + button_y
now x, y hold the top-left corner of button and those x, y are X11 and not window-relative.

Something more advanced but hopefully useful:

 menu.popup(None, None, self.position_actions_menu, 1, 0)
 menu.show_all()

 def position_actions_menu(self, menu):
	# here I get the coordinates of the button relative to
	# window (self.window)
	button_x, button_y = self.actions_button.allocation.x, self.actions_button.allocation.y

	# now convert them to X11-relative
	window_x, window_y = self.window.window.get_origin()
	x = window_x + button_x
	y = window_y + button_y

	# now move the menu below the button
	y += self.actions_button.allocation.height

	push_in = True # push_in is True so all menu is always inside screen
	return (x, y, push_in)

23.34. How can I use gtk.binding_entry_add (and why it's better than keypress in most cases)

If in your program you have a textview and you catch keypress signal and do checks on what key is pressed then you application will break some more advanced Input Methods such as [im-ja.sourceforge.net] .

It's because normal signals like 'key_press_event' are first catched by your application and then by the IM/GTK (and they are catched only if you do not return True). So you have to use bindings which are superior in most cases (NOTE: Bindings on a combination will never call your Callback if for the same combination a GTK default action exists). Those bindings need a signal-name, so you have to subclass so you can add those bindings only for that class:

	import gtk
	import gobject

	class MyTextView(gtk.TextView):
	    __gsignals__ = dict(
	        mykeypress = (gobject.SIGNAL_RUN_LAST | gobject.SIGNAL_ACTION,
	                  None, # return type
	                  (str,)) # arguments
	        )
        gobject.type_register(MyTextView)

	gtk.binding_entry_add_signal(MyTextView, gtk.keysyms.Return, 0, 'mykeypress', str, 'return')
	gtk.binding_entry_add_signal(MyTextView, gtk.keysyms.Home, gtk.gdk.CONTROL_MASK, 'mykeypress', str, 'ctrl+home')

	def activate_cb(tv, what):
	    print 'You pressed', what

	tv = MyTextView()
	tv.connect('mykeypress', activate_cb)
	w = gtk.Window()
	w.add(tv)
	w.set_default_size(400, 300)
	w.show_all()
	w.connect('destroy', gtk.main_quit)
	gtk.main()

Thanks to Gustavo and Muntyan

23.35. How can you set the tab / tabbing order?

Use: gtk.Container.set_focus_chain

Note: you can set the order, for direct children.

An example is here: [calmar.ws]

once the tab/tabbing order reaches the focus of the table2 (packed into the main table), the tab-chain of table2's children is active.

23.36. How do I acquire a screenshot of the whole screen?

Use the GDK Pixbuf API. Although it will only output to PNG and JPEG, the latter having an optional quality option passed as a dict with a quality value string of 0-100 to the gdk.Pixbuf save() method.

 # Either "png" or "jpeg"
 format = "jpeg"

 width = gtk.gdk.screen_width()
 height = gtk.gdk.screen_height()
 screenshot = gtk.gdk.Pixbuf.get_from_drawable(
              gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, width, height),
              gtk.gdk.get_default_root_window(),
              gtk.gdk.colormap_get_system(),
              0, 0, 0, 0, width, height)

 # Pixbuf's have a save method 
 # Note that png doesnt support the quality argument. 
 screenshot.save("screenshot." + format, format,  {"quality": "20"})
Warning: if you plan on running this code on a loop, or many times throughout the program, you might want to add the following code to avoid a big memory leak (considering the size of a bitmap of those proportions), as per a bug detailed here: [www.async.com.br]

 del screenshot
 gc.collect()

23.37. How do I create a throbber like the one in Firefox?

Easy, steal it from Firefox! Download the Firefox source and find the files Throbber.png and Throbber.gif (or do a Google Images search). Throbber.png is the static icon and Throbber.gif is the animated icon. Pack a gtk.Image with the static icon next to your menubar:

 hbox = gtk.HBox(expand=False)
 hbox.pack_start(menubar)
 self.throbber = gtk.Image()
 self.throbber.set_from_file('image_path/Throbber.png')
 hbox.pack_start(self.throbber, expand=False)
and create the animation:

 self.animation = gtk.gdk.PixbufAnimation('image_path/Throbber.gif')
Then all we need to do to get the throbber throbbing is load this animation into the Image:

 pixbuf = self.throbber.get_pixbuf() # save the Image contents so we can set it back later
 self.throbber.set_from_animation(self.animation)
 ...
 # then later to stop the animation just put the old contents back
 self.throbber.set_from_pixbuf(pixbuf)
Here's an example of using the throbber to show activity while we do some hard work in a thread:

 gobject.threads_init() # called somewhere at the top of your file

 def someActionCallback(self, *args):
     pixbuf = self.throbber.get_pixbuf()
     self.throbber.set_from_animation(self.animation)
     # make sure the throbbing starts now
     while gtk.events_pending():
         gtk.main_iteration()
     def call():
         try:
             # hard working code goes here
         finally: # make sure the throbbing stops whatever else happens
             gobject.idle_add(self.throbber.set_from_pixbuf, pixbuf)
     # start the hard work in a thread
     threading.Thread(target=call).start()
(See section 20 of this FAQ for more on using threads in PyGtk.)

23.38. How can I access data returned with a gpointer?

In some cases, for example in a callback function, you may get data as a gpointer instead of a python data type, making such data unreacheable from your python program. Although the gpointer data type provides no way of accesing the underlying pointer, there is a hack to do it using the gpointer's conversion to string and reach the data using the ctypes module.

Have a look at the following example, using the gtkmozembed widget. This function is the callback for the 'open_uri' widget signal. The second argument 'uri' should be a string, but all you'll get is a gpointer. The gpointer is converted to string to get the pointer value in [13:-1] characters as an hex number, which may be converted to an integer. Using ctypes this integer is typecasted to a pointer to c style string (c_char_p), which is converted to a python string by the value method.

 def mozilla_open_uri(widget, uri, *args):
     p=int(str(uri)[13:-1],16)
     url=ctypes.cast(p,ctypes.c_char_p).value
     print(url)
     return False

23.39. How do I acquire a screenshot of the active window?

I do not think this works in Windows since _NET_WM_* hints might not be supported there.

Use the GDK Pixbuf API. Although it will only output to PNG and JPEG, the latter having an optional quality option passed as a dict with a quality value string of 0-100 to the gdk.Pixbuf save() method.

 # Calculate the size of the whole screen
 screenw = gtk.gdk.screen_width()
 screenh = gtk.gdk.screen_height()

 # Get the root and active window
 root = gtk.gdk.screen_get_default()

 if root.supports_net_wm_hint("_NET_ACTIVE_WINDOW") and root.supports_net_wm_hint("_NET_WM_WINDOW_TYPE"):
        active = root.get_active_window()
        # You definately do not want to take a screenshot of the whole desktop, see entry 23.36 for that
        # Returns something like ('ATOM', 32, ['_NET_WM_WINDOW_TYPE_DESKTOP'])
        if active.property_get("_NET_WM_WINDOW_TYPE")[-1][0] == '_NET_WM_WINDOW_TYPE_DESKTOP':
         return False

        # Calculate the size of the wm decorations
        relativex, relativey, winw, winh, d = active.get_geometry() 
        w = winw + (relativex*2)
        h = winh + (relativey+relativex)

        # Calculate the position of where the wm decorations start (not the window itself)
        screenposx, screenposy = active.get_root_origin()
 else:
        return False

 screenshot = gtk.gdk.Pixbuf.get_from_drawable(gtk.gdk.Pixbuf(gtk.gdk.COLORSPACE_RGB, True, 8, w, h),
            gtk.gdk.get_default_root_window(),
            gtk.gdk.colormap_get_system(),
            screenposx, screenposy, 0, 0, w, h)

 # Either "png" or "jpeg" (case matters)
 format = "jpeg"

 # Pixbuf's have a save method 
 # Note that png doesnt support the quality argument. 
 screenshot.save("screenshot." + format, format,  {"quality": "20"})
Warning: if you plan on running this code on a loop, or many times throughout the program, you might want to add the following code to avoid a big memory leak (considering the size of a bitmap of those proportions), as per a bug detailed here: [www.async.com.br]

 del screenshot
 gc.collect()

23.40. Is g_utf8_collate and g_utf8_collate_key available in PyGTK?

g_utf8_collate and g_utf8_collate_key are two functions available in glib which compares strings using the correct locale.

They are not available in PyGTK, but don't worry you can just use the locale module to do the same thing;

  g_utf8_collate(mystr, mystr2) is the same as;
  locale.strcoll(mystr, mystr2)
and

  g_utf8_collate_key(mystr) is the same as;
  locale.strxfrm(mystr)
There's a third function in glib which is called g_utf8_collate_key_for_filename which doesn't have a similar implementation in python.

Remember to import pango or gtk for these functions to work properly.

23.41. How can I create a GObject from a memory address?

If you use ctypes or the dl module to access a function returning a GObject you need this boiler plate to access pyg_object_new:

 import ctypes
 import sys

 import gobject

 class _PyGObject_Functions(ctypes.Structure):
    _fields_ = [
        ('register_class',
         ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.c_char_p,
                           ctypes.c_int, ctypes.py_object,
                           ctypes.py_object)),
        ('register_wrapper',
         ctypes.PYFUNCTYPE(ctypes.c_void_p, ctypes.py_object)),
        ('register_sinkfunc',
         ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
        ('lookupclass',
         ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_int)),
        ('newgobj',
         ctypes.PYFUNCTYPE(ctypes.py_object, ctypes.c_void_p)),
        ]

 class PyGObjectCPAI(object):
    def __init__(self):
        PyCObject_AsVoidPtr = ctypes.pythonapi.PyCObject_AsVoidPtr
        PyCObject_AsVoidPtr.restype = ctypes.c_void_p
        PyCObject_AsVoidPtr.argtypes = [ctypes.py_object]
        addr = PyCObject_AsVoidPtr(ctypes.py_object(
            gobject._PyGObject_API))
        self._api = _PyGObject_Functions.from_address(addr)

    def pygobject_new(self, addr):
        return self._api.newgobj(addr)

 capi = PyGObjectCPAI()
 capi.pygobject_new(memory_address)
The opposite is much easier, you can get a reference to the memory address by using hash:

  address = hash(gobj)

23.42. How can integrate PyGTK with SDL / pygame ?

There are a couple of ways to do the integration;

* Inprocess

This method makes it possible to use pygame / SDL in the same process as your PyGTK application, eg you use PyGTK to construct the menus, buttons and windows, but pygame to draw parts of the interface.

* Out of process

This is more like a frontend to an already existing application, you decouple both of the applications (the gtk frontend and the pygame application).

This example will demonstrate the inprocess option, which is more attractive since it's easier to integrate the two frameworks together.

 import os

 import gobject
 import gtk
 import pygame

 WINX = 400
 WINY = 200

 window = gtk.Window()
 window.connect('delete-event', gtk.main_quit)
 window.set_resizable(False)
 area = gtk.DrawingArea()
 area.set_app_paintable(True)
 area.set_size_request(WINX, WINY)
 window.add(area)
 area.realize()

 # Force SDL to write on our drawing area
 os.putenv('SDL_WINDOWID', str(area.window.xid))

 # We need to flush the XLib event loop otherwise we can't
 # access the XWindow which set_mode() requires
 gtk.gdk.flush()

 pygame.init()
 pygame.display.set_mode((WINX, WINY), 0, 0)
 screen = pygame.display.get_surface()

 image_surface = pygame.image.load('foo.png')
 screen.blit(image_surface, (0, 0))

 gobject.idle_add(pygame.display.update)

 window.show_all()

 gtk.main()
There are two important things you have to notice; SDL_WINDOWID points to the Xwindow ID of the window you want to paint on, you need to create the window before drawing/accessing it, that's done with realize() and gtk.gdk.flush() The other is that you need to call pygame.display.update() at least once after the whole interface is constructed, we do this using gobject.idle_add in the example for simplicity, in a full blown application you need to process the SDL events and make sure that they interact with the gtk mainloop.

23.43. IDEs and editors with code completion support for PyGTK

[ Eclipse + Pydev ]
    1.- We assumed that you have installed or downloaded eclipse + pydev.

    2.- Click in Window --> Preferences --> Interpreter-Python

    3.- Watch gtk+ package is in "System PYTHONPATH"

    4.- In "Forced builtin libs", click in New, add "gtk", "gobject", "pango" and "atk"

    5.- Apply and, you're done
[ Ulipad ]

    Ulipad has code completion for pygtk by default.

    For download:
    svn co http://ulipad.googlecode.com/svn/trunk/ ulipad

    This create ulipad folder on your current path.
    For execute: "python Ulipad.py"
[ Pida ]

    Pida[1] is a IDE written in PyGTK that have two option as code editor: culebra or VIM. 
    Is integrated with Gazpacho[2], and Gazpacho is written in PyGTK too using kiwi[3] framework  
[1] [pida.co.uk] [2] [gazpacho.sicem.biz] [3] [www.async.com.br]

[ VIM 7 ]

    Is possible config to have PyGTK autocompletation in VIM 7: http://pida.co.uk/trac/wiki/ConfiguringVimForPython
[ Emacs ]

    It is possible to autocomplete PyGTK symbols in Emacs using the ropemacs package[1].

    In order to do this, you must:
    1. - Edit config of the rope project (using M-x rope-project-config or directly opening .ropeproject/config.py) and replace the line

    prefs['extension_modules'] = []

    with

    prefs['extension_modules'] = ['gtk._gtk', 'gobject._gobject', 'pango', 'atk']

    2. Remove file .ropeproject/globalnames from the root of your
 rope project if there is one.
[1] [rope.sf.net]

23.44. How can I embed a Jython application in PyGTK?

I'm glad you asked, it so happens I know how to do this.

On the Java side, you need to create an XEmbeddedFrame (or a Windows on if you're on windows:

 import sys
 from javax.swing import JButton
 from sun.awt.X11 import XEmbeddedFrame

 def printMessage(event):
    print 'Hello from Java!'

 window_id = long(sys.argv[1])
 frame = XEmbeddedFrame(window_id)
 frame.setVisible(True)
 frame.setSize(300, 300)
 button = JButton("Push Me!", actionPerformed=printMessage)
 frame.add(button)
Notice that you need to send a window-id of the window where you want to embed the java swing widget.

On the python side we do the following:

 import os
 import gtk

 def clicked(button, socket):
    print os.system('jython jframe.py %d &' % (socket.get_id(),))

 win = gtk.Window()
 win.connect('delete-event', gtk.main_quit)
 vbox = gtk.VBox()
 win.add(vbox)
 socket = gtk.Socket()
 vbox.pack_start(socket)
 button = gtk.Button('Launch')
 button.connect('clicked', clicked, socket)
 vbox.pack_start(button, False, False)
 win.set_size_request(640, 480)
 win.show_all()
 gtk.main()
Nothing fancy here apart from the fact that we use a gtk.Socket() to embed the java application and launching it by sending in socket.get_id() via os.system.

23.45. How do you get your app to restart after you log out if it was running?

This will restart your py-gtk app.

	import gnome.ui
	gnome.program_init('program name', "1.0")
	client = gnome.ui.master_client()
	command = os.path.normpath(os.path.join(os.getcwd(), sys.argv[0]))
	client.set_restart_style(gnome.ui.RESTART_IF_RUNNING)
	try: client.set_restart_command([command] + sys.argv[1:])
	except TypeError:
		client.set_restart_command(len(sys.argv), [command] + sys.argv[1:])
	client.connect('die', gtk.main_quit)

23.46. How do I get file mimetype and other info

Previously this was possible using the "get_mime_type" method of gnomevfs. Since gnomevfs has been replaced by gio, here we are going to show how to use gio in order to receive the mimetype of a file:

  >>> import gio
  >>> f = gio.File('/home/user/Documents/test.odt' )
  >>> f_info = f.query_info('standard::content-type')
  >>> mime_type = f_info.get_content_type()
  >>> mime_type
  'application/vnd.oasis.opendocument.text'
In the same way one can retrieve other file information by replacing the query string "standard::content-type" with some other attribute from [www.pygtk.org] s In this general case one should use the corresponding "get_attribute_X" method instead of "get_content_type".


24. Deprecated List Widgets: GtkList, GtkCList, GtkCTree and others

24.1. My GtkCList rows represent instances, but how can I keep track of them?

Often you have a CList where you represent instances, but since the CList itself is only an array of text cells, you might think that you need to do your own bookkeeping of them (having a mapping row -> instance, for example.) But GTK+ already does that for us:

Each row in a CList can have a data object attached to it by using the set_row_data() method. This method takes an object reference and attaches it to a row. Any object reference can be attached:

 class Foo: 
   pass
 f = Foo()
 clist = GtkCList(cols=2)
 row = clist.append(["foobar","noogie"])
 clist.set_row_data(row, f) # attaches a reference to f to row
To retrieve the reference to the instance you have attached, simply use:

 instance = clist.get_row_data(row)
To find a row that has this object attached to it, see question 13.8.

24.2. Why doesn't GtkCList's children() method return the lists rows?

If you try to

  c = gtk.GtkCList()
  c.append(["foo"])
  print c.children()
You will notice it returns an empty list. James says:

  the children() call is to return child _widgets_.  The rows of the clist 
  are not children of the CList.
See question 2.5 for a way to access CList rows.

24.3. How do I access data that is in a GtkCList?

Once you have stuffed data into a GtkCList, using something like:

  c = gtk.GtkCList(cols=2)
  c.append(["foo","bar"])
  c.append(["snark","boojum"])
The data is rendered into the list. To retrieve the data, you can use something like:

  >>> c.get_text(0,0)
  'foo'
  >>> c.get_text(0,1)
  'bar'
To retrieve all data into a list structure, use a loop like:

  ret = []
  for row in range(0, c.rows):
    tmp = []
    for col in range(0, c.cols):
      tmp.append(c.get_text(row,col))
    ret.append(tmp)
Don't forget the data object (see 2.2) attached to rows if you want an exact snapshot of the list.

24.4. How do I order the contents of a GtkCList according to the type of data in the columns (or, where is gtk_clist_set_compare_func)?

The gtk function gtk_clist_set_compare_func() is not currently mapped into pygtk. There are, however, solutions you can implement in python.

 # pop_all_rows removes and returns a list of rows, each of these being 
 # a list of columns. e.g. for a clist with 2 rows and 2 columns, it  ]
 # would produce: [ [ 'foo', 'bar' ] , [ 'baz', 'noogie'] ] 
 # See the Kiwi source code for an implementation.
 rows = clist.pop_all_rows()
 # use other funcs for other types
 func = int
 rows.sort( lambda x, y, column=column, func=func:    
            cmp(func(x[column]), func(y[column]) )
 clist.freeze()
 for r in rows:
   clist.append(r)
 clist.thaw()

 values = [3,4,5,1,49,456,342,345]

 # turn off column 1's visibility, so that only column 0 shows
 clist.set_column_visibility(1,0)

 # set the sort column to column 1
 clist.set_sort_column(1)

 # add the values, converting the integer to a string, and creating
 # a 8 character string that is left padded with zeros. This turns '1'
 # into '00000001' and 49345 into '00049345', allowing ascii to sort
 # by numerical value.

 for value in values:
   clist.append([str(value),"%08d" % value])

 clist.sort()

24.5. How do I get the data out of a GtkCTree?

Getting the information out of a CTree is very similar to getting the information out of a CList. Instead of CList.get_text() method with a row number, you use the CTree.node_get_text() method with the GtkCTreeNode representing the node in the tree:
  >>> ctree = gtk.GtkCTree(2, 0)
  >>> node = ctree.insert_node(None, None, ['foo', 'bar'])
  ...
  >>> ctree.node_get_text(node, 1)
  'bar'
Note that you can't get the text in the tree column this way, as it isn't a standard text cell. However, you can get information about the tree column with the ctree.get_node_info() method:
  >>> ctree.get_node_info(node)
  ('foo', 5, None, None, None, None, 1, 0)

24.6. How would I recurse through all nodes in a GtkCTree?

If you wish to recurse through all nodes in a ctree, you can use code like the following:

  >>> def recurse(node):
  ...     # do something with node
  ...     for child_node in node.children:
  ...         recurse(child_node)
  ... 
  >>> for node in ctree.base_nodes():
  ...     recurse(node)
  ...
The above code should be easily be modified for your purposes.

24.7. How do I capture a right-click or double-click event on a GtkCList row?

faq 5.4 explains the basic mechanics of capturing button presses on widgets. In our case, we attach a handler to the clist's button_press_event and verify the event button and type.

However, for right-clicks, the row you right-click on may not have been previously selected. This means the row will have to be selected first, and then right-clicked, which is bad usability (left-click then right-click). To avoid this, you can use something like this to select the row automatically on right-click:

 def button_clicked(list, event):
  # Check for right click
  if event.button == 3:
   sel=list.get_selection_info(event.x,event.y)
   list.select_row(sel[0], sel[1])
   print "Click."
   print list.selection
Let me guess, you want to pop up a menu? See faq 11.2.

Note that if you are trying to spawn a new window when double-clicking, *if that window is modal* your application may get stuck in a pointer-focus bug. I don't know of a good workaround beyond making the window non-modal (and then changing using idle_add to make it modal again -- it sucks but it works).

24.8. How do I find a row in a GtkCList that contains "X"?

You can query the list for both it's "label" (the strings in it) or the data object attached to a row. For the first case, simply use something like:

  row = clist.find_row_from_text(text)
  print "Row that contains %s: %s" % (text, row)
To find the row with a certain data object attached to it use:

  row = clist.find_row_from_data(obj)

24.9. When entering data dynamically into my GtkCList or tree, it flickers like mad!

If you are filling many rows into a GtkCList as part of a loop, each row insertion will force GTK+ to redraw the widget, causing flickering. To avoid this, you should wrap the insertion loop/call with call to the list's freeze() and thaw() methods:

 c = gtk.GtkCList
 # ...
 c.freeze() # avoid flickering
 for f in ...:
  c.insert_row(row_data)
 c.thaw()
If you really want flicker free operation, use pygtk 2; the new tree/list widget is much more powerful, and flickers a lot less.

24.10. How do I align a GtkCList's columns?

By default, a CList's columns will be left-aligned. Use the clist function set_column_justification for each column, passing in the appropriate GTK constants. Example:

 c = gtk.GtkCList(cols=2)
 c.set_column_justification(0, GTK.JUSTIFY_RIGHT)
 c.set_column_justification(1, GTK.JUSTIFY_CENTER)
Possible values for justification include:

 GTK.JUSTIFY_LEFT
 GTK.JUSTIFY_RIGHT
 GTK.JUSTIFY_CENTER

24.11. How do I remove a row from a CList?

Use the clist's remove function, which takes a row as argument:

 clist.remove(2) # remove row 2

24.12. How do I find out which row(s) are selected in the GtkCList?

The GtkCList has an (often-ignored) attribute called selection. It contains a list of selected rows. When the list mode is SINGLE or BROWSE, it will contain only one element:

 row = clist.selection[0]
 print "Row %d is selected" % row
If the mode is MULTIPLE or EXTENDED, the list will contain as many items as there are rows selected:

 for row in clist.selection:
   print "Row %d is selected" % row

24.13. How do I colour the background of a GtkCList row?

The GtkCList function set_background() can be used to colour a row. The trick here is getting the colour to set. pygtk-0 has a bug in which GdkColor SEGVs when being instantiated; however, the correct way to do it relies on the GtkWidget's get_colormap() method, which returns a GdkColormap. This instance provides a method to allocate a new color:

 map = clist.get_colormap()
 color = map.alloc("red")
 clist.set_background(row,color)
Note that you can pass both names ("red") and hex triplets (0xffff, 0x0000, 0x0000) to alloc():

 map = clist.get_colormap()
 color = map.alloc(0xffff, 0x0000, 0x0000)
 clist.set_background(row,color)

24.14. How do I find out what the current selection mode in the GtkCList is?

Easy (but undiscoverable):

 print clist['selection_mode']
will return the selection mode integer (which will correspond to one of SELECTION_SINGLE, SELECTION_BROWSE, SELECTION_MULTIPLE and SELECTION_EXTENDED).

24.15. How do I change the style of the white space between CList rows?

That'ss the `base' attribute of the CList's style object. See FAQ 4.5 for information on how to change it.

24.16. Is it possible to define a custom cursor from an image or data?

#! /usr/bin/env python

 import pygtk
 pygtk.require('2.0')
 import gtk

  class thinCrossCursor(object):
     def __init__(self,color='red'):
         __pm = gtk.gdk.Pixmap(None,16,16,1)
         __mask = gtk.gdk.Pixmap(None,16,16,1)
         __colormap = gtk.gdk.colormap_get_system()
         __black = __colormap.alloc_color('black')
         __white = __colormap.alloc_color('white')

         __bgc = __pm.new_gc(foreground=__black)
         __wgc = __pm.new_gc(foreground=__white)

         __mask.draw_rectangle(__bgc,True,0,0,16,16)
         __pm.draw_rectangle(__wgc,True,0,0,16,16)

         __mask.draw_line(__wgc,0,6,5,6)
         __mask.draw_line(__wgc,0,8,5,8)

         __mask.draw_line(__wgc,10,6,15,6)
         __mask.draw_line(__wgc,10,8,15,8)

         __mask.draw_line(__wgc,6,0,6,5)
         __mask.draw_line(__wgc,8,0,8,5)

         __mask.draw_line(__wgc,6,10,6,15)
         __mask.draw_line(__wgc,8,10,8,15)

         #__mask.draw_line(__wgc,0,5,0,9)
         #__mask.draw_line(__wgc,15,5,15,9)
         #__mask.draw_line(__wgc,5,0,9,0)
         #__mask.draw_line(__wgc,5,15,9,15)
         #__mask.draw_arc(__wgc,False,3,3,8,8,0,64*360)
         self.color=color
        self.cur=gtk.gdk.Cursor(__pm,__mask,
                                gtk.gdk.color_parse(self.color),
                                gtk.gdk.Color(),5,5)
 def close_application(widget, event, data=None):
      gtk.main_quit()
      return False
 w=gtk.Window()
 w.connect("delete_event",close_application)
 w.show()

 tc_cursor=thinCrossCursor(color='red')
 w.window.set_cursor(tc_cursor.cur)

 gtk.main()

PyGTK FAQ Wizard | PyGTK Homepage | Feedback to faq at pygtk.org